Spring Aop是通过代理模式实现的,动态代理实现有两种:①cglib(基于父子类)。②JDK自带动态代理(基于接口)。Spring封装后提供了几种创建AOP的方式:①ProxyFactoryBean ②ProxyFactory ③Auto-proxy(又可分为三种:BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator) 。这三种方法最终都会创建ProxyFactory,本教程主要以AnnotationAwareAspectJAutoProxyCreator为例,讲解Spring如果进行AOP的。
1、ProxyFactory用法介绍
因为上边介绍的几种Spring创建AOP的方式,最终都会去创建ProxyFactory,所以我们先来介绍下ProxyFactory的用法。
通过ProxyFactory,我们不用关心到底是用jdk还是cglib了,它会自己判断,如果代理的对象实现了接口,那么会用jdk动态代理,如果没有实现接口,则会用cglib技术。下面的例子,User类没有实现接口,所以底层走的是cglib。
@Component
public class User {
@Autowired
private Dog dog;
void say() {
System.out.println("hi i am tom");
}
}
@Configuration
@ComponentScan("com.ioc.tuing.impl")
public class MainStart {
public static void main(String[] args) {
// ProxyFactory
User target = new User();
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;
}
});
User user = (User)proxyFactory.getProxy();
user.say();
}
}
打印结果:
before...
hi i am tom
after...
2、Spring AOP流程
我们在实际工作中,通常会用注解的方式来使用AOP,首先用@EnableAspectJAutoProxy注解开启AOP自动代理,然后配合@Aspect、@before、@Pointcut等注解使用,实际上这就是我们在上面说AnnotationAwareAspectJAutoProxyCreator方式。大致步骤如下图所示:
2.1、@EnableAspectJAutoProxy开启AOP
通过@EnableAspectJAutoProxy注解,导入配置类AspectJAutoProxyRegistrar,而AspectJAutoProxyRegistrar类会向容器中注册一个AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,它本身也是一个BeanPostProcessor。
这个BeanDefinition会在org.springframework.context.support.AbstractApplicationContext#registerBeanPostProcessors这个方法中完成创建。
2.2、postProcessBeforeInstantiation方法执行
执行AnnotationAwareAspectJAutoProxyCreator的postProcessBeforeInstantiation方法,实际上就是父类AbstractAutoProxyCreator的postProcessBeforeInstantiation被执行。这个方法的作用就是:确定哪些类不需要被代理。
2.3、postProcessAfterInitialization方法执行
实际上也是执行父类AbstractAutoProxyCreator中的方法,其中wrapIfNecessary完成了AOP代理,对应源码如下:
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 什么时候这个判断会成立呢?
// 如果发生循环依赖的话,这个判断就不会成立(这里不做详细分析)
// 目前你只需要知道wrapIfNecessary完成了AOP代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 需要代理的话,在这里完成的代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
2.4、wrapIfNecessary方法执行,生成代理对象。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 在postProcessBeforeInstantiation方法中可能已经完成过代理了
// 如果已经完成代理了,那么直接返回这个代理的对象
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 在postProcessBeforeInstantiation方法中可能已经将其标记为不需要代理了
// 这种情况下,也直接返回这个Bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 跟在postProcessBeforeInstantiation方法中的逻辑一样
// 如果不需要代理,直接返回,同时在advisedBeans中标记成false
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取可以应用到这个Bean上的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果存在通知的话,说明需要被代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 到这里创建代理,实际上底层就是new了一个ProxyFactory来创建代理的
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 如果没有通知的话,也将这个Bean标记为不需要代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
3、AOP底层逻辑
前面我们只是介绍了Spring AOP的过程,结合bean的生命周期,讲了Spring如何、在何时进行的AOP。但是AOP的底层逻辑(比如怎么解析的通知)我们没做讲解,这些步骤很杂、很多,这里放出一张思维图,供大家参考:
https://www.processon.com/view/link/5faa4ccce0b34d7a1aa2a9a5