我们的AOP实现大致分为3块
解析切面,将所有带aspect的切面和所有的通知解析成advisor,advisor中就带了通知和pointCut
根据ponitcut去匹配,如果匹配上就会创建动态代理
调用的时候通过责任链的方式,去调用
使用@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事务