spring · 2021-11-30 0

Spring AOP 原理

准备

版本

<properties>
    <spring.version>5.1.9.RELEASE</spring.version>
</properties>

<dependencies>

    <!-- spring core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- spring aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>

</dependencies>

配置

pointcut 会切指定类的所有实现类

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="studentService" class="com.exmple.service.StudentServiceImpl"/>

    <bean id="teacherService" class="com.exmple.service.TeacherServiceImpl"/>

    <bean id="serviceAspect" class="com.exmple.aop.ServiceAspect"/>

    <bean id="serviceAdvice" class="com.exmple.aop.ServiceAdvice"/>

    <!--
        标签 aop:config 会在 spring 中注册为 bean, 
        key 是 "org.springframework.aop.config.internalAutoProxyCreator"
        value 是  AspectJAwareAdvisorAutoProxyCreator 对象
    -->
    <aop:config proxy-target-class="false">

        <aop:pointcut id="myPoint1" expression="execution(public * com.exmple.service.StudentServiceImpl.*(..))"/>

        <aop:pointcut id="myPoint2" expression="execution(public * com.exmple.service.TeacherServiceImpl.*(..))"/>

        <!--
            标签 aop:advisor 会在 spring 中注册为 bean,
            key 是 "myAdvisor1"
            value 是 DefaultBeanFactoryPointcutAdvisor 对象,
                    其中有 Advice advice 为 serviceAdvice 对象, Pointcut pointcut 为 AspectJExpressionPointcut
        -->
        <aop:advisor id="myAdvisor1" advice-ref="serviceAdvice" pointcut-ref="myPoint1"/>

        <!--
            标签 aop:advisor 会在 spring 中注册为 bean,
            key 是 "myAdvisor2"
            value 是 DefaultBeanFactoryPointcutAdvisor 对象,
                其中有 Advice advice 为 serviceAdvice 对象, Pointcut pointcut 为 AspectJExpressionPointcut
        -->
        <aop:advisor id="myAdvisor2" advice-ref="serviceAdvice" pointcut-ref="myPoint2"/>

        <!--
           注册两个 bean
           key 是 "org.springframework.aop.aspectj.AspectJPointcutAdvisor#0"
           value 是 AspectJPointcutAdvisor 对象,
                其中有 AbstractAspectJAdvice advice 为 AspectJMethodBeforeAdvice, Pointcut pointcut 为 ComposablePointcut

           key 是 "org.springframework.aop.aspectj.AspectJPointcutAdvisor#1"
           value 是 AspectJPointcutAdvisor 对象,
                其中有 AbstractAspectJAdvice advice 为 AspectJAfterReturningAdvice, Pointcut pointcut 为 ComposablePointcut
        -->
        <aop:aspect id="aspect1" ref="serviceAspect">
            <aop:before method="beforeAdvice" pointcut-ref="myPoint1"/>
            <aop:after-returning method="afterReturningAdvice" pointcut-ref="myPoint1" returning="res" />
        </aop:aspect>

        <!--
           注册两个 bean
           key 是 "org.springframework.aop.aspectj.AspectJPointcutAdvisor#2"
           value 是 AspectJPointcutAdvisor 对象,
                 其中有 AbstractAspectJAdvice advice 为 AspectJMethodBeforeAdvice, Pointcut pointcut 为 ComposablePointcut

           key 是 "org.springframework.aop.aspectj.AspectJPointcutAdvisor#3"
           value 是 AspectJPointcutAdvisor 对象,
                 其中有 AbstractAspectJAdvice advice 为 AspectJAfterReturningAdvice, Pointcut pointcut 为 ComposablePointcut
        -->
        <aop:aspect id="aspect2" ref="serviceAspect">
            <aop:before method="beforeAdvice" pointcut-ref="myPoint2"/>
            <aop:after-returning method="afterReturningAdvice" pointcut-ref="myPoint2" returning="res" />
        </aop:aspect>

    </aop:config>

</beans>
// ServiceAdvice.java
public class ServiceAdvice implements MethodBeforeAdvice, AfterReturningAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("- - - ServiceAdvice before - - -");
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("- - - ServiceAdvice afterReturning - - -");
    }
}
// ServiceAspect.java
public class ServiceAspect {

    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("- - - - - ServiceAspect beforeAdvice  - - - - -");
    }

    public void afterReturningAdvice(JoinPoint joinPoint, Object res){
        System.out.println("- - - - - ServiceAspect afterReturningAdvice  - - - - -");
    }
}

一、转化 BeanDefinition

ConfigBeanDefinitionParser 处理 <aop:config> 标签

configureAutoProxyCreator(parserContext, element) 作用:构造 RootBeanDefinition,其 beanClassAspectJAwareAdvisorAutoProxyCreator;把 RootBeanDefinition 放入 beanDefinitionMap,其keyorg.springframework.aop.config.internalAutoProxyCreator

1.pointcut

parsePointcut(elt, parserContext) 解析 <aop:pointcut > 标签

构造 RootBeanDefinition,其 beanClassAspectJExpressionPointcut;把 RootBeanDefinition 放入 beanDefinitionMap,其key 是 标签的 id 属性

scope = prototype
synthetic = true

2.advisor

parseAdvisor(elt, parserContext) 解析 <aop:advisor> 标签

构造 RootBeanDefinition,其 beanClassDefaultBeanFactoryPointcutAdvisor;把 RootBeanDefinition 放入 beanDefinitionMap,其key 是 标签的 id 属性

3.aspect

parseAspect(elt, parserContext) 解析 <aop:aspect> 标签

1.解析<aop:before>

构造 RootBeanDefinition,其 beanClassMethodLocatingFactoryBean

构造 RootBeanDefinition,其 beanClassSimpleBeanFactoryAwareAspectInstanceFactory

对于 <aop:before>标签,构造 RootBeanDefinition,其 beanClassAspectJMethodBeforeAdvice

构造 RootBeanDefinition,其 beanClassAspectJPointcutAdvisor

AspectJPointcutAdvisor 放入 beanDefinitionMap,其keyorg.springframework.aop.aspectj.AspectJPointcutAdvisor#0

2.解析<aop:after-returning>

构造 RootBeanDefinition,其 beanClassMethodLocatingFactoryBean

构造 RootBeanDefinition,其 beanClassSimpleBeanFactoryAwareAspectInstanceFactory

对于 <aop:after-returning>标签,构造 RootBeanDefinition,其 beanClassAspectJAfterReturningAdvice

构造 RootBeanDefinition,其 beanClassAspectJPointcutAdvisor

AspectJPointcutAdvisor 放入 beanDefinitionMap,其keyorg.springframework.aop.aspectj.AspectJPointcutAdvisor#1

    // ConfigBeanDefinitionParser.java
    @Override
    @Nullable
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);

        configureAutoProxyCreator(parserContext, element);

        List<Element> childElts = DomUtils.getChildElements(element);
        for (Element elt: childElts) {
            String localName = parserContext.getDelegate().getLocalName(elt);
            if (POINTCUT.equals(localName)) {
                parsePointcut(elt, parserContext);
            }
            else if (ADVISOR.equals(localName)) {
                parseAdvisor(elt, parserContext);
            }
            else if (ASPECT.equals(localName)) {
                parseAspect(elt, parserContext);
            }
        }

        parserContext.popAndRegisterContainingComponent();
        return null;
    }

    private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
        AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
    }

二、构造代理类

AspectJAwareAdvisorAutoProxyCreator 实现了 BeanPostProcessor 接口,因此其会最先进行实例化

1.实例化切面类

还没有实例化对象时

AspectJAwareAdvisorAutoProxyCreator 实现了 InstantiationAwareBeanPostProcessor,使用 AspectJAwareAdvisorAutoProxyCreatorpostProcessBeforeInstantiation 处理 bean

对于 bean 的 synthetic = ‘false’ (除去pointcut,其为 ‘true’),如果 bean 实现了 AdvicePointcutAdvisorAopInfrastructureBean中一个,则放到 AspectJAwareAdvisorAutoProxyCreatorMap<Object, Boolean> advisedBeans,key 是 id,value 是 false

包括 <aop:advisor> 标签的 DefaultBeanFactoryPointcutAdvisor<aop:before> 标签的 AspectJPointcutAdvisorAspectJMethodBeforeAdvice<aop:after-returning> 标签的 AspectJPointcutAdvisorAspectJAfterReturningAdvice

<aop:before> 标签转化的 AspectJPointcutAdvisorAbstractAspectJAdvice adviceAspectJMethodBeforeAdvicePointcut pointcutComposablePointcut

2.初始化 bean

在创建 bean 生命周期中,初始化 bean 步骤中,调用 AspectJAwareAdvisorAutoProxyCreatorpostProcessAfterInitialization

把类进行处理

AspectJAwareAdvisorAutoProxyCreator 继承了 AbstractAdvisorAutoProxyCreatorAbstractAdvisorAutoProxyCreator 继承了 AbstractAutoProxyCreator

postProcessBeforeInstantiation 实例化前的后处理

postProcessAfterInstantiation 实例化后的后处理

postProcessBeforeInitialization 初始化前的后处理

postProcessAfterInitialization 初始化后的后处理,内部执行的是 wrapIfNecessary() 方法

(在 Bean 生命周期中,实例化、属性赋值、初始化、销毁
,在初始化时,会执行 BeanPostProcessorpostProcessBeforeInitialization()方法和 postProcessAfterInitialization()方法)

(如果存在需要把对象,从三级缓存放到二级缓存的情况,则会执行 AbstractAutowireCapableBeanFactorygetEarlyBeanReference() 方法,内部执行的是 wrapIfNecessary() 方法,返回代理对象)

主要在逻辑在 postProcessBeforeInstantiation 实例化前的后处理 和 postProcessAfterInitialization 初始化后的后处理

处理类,放入 AbstractAutoProxyCreatorMap<Object, Boolean> advisedBeans 中,key 是 beanName,value 是 false;放入 AbstractAutoProxyCreatorMap<Object, Class<?>> proxyTypes中,key 是 beanName,value 是 proxy.getClass()

    // AbstractAutoProxyCreator.java
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        // Create proxy here if we have a custom TargetSource.
        // Suppresses unnecessary default instantiation of the target bean:
        // The TargetSource will handle target instances in a custom fashion.
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }

        return null;
    }

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

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            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;
    }

    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);

        if (!proxyFactory.isProxyTargetClass()) {
            if (shouldProxyTargetClass(beanClass, beanName)) {
                proxyFactory.setProxyTargetClass(true);
            }
            else {
                evaluateProxyInterfaces(beanClass, proxyFactory);
            }
        }

        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        proxyFactory.addAdvisors(advisors);
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);

        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }

        return proxyFactory.getProxy(getProxyClassLoader());
    }

getAdvicesAndAdvisorsForBean() 方法找到符合当前 bean 与 advisor 匹配的 advisor

比如,当前 bean 为 StudentServiceImpl,specificInterceptors 的值为:

  • DefaultPointcutAdvisor (又ExposeInvocationInterceptor$1)
  • DefaultBeanFactoryPointcutAdvisor (<aop:advisor id="myAdvisor1" advice-ref="serviceAdvice" pointcut-ref="myPoint1"/>创建的advisor)
  • AspectJPointcutAdvisor(<aop:aspect id="aspect1" ref="serviceAspect"> <aop:before method="beforeAdvice" pointcut-ref="myPoint1"/>创建的advisor)
  • AspectJPointcutAdvisor(<aop:aspect id="aspect1" ref="serviceAspect"><aop:after-returning method="afterReturningAdvice" pointcut-ref="myPoint1" returning="res" />创建的advisor)
// AbstractAdvisorAutoProxyCreator
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

findCandidateAdvisors() 方法找到 BeanFactorybeanDefinitionMapAdvisor,并实例化 Advisor

candidateAdvisors 有:

  • DefaultBeanFactoryPointcutAdvisor
  • DefaultBeanFactoryPointcutAdvisor
  • AspectJPointcutAdvisor
  • AspectJPointcutAdvisor
  • AspectJPointcutAdvisor
  • AspectJPointcutAdvisor
    // AspectJAwareAdvisorAutoProxyCreator.java
    @Override
    protected boolean shouldSkip(Class<?> beanClass, String beanName) {
        // TODO: Consider optimization by caching the list of the aspect names
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        for (Advisor advisor : candidateAdvisors) {
            if (advisor instanceof AspectJPointcutAdvisor &&
                    ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
                return true;
            }
        }
        return super.shouldSkip(beanClass, beanName);
    }
    // ProxyFactory.java
    public Object getProxy(@Nullable ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }
    // ProxyCreatorSupport.java
    public ProxyCreatorSupport() {
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }

    public AopProxyFactory getAopProxyFactory() {
        return this.aopProxyFactory;
    }

Spring AOP的默认代理方式是jdk动态代理,还有另外一种代理方式是cglib代理,简单说前者基于接口,后者基于继承。一般采用前者,因为前者效率高。后者不建议使用

<aop:config proxy-target-class="false"> 默认是 false,会判断要代理的类是否有接口,如果有接口ProxyFactoryproxyTargetClass 默认值 false,使用 jdk动态代理;如果没有则设置 ProxyFactoryproxyTargetClasstrue,使用 cglib代理

高版本spring 设置proxy-target-class为flase或不设置,自动根据运行类选择JDK或CGLIB代理;设置proxy-target-class为true,则只使用 cglib代理

config 为 ProxyFactory,有成员变量 List<Advisor> advisors

    // DefaultAopProxyFactory.java
    @Override
    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);
        }
    }

proxiedInterfaces 为需要代理的接口 + SpringProxy + Advised + DecoratingProxy

    // JdkDynamicAopProxy.java
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
    Assert.notNull(config, "AdvisedSupport must not be null");
    if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
        throw new AopConfigException("No advisors and no TargetSource specified");
    }
    this.advised = config;
}

    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;

            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            Class<?> targetClass = (target != null ? target.getClass() : null);

            // Get the interception chain for this method.
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            if (chain.isEmpty()) {
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // We need to create a method invocation...
                MethodInvocation invocation =
                        new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

对于 <aop:pointcut > 对应的 RootBeanDefinitionsynthetic = true,不会执行 resolveBeforeInstantiation ,即此 RootBeanDefinition 是合成的,不进行实例化前解析

    // AbstractAutowireCapableBeanFactory.java
    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            // A previously detected exception with proper bean creation context already,
            // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

    @Nullable
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    @Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }
    // ReflectiveMethodInvocation.java
    @Override
    @Nullable
    public Object proceed() throws Throwable {
        //  We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

三、代理拦截

例如,由 Proxy 形成的代理,每次调用方法时,会执行 InvocationHandler 的 invoke() 方法

比如,当前 bean 为 StudentServiceImpl,JdkDynamicAopProxy 的 invoke() 方法中,形成拦截链有:

  • DefaultPointcutAdvisor 的 ExposeInvocationInterceptor
  • DefaultBeanFactoryPointcutAdvisor 的 ServiceAdvice (自定义的bean),MethodBeforeAdviceInterceptor(advice)
  • DefaultBeanFactoryPointcutAdvisor 的 ServiceAdvice (自定义的bean),AfterReturningAdviceInterceptor(advice)
  • AspectJPointcutAdvisor 的 AspectJAfterReturningAdvice,AfterReturningAdviceInterceptor(advice)
  • AspectJPointcutAdvisor 的 AspectJMethodBeforeAdvice,MethodBeforeAdviceInterceptor(advice)
// JdkDynamicAopProxy.java
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            // The target does not implement the equals(Object) method itself.
            return equals(args[0]);
        }
        else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // The target does not implement the hashCode() method itself.
            return hashCode();
        }
        else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // There is only getDecoratedClass() declared -> dispatch to proxy config.
            return AopProxyUtils.ultimateTargetClass(this.advised);
        }
        else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // Service invocations on ProxyConfig with the proxy config...
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;

        if (this.advised.exposeProxy) {
            // Make invocation available if necessary.
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        // Get as late as possible to minimize the time we "own" the target,
        // in case it comes from a pool.
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // Get the interception chain for this method.
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        }
        else {
            // We need to create a method invocation...
            MethodInvocation invocation =
                    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            retVal = invocation.proceed();
        }

        // Massage return value if necessary.
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }
        return retVal;
    }
    finally {
        if (target != null && !targetSource.isStatic()) {
            // Must have come from TargetSource.
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // Restore old proxy.
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}
// AdvisedSupport.java
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

advisors 有:ExposeInvocationInterceptor、DefaultBeanFactoryPointcutAdvisor、AspectJPointcutAdvisor、AbstractAspectJAdvice

取出 advisor 的 advice ;如果 advice 继承 MethodInterceptor,则放到 interceptors 中;继续看 advice 是否继承 MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice,如果符合,包装成 MethodBeforeAdviceInterceptor(advice)、AfterReturningAdviceInterceptor(advice)、ThrowsAdviceInterceptor(advice)

  • DefaultPointcutAdvisor 的 ExposeInvocationInterceptor
  • DefaultBeanFactoryPointcutAdvisor 的 ServiceAdvice (自定义的bean),MethodBeforeAdviceInterceptor(advice)
  • DefaultBeanFactoryPointcutAdvisor 的 ServiceAdvice (自定义的bean),AfterReturningAdviceInterceptor(advice)
  • AspectJPointcutAdvisor 的 AspectJAfterReturningAdvice,AfterReturningAdviceInterceptor(advice)
  • AspectJPointcutAdvisor 的 AspectJMethodBeforeAdvice,MethodBeforeAdviceInterceptor(advice)
// DefaultAdvisorChainFactory.java
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Advised config, Method method, @Nullable Class<?> targetClass) {

    // This is somewhat tricky... We have to process introductions first,
    // but we need to preserve order in the ultimate list.
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
    Advisor[] advisors = config.getAdvisors();
    List<Object> interceptorList = new ArrayList<>(advisors.length);
    Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
    Boolean hasIntroductions = null;

    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // Add it conditionally.
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                boolean match;
                if (mm instanceof IntroductionAwareMethodMatcher) {
                    if (hasIntroductions == null) {
                        hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                    }
                    match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
                }
                else {
                    match = mm.matches(method, actualClass);
                }
                if (match) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    if (mm.isRuntime()) {
                        // Creating a new object instance in the getInterceptors() method
                        // isn't a problem as we normally cache created chains.
                        for (MethodInterceptor interceptor : interceptors) {
                            interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                        }
                    }
                    else {
                        interceptorList.addAll(Arrays.asList(interceptors));
                    }
                }
            }
        }
        else if (advisor instanceof IntroductionAdvisor) {
            IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        else {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}
// DefaultAdvisorAdapterRegistry.java
public DefaultAdvisorAdapterRegistry() {
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
}

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
    List<MethodInterceptor> interceptors = new ArrayList<>(3);
    Advice advice = advisor.getAdvice();
    if (advice instanceof MethodInterceptor) {
        interceptors.add((MethodInterceptor) advice);
    }
    for (AdvisorAdapter adapter : this.adapters) {
        if (adapter.supportsAdvice(advice)) {
            interceptors.add(adapter.getInterceptor(advisor));
        }
    }
    if (interceptors.isEmpty()) {
        throw new UnknownAdviceTypeException(advisor.getAdvice());
    }
    return interceptors.toArray(new MethodInterceptor[0]);
}

ReflectiveMethodInvocation 执行拦截器链

// ReflectiveMethodInvocation.java
@Override
@Nullable
public Object proceed() throws Throwable {
    //  We start with an index of -1 and increment early.
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

通过每个拦截器,链式调用,实现了切面调用的顺序

// AfterReturningAdviceInterceptor.java
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    Object retVal = mi.proceed();
    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
    return retVal;
}
// MethodBeforeAdviceInterceptor.java
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
    this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    return mi.proceed();
}

若需要在被代理方法中获得代理类,则需要配置 <aop:config expose-proxy="true">,则才会在每次调用方法时,把代理对象设置到 AopContext 中的 ThreadLocal<Object> currentProxy 中,通过AopContent类,使用AopContext.currentProxy()获取代理对象

四、AOP 注解原理

@Aspect :声明这是一个切面类

@Aspect
public class ServiceAspect {

    @Pointcut("execution(public * com.example.service.StudentServiceImpl.*(..))")
    public void pointcut1(){};

    @Pointcut("execution(public * com.example.service.TeacherServiceImpl.*(..))")
    public void pointcut2(){};

    @Before("pointcut1() || pointcut2()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("- - - - - ServiceAspect beforeAdvice  - - - - -");
    }

    @AfterReturning(value = "pointcut1() || pointcut2()", returning = "res")
    public void afterReturningAdvice(JoinPoint joinPoint, Object res){
        System.out.println("- - - - - ServiceAspect afterReturningAdvice  - - - - -");
    }
}

配置类

AnnotationAwareAspectJAutoProxyCreator 相当于 <aop:aspectj-autoproxy/>

@Configuration
public class BeanConfig {

    @Bean
    public IStudentService studentService() {
        return new StudentServiceImpl();
    }

    @Bean
    public ITeacherService teacherService() {
        return new TeacherServiceImpl();
    }

    @Bean
    public ServiceAspect serviceAspect() {
        return new ServiceAspect();
    }

    @Bean
    public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
        return new AnnotationAwareAspectJAutoProxyCreator();
    }
}

1.构建 advisor

AnnotationAwareAspectJAutoProxyCreatorfindCandidateAdvisors() 方法,构造 advisor

candidateAdvisors 有:

  • InstantiationModelAwarePointcutAdvisorImpl
  • InstantiationModelAwarePointcutAdvisorImpl