SpringAOP源码解析DayTwo
回顾
我们的AOP实现大致分为3块
-
解析切面,将所有带aspect的切面和所有的通知解析成advisor,advisor中就带了通知和pointCut
-
根据ponitcut去匹配,如果匹配上就会创建动态代理
-
调用的时候通过责任链的方式,去调用
解析advisor过程
使用@EnableAspectJAutoProxy
注解开启aop
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
import导入1个实现了ImportBeanDefinitionRegistrar
接口的类,调用
往bean定义中注册个AnnotationAwareAspectJAutoProxyCreator
这个就是aop最核心的类,包括解析切面,创建动态代理,创建循环依赖下的动态代理。
那么这个方法registerBeanDefinitions
会在哪里调用呢?invokeBeanFactoryPostProcessors
这里
最终排好序后,把这些后置处理器放到集合中去
在createBean的时候,调用createBean方法,
拿到我们刚刚注册进来的所有的bean的后置处理器
调用AnnotationAwareAspectJAutoProxyCreator的
shouldSkip
找到候选的Advisors(通知 前置通知、后置通知等…)
具体是调用
去容器中获取到所有的切面信息保存到缓存中
放到存所有切面的list中。解析过程是非常耗资源的。
advisor里就包含了advice和pointCut
放到缓存中
创建动态代理
所有的advisor都解析完了,就要创建动态代理,根据pointCut去做匹配。如果匹配上就创建
创建动态代理会在哪里呢?
正常的bean会在初始化之后
我们只看正常的
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建一个代理对象工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//为proxyFactory设置创建jdk代理还是cglib代理
// 如果设置了 <aop:aspectj-autoproxy proxy-target-class="true"/>不会进if,说明强制使用cglib
if (!proxyFactory.isProxyTargetClass()) {
// 内部设置的 , 配置类就会设置这个属性
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 检查有没有接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//把我们的specificInterceptors数组中的Advisor转化为数组形式的
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//为我们的代理工厂加入通知器,
proxyFactory.addAdvisors(advisors);
//设置targetSource对象
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// 代表之前是否筛选advise.
// 因为继承了AbstractAdvisorAutoProxyCreator , 并且之前调用了findEligibleAdvisors进行筛选, 所以是true
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//真正的创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
设置ProxyTargetClass就会用cglib进行动态代理,如果没有设置并且有接口就会使用jdk动态代理
/**
*
* @param config 用来为我们指定我们advisor信息
* 该方法用来创建我们的代理对象
* 所我们的targetClass对象实现了接口,且 ProxyTargetClass 没有指定强制的走cglib代理,那么就是创建jdk代理
* 我们代理的类没有实现接口,那么会直接走cglib代理
* 若我们 ProxyTargetClass 指定为false 且代理类是接口才会走jdk代理 否在我们还是cglib代理
* @return
* @throws AopConfigException
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//判断我们是否前置指定使用cglib代理ProxyTargetClass =true 或者没有接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//所targetClass是接口 使用的就是jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
//cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
//动态代理
return new JdkDynamicAopProxy(config);
}
}
最终放到一级缓存中
如何调用
调用这个div方法就会来到
这里面有个细节
这个if只有@EnableAspectJAutoProxy(exposeProxy = true)
才会进入,
现在我们加上,进入断点
把我们当前的动态代理对象set到ThreadLocal里去,
private static final ThreadLocal<Object> currentProxy =
new NamedThreadLocal<>("Current AOP proxy");
那有什么用呢?
假如是JDK的动态代理,在本类里调用本类的方法。是不会再次执行动态代理的方法。
所以JDK动态代理必须把代理暴露到ThreadLocal里面。看下面例子
public int mod(int numA,int numB){
System.out.println("执行目标方法:mod");
int retVal = ((Calculate)AopContext.currentProxy()).add(numA,numB);
//int retVal = this.add(numA,numB);
return retVal%numA;
}
比如说在mod里调用add方法,就可以通过AopContext,拿到theadLocal里的动态代理去调用
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
}
return proxy;
}
currentProxy是
private static final ThreadLocal<Object> currentProxy =
new NamedThreadLocal<>("Current AOP proxy");
ThreadLocal不懂的看我这篇文章ThreadLocal初探
jdk动态代理不可以本类里调用其他方法,但是cglib是可以的
继续往下看
转为interceptor调用invoke方法,因为之前说过要用责任链调用必须用统一的接口,只有interceptor才有invoke方法
这里就是责任链递归调用,这里太复杂知道责任链递归调用,执行完所有通知就行了,
invocation.proceed()
至此AOP源码的解析就走完了,下一篇Spring事务