目录
动态代理
cglib动态代理
jdk动态代理
ProxyFactory
Advice的分类
Advisor的理解
spring创建代理对象的方式
ProxyFactoryBean(相对灵活,可以更精细地控制代理对象的创建过程)
BeanNameAutoProxyCreator(适合对特定Bean进行简单代理的场景)
DefaultAdvisorAutoProxyCreator(适合使用切面(Aspect)来定义通知的情况)
aop其实就是动态代理的一种体现,像spring的事务也是一种动态代理的体现。比如我们对某个方法进行增强,其实就是通过动态代理的方式在执行某个方法之前,进行方法前或者方法后等一些操作,比如比较常见的用@Before("execution(代理逻辑)")来记录操作日志等。
动态代理又分为两种,一种是cglib,一种是jdk。
public class UserService {
public void test() {
System.out.println("test...");
}
}
//此时,我们new一个UserService对象,然后执行test()方法,结果是显而易见的。
-----------------------------------------------------------------------------------------
//如果我们现在想在不修改UserService类的源码前提下,给test()增加额外逻辑,
//那么就可以使用动态代理机制来创建UserService对象了,比如:
UserService target = new UserService();
// 通过cglib技术
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
// 定义额外逻辑,也就是代理逻辑
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy
methodProxy) throws Throwable {
System.out.println("before...");
Object result = methodProxy.invoke(target, objects);
System.out.println("after...");
return result;
}
}});
// 动态代理所创建出来的UserService对象
UserService userService = (UserService) enhancer.create();
// 执行这个userService的test方法时,就会额外会执行一些其他逻辑
userService.test();
得到的都是UserService对象,但是执行test()方法时的效果却不一样了,这就是代理所带来的效果。
上面是通过cglib来实现的代理对象的创建,是基于父子类的,被代理类(UserService)是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的,对于程序员来说不用关心。
注意:jdk动态代理只能代理实现接口,也就是一个类需要先实现接口才能利用jdk动态代理来生成代理对象。
public interface UserInterface {
public void test();
}
public class UserService implements UserInterface {
public void test() {
System.out.println("test...");
}
}
//创建将要使用jdk动态代理的UserService类
------------------------------------------------------------------------------------------
//利用JDK动态代理来生成一个代理对象
UserService target = new UserService();
// UserInterface接口的代理对象
Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(),
new Class[]{UserInterface.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
Object result = method.invoke(target, args);
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxy;
userService.test();
如果将new Class[]{UserInterface.class},替换成new Class[]{UserService.class},代码会直接报错,表示一定要是个接口。
上述两种动态代理技术,在spring中已经进行了封装ProxyFactory,表示创建代理对象的工厂,使用更加方便。
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();
ProxyFactory会自动去判断使用那种动态代理,如果没有实现接口就用cglib,反之亦然。
Advisor
是一个包含了切面的全部信息的对象,它将Advice
和Pointcut
(切入点)结合起来。Pointcut
定义了在什么地方(连接点)应用切面逻辑,而 Advice
定义了切面实际执行的逻辑。
Spring中常见的实现Advisor
接口的类是 DefaultPointcutAdvisor
,它通过组合 Pointcut
和 Advice
来创建一个完整的切面。Pointcut
用于匹配连接点,而 Advice
则定义了在匹配的连接点上执行的逻辑。
在使用Spring时,并不会直接去使用ProxyFactory。
@Bean
public ProxyFactoryBean userServiceProxy(){
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
return proxyFactoryBean;
}
这种方式定义的Bean是经过AOP的,只能针对某一个Bean,定制化相当于FactoryBean,并将代理对象生成了Bean。
ProxyFactoryBean还有额外的功能,比如把某个Advise或Advisor定义成为Bean,然后在ProxyFactoryBean中进行设置
@Bean
public MethodInterceptor AroundAdvise(){
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
};
}
@Bean
public ProxyFactoryBean userService(){
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.setInterceptorNames("AroundAdvise");
return proxyFactoryBean;
}
BeanNameAutoProxyCreator通过指定某个bean的名字,来对该bean进行代理
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
//表示可批量对Bean进行AOP
beanNameAutoProxyCreator.setBeanNames("userSe*");
beanNameAutoProxyCreator.setInterceptorNames("AroundAdvise");
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的。BeanNameAutoProxyCreator的缺点是只能根据beanName来指定想要代理的Bean。
此方式就是我们编写一个切面类,里边包含切面方法,像@Befoer、@After等,通过扫描Spring容器中的Advisor,为匹配的Bean创建代理对象,并将Advisor中定义的通知应用到代理对象上。
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor(){
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("test");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
defaultPointcutAdvisor.setAdvice(new XXXAfterReturningAdvise());
return defaultPointcutAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new
DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
上述方式为非注解方式,注解方式就是@Before、@After,如果是注解方式会通过@EnableAspectJAutoProxy注解去解析,后续会分析。