本文是学习Spring框架的副产品。Spring中的AOP涉及动态代理的原理。
什么是代理
定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用;
目的:
- 通过引入代理对象的方式来间接访问目标对象,以防止直接访问目标对象给系统带来的不必要的复杂性;
- 通过代理对象对原有业务进行增强
代理设计模式
https://www.runoob.com/design-pattern/proxy-pattern.html
静态代理不能解决代码冗余的问题。一般不推荐静态代理(代理的关系用代码直接定义,代理和被代理需要有相同的接口,被代理作为代理对象的成员变量)。
jdk机制的动态代理
动态代理有以下特点:
- 代理对象,不需要实现接口
- 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
动态代理的实现方案
- jdk代理,通过和目标实现相同接口保证功能一致
- cglib代理(第三方cglib库中的一套api),通过继承保证功能一致
主要涉及:
1 2 3 4
| static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
public interface InvocationHandler {....}
|
基本思路是使用上面的方法,动态生成代理对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class ProxyDemo { @Test public void proxy(){ final UserService userService=new UserServiceImpl(); InvocationHandler handler=new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理增加的额外功能,在执行前"); method.invoke(userService,args); System.out.println("代理增加的额外功能,在执行后"); return null; } };
UserService proxy = (UserService)Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(), userService.getClass().getInterfaces(), handler); proxy.queryOne(1); proxy.insertUser(new User()); }
|
Spring动态代理实现AOP
AspectJ 是Spring集成的一个AOP框架。
spring的aop套路:
- 目标类
- 代理类,implement advice的各中AOP接口
- spring配置中增加aop的命名空间和xsi:location
- spring配置中编织代理关系,构建一个动态的代理类。
下面代码演示了,代理前、代理后、环绕代理。
aopContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userServervice" class="aop.service.UserServiceImpl"></bean> <bean id="myadvice" class="aop.springAOP.MybeforAdvice"></bean> <bean id="myafteradvice" class="aop.springAOP.MyafterAdvice"></bean> <bean id="myinterceptor" class="aop.springAOP.MymethodInterceptor"></bean>
<aop:config>
<aop:pointcut id="before" expression="execution(* aop.springAOP.*(..))"/> <aop:advisor advice-ref="myadvice" pointcut-ref="before"></aop:advisor> <aop:advisor advice-ref="myafteradvice" pointcut-ref="before"></aop:advisor> <aop:advisor advice-ref="myinterceptor" pointcut-ref="before"></aop:advisor> </aop:config> </beans>
|
接口及其实现类
1 2 3 4 5 6 7 8 9
| package aop.service;
import aop.pojo.User;
public interface UserService { Integer insertUser(User user); User queryOne(Integer id);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package aop.service;
import aop.pojo.User;
public class UserServiceImpl implements UserService { @Override public Integer insertUser(User user) { System.out.println("insertUser 核心功能"); return 4; }
@Override public User queryOne(Integer id) { System.out.println("queryOne 核心功能"); return new User(); } }
|
测试类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package aop.springAOP;
import aop.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class aopTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("aopContext.xml"); UserService service = (UserService)context.getBean("userServervice"); service.queryOne(3); System.out.println(service.getClass()); } }
|
小结:spring的aop,在xml中完成切入点的定义,核心逻辑是expression表达式。凡是符合表达式的bean方法,都可以被当做切入点。而切入点的行为,是通过关联切入点和切入点行为的bean(实现了advice)来编织的。