• 二、SpringAOP终结篇(补充中...)


    一、基本源码分析

    1.寻找入口

    Spring 的 AOP 是通过接入 BeanPostProcessor 后置处理器开始的

    2.BeanPostProcessor

    BeanPostProcessor的体现在IOC源码分析的doCreateBean中,populateBean的后一句

    Object exposedObject = bean;
    try {
       populateBean(beanName, mbd, instanceWrapper);
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    

    initializeBean中,在调用invokeInitMethods初始化方法的前后调用BeanPostProcessor

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
       wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    
    try {
       invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
       //...
    }
    if (mbd == null || !mbd.isSynthetic()) {
       wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    

    其实就是在你的init方法前后调用BeanPostProcessor的before方法和after方法。

    在 Spring 中,BeanPostProcessor 的实现子类非常的多,分别完成不同的操作,如:AOP 面向切面编程的注册通知适配器、Bean 对象的数据校验、Bean 继承属性、方法的合并等等。

    分析创建AOP代理对象的相关BeanPostProcessor子类AbstractAutoProxyCreator(经典实现类AnnotationAwareAspectJAutoProxyCreator) 。

    3.AbstractAutoProxyCreator

    AbstractAutoProxyCreator的postProcessAfterInitialization ,即after方法

    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
       if (bean != null) {
          Object cacheKey = getCacheKey(bean.getClass(), beanName);
          if (!this.earlyProxyReferences.contains(cacheKey)) {
             return wrapIfNecessary(bean, beanName, cacheKey);
          }
       }
       return bean;
    }
    

    核心逻辑在wrapIfNecessary,里面主要几步

    1.判断是不是该wrap包装(AOP代理):是不是缓存过、基础Bean(Advice/PointCut/Advisor)跳过

    2.获取这个Bean的advice

    3.处理advice去createProxy创建代理对象并缓存

    核心当然是createProxy,最终是交给了工厂proxyFactory.getProxy(),最终到DefaultAopProxyFactory的 createAopProxy()方法

    4.DefaultAopProxyFactory#createAopProxy()

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
       if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
          Class<?> targetClass = config.getTargetClass();
          if (targetClass == null) {
             //...
          }
          if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
             return new JdkDynamicAopProxy(config);
          }
          return new ObjenesisCglibAopProxy(config);
       }
       else {
          return new JdkDynamicAopProxy(config);
       }
    }
    

    两种方式来生成代理方式有 JDKProxy 和 CGLib

    来分析一下spring中JDK动态代理如何运作的,织入切面的,对应是JdkDynamicAopProxy

    5.JdkDynamicAopProxy

    InvocationHandler 是 JDK 动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。JdkDynamicAopProxy 的源码可以看到这个类也实现了 InvocationHandler,

    5.1 invoke()方法:

    避免一些不aop的特殊情况后,首先获取应用到此方法上的通知链(Interceptor Chain)。如果有通知,则应用通知,并执行 JoinPoint;如果没有通知,则直接反射执行 JoinPoint。

    5.2 获取通知链

    getInterceptorsAndDynamicInterceptionAdvice 方法:

    1从提供的配置实例 config 中获取 advisor 列表,

    2 遍历处理这些 advisor.如果是 IntroductionAdvisor,则判断此 Advisor 能否应用到目标类 targetClass 上.

    3.如果是 PointcutAdvisor,则判断此 Advisor 能否应用到目标方法 Method 上.

    4.将满足条件的 Advisor 通过 AdvisorAdaptor 转化成 Interceptor 列表返回.

    这个方法执行完成后,Advised 中配置能够应用到连接点(JoinPoint)或者目标类(Target Object)
    的 Advisor 全部被转化成了 MethodInterceptor

    5.3 执行

    获取完通知链之后就是执行了:

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    if (chain.isEmpty()) {
       Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
       retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
    }
    else {
       invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
       retVal = invocation.proceed();
    }
    

    核心就是retVal = invocation.proceed();打开ReflectiveMethodInvocation的proceed源码:

    public Object proceed() throws Throwable {
    	//1.如果 Interceptor 执行完了, 则执行 joinPoint
    	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    		return invokeJoinpoint();
    	}
    	Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    	//2.如果要动态匹配 joinPoint
    	InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    	//3.动态匹配: 运行时参数是否满足匹配条件
    	if (dm.MethodMatcher.matches(this.Method, this.targetClass, this.arguments)) {
    		return dm.interceptor.invoke(this);
    	} else {
    		//动态匹配失败时,略过当前 Intercetpor,调用下一个 Interceptor
    		return proceed();
    	}
    } else {
    	//4.执行当前 Intercetpor
    	return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    }
    

    1.从执行链里取Interceptor(排序好了,依次是before、after、return、afterthrowing)

    2.分两种情况,Interceptor是否是动态匹配型的

    ​ 2.1 动态匹配型,去执行动态匹配代码,匹配上则执行

    ​ 2.2 普通型else,直接执行Interceptor逻辑(这个逻辑里排好代码,是先继续递归还是先执行自己,before是先执行自己)如下:

    beofore-Interceptor的的invoke(先自己再继续递归)

    public Object invoke(MethodInvocation mi) throws Throwable {
       this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
       return mi.proceed();
    }
    

    after-Interceptor的的invoke(先继续递归,再执行自己)

    public Object invoke(MethodInvocation mi) throws Throwable {
       try {
          return mi.proceed();
       }
       finally {
          invokeAdviceMethod(getJoinPointMatch(), null, null);
       }
    }
    
  • 相关阅读:
    配合 envoy 使用 Zipkin
    一文带你彻底搞懂Cookie、Session和Token
    一种Hudi on Flink动态同步元数据变化的方法
    Flink SQL UNNEST/UDTF 如何实现列转行?
    Apache Flink 流计算基准测试框架
    Curator处理zookeeper会话过期session expired
    Flink性能测试case案例
    flink 项目打包成jar包使用java jar运行异常
    Keeping Multiple Databases in Sync Using Kafka Connect and CDC
    zookeeper所有超时异常全解析
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/13113518.html
Copyright © 2020-2023  润新知