• SpringAOP


    这是一篇关于AOP入门小白的介绍,这里会介绍一部分源码,但不会过多涉及,之后有时间会出一篇源码解析的文章,本文主要目的是帮助初学者了解什么是AOP以及他的工作原理是什么,从而帮助其在阅读源码时更好的理解。

    AOP介绍

    AOP(Aspect Oriented Programming)面向切面编程,其特点为

    • 解耦合,系统应求追高内聚低耦合,增强的逻辑独立存在,即插即用,不需要移除掉切点即可,对原有业务无影响(或影响极小)。
    • 符合开闭原则,对扩展开放,对修改关闭,不修改原有代码。改代码的代价有些时候比较大。
    • 代码复用,可以在不侵入当前代码的情况下复用代码或引入第三方功能从而扩展系统功能。

    在Spring中AOP的实现是通过JDK动态代理CgLib动态代理实现AOP的功能。

    那么AOP代理是在什么时候创建的呢?先来看一下Bean的创建过程

    Bean的创建过程

    在这里插入图片描述
    首先看一下Spring Bean的创建过程,这里先不考虑循环依赖的影响,Bean的创建过程可以分为以下几步:

    1. 根据注解或者xml创建BeanDefinition的类,BeanDefinition中包括了Bean的相关信息,用于之后创建Bean。
    2. 调用BeanFactoryPostProcessor来进行前置处理,比如对BeanDifition中的占位符进行解析
    3. 实例化,开始创建Bean,为Bean分配内存空间
    4. 属性填充,为Bean注入相应的属性
    5. 初始化过程,初始化过程中,如果有相应的实现了BeanPostProcessor接口的处理器,那么就会按照Before->init->after的方法执行,如果一个Bean命中了多个BeanPostPrcessor,那么他们就会按照优先级排序组成一个List,然后进行遍历调用
      在这里插入图片描述
    6. 创建完成后放入BeanFactory的单例池中,之后就可以被使用。

    Spring AOP何时如何创建的

    下面我以日志切入为例,
    我首先查看了代码中使用的方式,主要有两种

    1. 实现MethodIntercpter接口,注册BeanNameAutoProxyCreator
      
        <bean id="salInterceptor" class="com.alibaba.txcs.ad.delivery.common.log.interceptor.SalInterceptor"/>
        <bean id="salAutoProxyCreator"
              class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="interceptorNames">
                <list>
                    <value>salInterceptorvalue>
                list>
            property>
            <property name="beanNames">
                <list>
                    
                    <value>*Gatewayvalue>
                    <value>*GatewayImplvalue>
                list>
            property>
        bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. 使用@Around等注解的形式对原有方法进行扩展,这种方式最终会生成一个AnnotationAwareAspectJAutoProxyCreator类
    @Around(
            "execution(public com.alibaba.tcls.tc.com.service.client.base.model.ResultResponse+||com.taobao.mtop.common"
                + ".Result||com.wdk.client.result.ResultDO com.alibaba.tcls.tc.com.service.biz..*.*(..))")
        public Object process(final ProceedingJoinPoint pjp) throws Throwable {
            MethodSignature signature = (MethodSignature)pjp.getSignature();
            long startTime = System.currentTimeMillis();
            Object result = null;
            long elapseTime = 0;
            String success = LogConstants.SUCCESS;
            Object[] args = pjp.getArgs();
            LogAnnotation logAnnotation = getAnnotation(pjp);
            boolean printArgs = SysSwitch.SERVICE_ARGS;
            boolean printRes = SysSwitch.SERVICE_ARGS;
            if (logAnnotation != null) {
                printArgs = logAnnotation.printArgs();
                printRes = logAnnotation.printResult();
            }
            try {
                result = pjp.proceed();
                elapseTime = System.currentTimeMillis() - startTime;
            } catch (BizException e) {
                success = LogConstants.FAIL;
                LoggerUtil.warn(LOGGER, "{}#{}invoke fail", pjp.getSignature().getDeclaringType().getSimpleName(),
                    signature.getMethod().getName(), e);
                throw e;
            } catch (Throwable e1) {
                LoggerUtil.error(LOGGER, "{}#{}invoke fail", pjp.getSignature().getDeclaringType().getSimpleName(),
                    signature.getMethod().getName(), e1);
                success = LogConstants.FAIL;
                throw e1;
            } finally {
                LoggerUtil.info(Loggers.SERVICE_DIGEST, "{},{},{}#{},{},{}ms,{},[{}],[{}]",
                    RequestCtxUtil.getClientIp(), RequestCtxUtil.getAppNameOfClient(),
                    pjp.getSignature().getDeclaringType().getSimpleName(),
                    signature.getMethod().getName(),
                    success, elapseTime,
                    genBizResult(result),
                    getLog(printArgs, args),
                    getLog(printRes, result));
            }
            return result;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    我们从下面这幅图可以看到,这两个类都是继承AbstractAutoProxyCreator的
    在这里插入图片描述AbstractAutoProxyCreator实现了BeanPostProcessor

    
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            return bean;
        }
    
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean != null) {
                Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
                //判断是否有循环依赖导致的代理前置
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //创建代理类的方法
                    return this.wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
    
            return bean;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    因此,在正常情况下,aop应该在Bean初始化的时候被调用。其中代理主要是在after方法中实现的,主要的方法是wrapIfNecessary方法

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    	    //前置一些判断
    		。。。。。
    		// 1.获取这个bean特定的拦截器
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		if (specificInterceptors != DO_NOT_PROXY) {
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
    			//2.创建代理
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    
    		this.advisedBeans.put(cacheKey, Boolean.FALSE);
    		return bean;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    进入createProxy方法

    protected Object createProxy(
    			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
    		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    		}
    		//1.对代理工厂进行属性设置
    		ProxyFactory proxyFactory = new ProxyFactory();
    		proxyFactory.copyFrom(this);
    
    		if (!proxyFactory.isProxyTargetClass()) {
    			if (shouldProxyTargetClass(beanClass, beanName)) {
    				proxyFactory.setProxyTargetClass(true);
    			}
    			else {
    				evaluateProxyInterfaces(beanClass, proxyFactory);
    			}
    		}
    		//2.将拦截器进行包装,创建advisor数组,并写入代理工厂
    		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    		for (Advisor advisor : advisors) {
    			proxyFactory.addAdvisor(advisor);
    		}
    
    		proxyFactory.setTargetSource(targetSource);
    		customizeProxyFactory(proxyFactory);
    
    		proxyFactory.setFrozen(this.freezeProxy);
    		if (advisorsPreFiltered()) {
    			proxyFactory.setPreFiltered(true);
    		}
    		//3.获取代理
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    进入getProxy方法

    	public Object getProxy(ClassLoader classLoader) {
    			   //创建aop代理。   //获取代理类
    		return createAopProxy().getProxy(classLoader);
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    进入createAopProxy方法,判断使用jdk动态代理还是cglib动态代理

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    		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.");
    			}
    			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    				return new JdkDynamicAopProxy(config);
    			}
    			return new ObjenesisCglibAopProxy(config);
    		}
    		else {
    			return new JdkDynamicAopProxy(config);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    进入getProxy方法,以JDK动态代理为例

    @Override
    	public Object getProxy(ClassLoader classLoader) {
    		if (logger.isDebugEnabled()) {
    			logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
    		}
    		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
    		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    		//创建代理,切面增强方法查看invoke方法
    		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    进入invoke方法

    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    	@Override
    	@Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          //一些判断省略
          	....
          	//获取目标方法的通知
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    if (chain.isEmpty()) {
                    //如果没有通知,则不生成代理
                        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                    } else {
                    //否则执行proceed()方法递归调用拦截器链
                        MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                        retVal = invocation.proceed();
                    }
    
                //后置一些处理
          	....
    
            return retVal;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这段代码的主要工作就是:

    1. 创建一个拦截器链,并使用ReflectiveMethodInvocation类进行链的封装。
    2. 调用ReflectiveMethodInvocation.proceed()进行拦截器的逐一调用。

    进入proceed方法

      public Object proceed() throws Throwable {
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //如果调用到最后的拦截器,那么执行目标对象的原有方法,具体实现看invokeJoinpoint的代码
                return this.invokeJoinpoint();
            } else {
            //否则获取拦截器切面
                Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
                if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                //对interceptorOrInterceptionAdvice做一个判断
                    InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                    return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
                } else {
                //开始调用拦截器的invoke方法
                    return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
                }
            }
        }
    
    //这个方法调用AopUtils工具类的静态方法
     protected Object invokeJoinpoint() throws Throwable {
            return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
        }
    
     public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args) throws Throwable {
            try {
            	//设置method的accessible为true
                ReflectionUtils.makeAccessible(method);
                //通过反射调用方法
                return method.invoke(target, args);
            } catch (InvocationTargetException var4) {
                throw var4.getTargetException();
            } catch (IllegalArgumentException var5) {
                throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", var5);
            } catch (IllegalAccessException var6) {
                throw new AopInvocationException("Could not access method [" + method + "]", var6);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    `
    然后我们看一下proceed方法是怎么执行的,这个方法采用的是责任链模式,对适配某一类的某一方法的切面连成一条链,这里采用的递归调用,所以如果链非常长,可能就会堆栈溢出。

    上面最重要的一行代码如下,我们需要搞清楚MethodIntercepetor是什么,以及他对应的invoke方法是什么,我们通常使用时采用@Before,@After,@Around等五个注解来表示对方法进行增强,这些注解对应的类如下面的类图所示,
    Spring会把五个注解解析为对应的Advice类:

    1、@Before:AspectJMethodBeforeAdvice,实际上就是一个MethodBeforeAdvice
    2、@AfterReturning:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice
    3、@AfterThrowing:AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor
    4、@After:AspectJAfterAdvice,实际上就是一个MethodInterceptor
    5、@Around:AspectJAroundAdvice,实际上就是一个MethodInterceptor

     return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
    
    • 1

    在这里插入图片描述
    既然一个方法可能同时对应多类切面,那么多个切面是以什么样的顺序串成一条调用链,这里直接给出结论,对于不同类型的advisor,在链表中的排序是AspectJAfterThrowingAdvice->AspectJAfterReturningAdvice->AspectJAfterAdvice->AspectJAroundAdvice->AspectJMethodBeforeAdvice
    在这里插入图片描述
    如果同一种切面有多个通知,那么对于@Before而言,优先级高的排在调用链的前面,对于@After而言,优先级高的排在调用链的后面。

    循环依赖中的aop

    在这里插入图片描述
    没有循环依赖的AOP代理,简单的递归创建就可以完成Bean加载

    在这里插入图片描述
    存在循环依赖的AOP代理,因为正常情况下创建代理是在填充属性之后的,导致B中填充的A对象不是代理对象A1,为了解决这个问题,在B获取A的时候,会查询getSingleton方法,提前暴露并进行代理,

    public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
    		implements AutowireCapableBeanFactory {
    
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    		Object exposedObject = bean;
    		if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    			for (BeanPostProcessor bp : getBeanPostProcessors()) {
    				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
    					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
    					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
    					if (exposedObject == null) {
    						return null;
    					}
    				}
    			}
    		}
    		return exposedObject;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    	@Override
    	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    		Object cacheKey = getCacheKey(bean.getClass(), beanName);
    		if (!this.earlyProxyReferences.contains(cacheKey)) {
    			//增加一个标记,防止后处理阶段重复aop
    			this.earlyProxyReferences.add(cacheKey);
    		}
    		//创建代理的过程
    		return wrapIfNecessary(bean, beanName, cacheKey);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    然后在最后会将代理对象放入一级缓存中结束循环依赖的过程。
    在这里插入图片描述

    https://zhuanlan.zhihu.com/p/373973937

    https://blog.csdn.net/weixin_45723046/article/details/124546319

  • 相关阅读:
    关于微信小程序rich-text中图片宽度超出范围解决办法
    java计算机毕业设计西安财经大学校园一卡通管理系统源码+系统+数据库+lw文档+mybatis+运行部署
    “碳”零排放是什么意思
    前端面试 10个前端小知识
    十四、流式编程(1)
    muduo库的高性能日志库(一)
    Kotlin_获取网络图片(HttpURLConnection, AsyncTask,协程)
    【图文教程】Centos 7下安装Hadoop
    【opencv-c++】windows10系统安装OpenCV4.6.0
    ES-ES的基本概念
  • 原文地址:https://blog.csdn.net/layAlex/article/details/126452546