美文网首页
Spring AOP实现源码分析

Spring AOP实现源码分析

作者: Sscon70 | 来源:发表于2018-11-30 22:11 被阅读0次

    Spring AOP实现

    概念简介

    • Aspect:系统中,功能模块或者类的横切面的一种抽象。举例来说,web应用常见的事务管理即是典型的Aspect。各个服务功能(或类方法),都需要实现事务管理(一般指数据库事务),这种横跨多个功能的相同逻辑,可以称之为Aspect。
    • Join Point:系统功能的执行点,方法调用或者方法抛出的异常处理,都可以称之为Join Point。AOP的目的就是在方法某处执行自定义的功能,归纳为在【哪里】执行【什么功能】,这个【哪里】就是指Join Point。Spring中,Join Point指的是方法调用,从方法层级来切入。
    • Advice:在Join Point执行的具体动作,即【什么功能】。Advice分为多种类型,around、before、after等。通常,Advice以拦截器Interceptor的方式实现,某个方法的Advice的interceptor会组成一个链,来执行多个Advice的功能。
    • Pointcut:匹配Join Point的规则。例如,可以指定匹配带有【add】前缀的所有方法。Advice要关联Pointcut使用,来确定动作具体在哪里执行。Spring使用的是AspectJ的表达式。
    • Introduction:通常意义上的Advice都是附加在某个已有的方法上来指定额外的功能,Introduction可以在指定类上增加方法或者属性。通过Introduction可以帮指定bean引入新的接口,实现新的功能。

    Spring代理实现技术

    ​ Spring代理的实现方式有两种:

    JDK代理:如果代理目标类实现了至少一个接口,那么接口的方法代理就可以使用JDK代理来实现。如果目标类没有实现任何接口,那么将使用CGLIB来实现代理功能

    CGLIB:主要实现方式是对生成一个目标类的子类,来对方法实行覆盖,所以不可覆盖的方法无法利用此方式来代理。

    ​ Spring内部依赖于这两种方式来实现代理,下面简单举例,说明一下二者的实现方式的区别

    JDK代理

    ​ 由于JDK代理需要接口的实现,所以先自定义一个简单的接口:

    public interface Fly {
        void fly();
    }
    

    ​ 定义一个简单类实现接口:

    public class Bird implements Fly{
        @Override
        public void fly() {
            System.out.println("this is bird flying");
        }
    }
    

    ​ JDK代理主要使用InvocationHandler接口来实现方法的代理:

    public class FlyInvocationHandler implements InvocationHandler {
        /**
         * 代理目标类
         */
        private Object target;
    
        public FlyInvocationHandler(Object target) {
            super();
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 代理方式执行前后,自定义逻辑
            System.out.println("invocation interceptor, before");
            Object invokeResult = method.invoke(target, args);
            System.out.println("invocation interceptor, after");
            return invokeResult;
        }
        /**
         * 返回代理类对象
         *
         * @return the proxy
         * @author liuxinxing5 2018年11月30日 11:05
         */
        public Object getProxy() {
            return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    target.getClass().getInterfaces(), this);
        }
    }
    
    

    ​ 测试代理类:

    public class JdkProxyTest {
        public static void main(String[] args) {
            FlyInvocationHandler handler = new FlyInvocationHandler(new Bird());
            Fly fly = (Fly) handler.getProxy();
            fly.fly();
        }
    }
    

    ​ 测试输出:

    invocation interceptor, before
    this is bird flying
    invocation interceptor, after
    

    CGLIB

    public class EnhancerDemo {
    
        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer();
            // 设置代理目标
            enhancer.setSuperclass(EnhancerDemo.class);
            // 设置代理的action,即Advice
            enhancer.setCallback(new MethodInterceptorImpl());
            EnhancerDemo demo = (EnhancerDemo) enhancer.create();
            demo.test(100);
        }
    
        public void test(int i) {
            System.out.println("inside enhancer demo " + i);
        }
    
        private static class MethodInterceptorImpl implements MethodInterceptor {
    
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("interceptor  begin   ");
                Object res = methodProxy.invokeSuper(o, objects);
                System.out.println("interceptor  end     ");
                return res;
            }
        }
    }
    

    ​ 测试输出:

    interceptor  begin   
    inside enhancer demo 100
    interceptor  end
    

    Spring代理实现逻辑

    简单示例

    ​ 首先先定义一个简单的Bean:

    public class TestBean {
        // 被代理方法
        public void test() {
            System.out.println("inside test bean");
        }
    }
    

    test()方法是被代理的测试方法,下面需要定义代理的配置。Spring代理配置可以使用两种方式,XML配置注解配置

    XML配置

    ​ 新增一个aop的配置类,XMLAop.java

    public class XMLAop {
        // 用于before Advice测试
        public void before() {
            System.out.println("inside xml configured before method");
        }
        // 用于around Advice测试
        public Object around(ProceedingJoinPoint point) throws Throwable {
            System.out.println("inside xml configured around method 1");
            Object result = point.proceed(point.getArgs());
            System.out.println("inside xml configured around method 2");
            return result;
        }
    }
    

    ​ XML配置aop.xml

    <?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <aop:aspectj-autoproxy/>
    <!--XMLAop配置为Bean-->
    <bean id="xmlAop" class="com.sscon.aop.spring.XMLAop"/>
    <aop:config>
        <!--Aspect配置-->
        <aop:aspect id="xmlAspect" ref="xmlAop">
            <!--定义pointcut匹配规则,用于匹配join point,这里直接匹配所有test方法-->
            <aop:pointcut id="somePointCut"
                          expression="execution(* com.sscon.aop.spring.*.test(..))" />
            <!--指定before的Advice action-->
            <aop:around method="around" pointcut-ref="somePointCut" />
            <!--指定around的Advice action-->
            <aop:before method="before" pointcut-ref="somePointCut" />
        </aop:aspect>
    </aop:config>
    <bean id="test" class="com.sscon.aop.spring.TestBean" />
    

    ​ 测试test()方法输出:

    public static void main(String[] args) {
        ApplicationContext c = new ClassPathXmlApplicationContext("aop.xml");
        // 获取test bean
        TestBean test = (TestBean)c.getBean("test");
        // 指定test方法
        test.test();
    }
    

    ​ 测试输出:

    inside xml configured around method 1
    inside xml configured before method
    inside test bean   
    inside xml configured around method 2
    

    注解配置

    ​ 注解配置方式就是对XMLAop类作简单修改,增加注解:

    @Aspect
    public class XMLAop {
    
        @Pointcut("execution(* com.sscon.aop.spring.*.test(..))")
        public void test() {
        }
        @Before("test()")
        public void before() {
            System.out.println("inside xml configured before method");
        }
    
        @Around("test()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            System.out.println("inside xml configured around method 1");
            Object result = point.proceed();
            System.out.println("inside xml configured around method 2");
            return result;
        }
    }
    

    ​ 关键注解:

    @Aspect:表明此类是一个Aspect配置

    @Pointcut:注解于void返回值的方法,用于定义join point的匹配规则

    @Before:定义before类型的Advice,方法内指定执行的逻辑

    @Aroud:定义around类型的Advice,方法内指定执行的逻辑,注解的方法的参数第一个必须为ProceedingJoinPoint ,使用ProceedingJoinPoint.proceed方法类实现对被代理目标方法的调用

    ...

    ​ XML配置aop.xml移除aspect的相关配置:

    <?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <aop:aspectj-autoproxy/>
    <!--XMLAop配置为Bean-->
    <bean id="xmlAop" class="com.sscon.aop.spring.XMLAop"/>
    <bean id="test" class="com.sscon.aop.spring.TestBean" />
    

    ​ 测试test()方法输出:

    inside xml configured around method 1
    inside xml configured before method
    inside test bean   
    inside xml configured around method 2
    

    源码分析

    AOP功能入口,创建ProxyCreator

    ​ Spring xml配置文件中,<aop:aspectj-autoproxy>是开启aop功能的入口,所以我们从此xml标签的解析来分析Spring的处理流程。

    ​ 在AopNamespaceHandler类中,Spring注册了aop标签配置的解析器,AspectJAutoProxyBeanDefinitionParser

    // AopNamespaceHandler.java
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        // 注册处理aspectj-autoproxy标签的处理器
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
    
        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }
    
    

    AspectJAutoProxyBeanDefinitionParser类实现了BeanDefinitionParser接口,BeanDefinitionParser是Spring用来解析<beans>直接子节点的接口,主要逻辑是parse方法:

    // AspectJAutoProxyBeanDefinitionParser.java
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        AopNamespaceUtils.
        registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        extendBeanDefinition(element, parserContext);
        return null;
    }
    // AopNamespaceUtils.java
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        ParserContext parserContext, Element sourceElement) {
        // 注册代理的creator
        BeanDefinition beanDefinition = AopConfigUtils.
            registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        // 处理proxy-target-class 和 expose-proxy属性
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }
    // AopConfigUtils.java
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        BeanDefinitionRegistry registry, Object source) {
        return registerOrEscalateApcAsRequired(
            AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }
    

    ​ 跟踪到AopConfigUtilsregisterOrEscalateApcAsRequired方法,可以看到Spring注册代理creator的逻辑,其中参数clsAnnotationAwareAspectJAutoProxyCreator.class,这个方法的主要逻辑是注册一个创建代理的工具类:

    如果当前没有注册AUTO_PROXY_CREATOR_BEAN_NAME的代理Creator,那么使用cls参数指定的类作为工具创建

    如果当前注册了AUTO_PROXY_CREATOR_BEAN_NAME的Creator,那么要进行优先级排序,确定具体使用AnnotationAwareAspectJAutoProxyCreator还是已经创建的Creator

    Spring默认使用AnnotationAwareAspectJAutoProxyCreator

    // AopConfigUtils.java
    public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
                "org.springframework.aop.config.internalAutoProxyCreator";
    
    static {
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }
    
    private static BeanDefinition registerOrEscalateApcAsRequired(
        Class<?> cls, BeanDefinitionRegistry registry, Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        // 如果当前已注册AUTO_PROXY_CREATOR_BEAN_NAME的creator,那么需要做一下选择
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = 
                registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                // 已注册的creator和指定cls不同,根据优先级排序选择
                int currentPriority = 
                    // 当前已注册的creator的优先级,优先级根据APC_PRIORITY_LIST中的
                    // 序号来表示,AnnotationAwareAspectJAutoProxyCreator位于序号2
                    // 是最高的优先级
                    findPriorityForClass(apcDefinition.getBeanClassName());
                // cls指定的creator的优先级
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    // 如果cls指定的优先级高,那么更换为cls的creator
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }
    

    代理配置处理

    ​ 注册完代理的Creator后,还需要处理指定的配置信息,读取用户的配置信息后,保存:

    // AopNamespaceUtils.java
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        ParserContext parserContext, Element sourceElement) {
        // 注册代理的creator
        BeanDefinition beanDefinition = AopConfigUtils.
            registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        // 处理proxy-target-class 和 expose-proxy属性
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }
    // AopConfigUtils.java
    private static void useClassProxyingIfNecessary(
        BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {
            // PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class"
            boolean proxyTargetClass = Boolean.parseBoolean(
                sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            // EXPOSE_PROXY_ATTRIBUTE = "expose-proxy"
            boolean exposeProxy = Boolean.parseBoolean(
                sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }
    // AopConfigUtils.java
    public static void forceAutoProxyCreatorToUseClassProxying(
        BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = 
                registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }
    }
    // AopConfigUtils.java
    public static void forceAutoProxyCreatorToExposeProxy(
        BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = 
                registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
        }
    }
    

    ​ proxy-target-class与expose-proxy属性:

    proxy-target-class:Spring默认使用JDK代理来实现代理功能(前提是类至少实现了一个接口),该属性可以强制指定使用CGLIB来实现代理功能

    expose-proxy:被代理对象如果存在自我调用,例如a方法调用b方法,两个方法都被代理,那么b方法是无法执行代理逻辑的。

    被代理对象内部方法调用的问题

    ​ 拿一个简单的例子来描述这个问题,TestBean有方法被代理,test()test2(),test内部调用test2,test2方法配置的代理逻辑不会执行:

    public class TestBean {
        // 被代理方法
        public void test() {
            System.out.println("inside test bean");
            test2();
        }
        // 被代理方法
        public void test2() {
            System.out.println("inside test2 bean   ");
        }
    }
    

    ​ 如果代理的配置如下:

    @Aspect
    public class XMLAop {
        // test test2方法都会匹配
        @Pointcut("execution(* com.sscon.aop.spring.*.test*(..))")
        public void test() {
    
        }
        @Before("test()")
        public void before() {
            System.out.println("inside xml configured before method");
        }
    }
    

    ​ 输出如下:

    inside xml configured before method
    inside test bean   
    inside test2 bean   
    

    ​ 如果希望test2()方法也执行代理的逻辑,Spring给出一个解决办法是,将expose-proxy修改为true吗,暴露Spring生成的代理实体,且修改test()方法的逻辑:

    public class TestBean {
        public void test() {
            System.out.println("inside test bean   ");
            // 拿到Spring生成的代理,指定test2()的方法,如果不修改expose-proxy配置,会报错
            ((TestBean)AopContext.currentProxy()).test2();
        }
        public void test2() {
            System.out.println("inside test2 bean   ");
        }
    }
    

    使用代理Creator创建代理

    ​ Spring默认使用AnnotationAwareAspectJAutoProxyCreator来对Spring管理的Bean做代理创建处理,此类实现了BeanPostProcessorBeanPostProcessor的关键方法是postProcessAfterInitialization。Bean初始化完成之后会调用此方法对Bean进行处理。该方法的实现在抽象父类AbstractAutoProxyCreator

    // AbstractAutoProxyCreator.java
    public Object postProcessAfterInitialization(Object bean, String beanName) 
        throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                // 没有缓存存在时,初始化代理
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
    

    ​ 从上面的逻辑可以看到,当没有缓存时,使用wrapIfNecessary方法进行代理初始化:

    // AbstractAutoProxyCreator.java
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 判断是否已经处理过
        if (beanName != null && 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;
        }
        // 拿到Bean所有配置的interceptors
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
            bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 根据interceptors创建代理并缓存
            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;
    }
    
    获取Bean所有配置的interceptors

    ​ Spring内部使用Advisor类来保存Advice和Pointcut的配置信息,获取Bean所有可用的Advisor的基本逻辑是:

    首先拿到所有的advice配置,保留xml配置与注解配置

    根据被代理类的实体,决定具体哪些advice可以应用于当前实体类

    对advice排序,返回

    // AbstractAdvisorAutoProxyCreator.java
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
                                                    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) {
        // 查找所有可能的advice配置
        List<Advisor> candidateAdvisors = findCandidateAdvisors();
        // 过滤处理,拿到所有匹配的advice配置
        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(
            candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            // 多个advisor需要进行排序,确定所有代理的advice逻辑的执行顺序
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }
    

    ​ findCandidateAdvisors,主要负责读取所有配置的Advice,包括两个部分,一种是xml配置,一种的注解配置:

    // AnnotationAwareAspectJAutoProxyCreator.java
    protected List<Advisor> findCandidateAdvisors() {
        // 将父类读取的advisor也保存到结果中,这里主要是xml配置的advice
        List<Advisor> advisors = super.findCandidateAdvisors();
        // 读取注解配置的advice
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }
    

    ​ 查询注解配置的advice信息的基本逻辑是:

    首先获取所有的Bean信息,遍历

    判断Bean是否具有Aspect注解,如果有,获取Advisor信息,其中包括配置的Pointcut规则,Advice配置等

    缓存查询结果,方便下次查询

    // BeanFactoryAspectJAdvisorsBuilder.java
    public List<Advisor> buildAspectJAdvisors() {
        List<String> aspectNames = this.aspectBeanNames;
    
        if (aspectNames == null) {
            // 缓存结果
            synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) {
                    List<Advisor> advisors = new LinkedList<Advisor>();
                    aspectNames = new LinkedList<String>();
                    // 查询所有的bean
                    String[] beanNames = 
                        BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                    for (String beanName : beanNames) {
                        // 是否合法,默认返回true
                        if (!isEligibleBean(beanName)) {
                            continue;
                        }
                        // 拿到Bean的Class对象
                        Class<?> beanType = this.beanFactory.getType(beanName);
                        if (beanType == null) {
                            continue;
                        }
                        // 如果有Aspect注解
                        if (this.advisorFactory.isAspect(beanType)) {
                            aspectNames.add(beanName);
                            AspectMetadata amd = new AspectMetadata(beanType, beanName);
                            if (amd.getAjType().getPerClause().getKind() 
                                == PerClauseKind.SINGLETON) {
                                MetadataAwareAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(
                                    this.beanFactory, beanName);
                                // 获取所有的advice信息并保存到列表
                                List<Advisor> classAdvisors = 
                                    this.advisorFactory.getAdvisors(factory);
                                if (this.beanFactory.isSingleton(beanName)) {
                                    this.advisorsCache.put(beanName, classAdvisors);
                                }
                                else {
                                    this.aspectFactoryCache.put(beanName, factory);
                                }
                                advisors.addAll(classAdvisors);
                            }
                            else {
                                // Per target or per this.
                                if (this.beanFactory.isSingleton(beanName)) {
                                    throw new IllegalArgumentException(
                                        "Bean with name '" + beanName +
                  "' is a singleton, but aspect instantiation model is not singleton");
                                }
                                MetadataAwareAspectInstanceFactory factory =
                                    new PrototypeAspectInstanceFactory(
                                    this.beanFactory, beanName);
                                this.aspectFactoryCache.put(beanName, factory);         
                                advisors.addAll(this.advisorFactory
                                              .getAdvisors(factory));
                            }
                        }
                    }
                    this.aspectBeanNames = aspectNames;
                    return advisors;
                }
            }
        }
    
        if (aspectNames.isEmpty()) {
            return Collections.emptyList();
        }
        // 从缓存中获取advice信息并返回
        List<Advisor> advisors = new LinkedList<Advisor>();
        for (String aspectName : aspectNames) {
            List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
            if (cachedAdvisors != null) {
                advisors.addAll(cachedAdvisors);
            }
            else {
                MetadataAwareAspectInstanceFactory factory = 
                    this.aspectFactoryCache.get(aspectName);
                advisors.addAll(this.advisorFactory.getAdvisors(factory));
            }
        }
        return advisors;
    }
    

    ​ 获取Bean类的Advisor的逻辑:

    遍历Bean的方法,带有@Pointcut注解的方法除外,因为@Pointcut配置的是join point的匹配规则,单独处理

    如果该方法有配置@Before等注解,那么构造Advisor,放入结果列表中

    如果属性有配置@DeclareParents,那么构造Advisor,放入结果列表中

    // ReflectiveAspectJAdvisorFactory.java
    public List<Advisor> getAdvisors(
        MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
        Class<?> aspectClass = aspectInstanceFactory
            .getAspectMetadata().getAspectClass();
        String aspectName = aspectInstanceFactory
            .getAspectMetadata().getAspectName();
        validate(aspectClass);
    
        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = 
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
        // 保存Advisor信息
        List<Advisor> advisors = new LinkedList<Advisor>();
        // 遍历当前Bean类的非Pointcut注解的方法,判断是否有@Before等注解配置
        for (Method method : getAdvisorMethods(aspectClass)) {
            // 尝试获取方法的Advisor,如果当前类没有@Pointcut配置或者方法没有任何Advice配置
            // 都会直接返回null
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 
                                         advisors.size(), aspectName);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
        if (!advisors.isEmpty() 
            && lazySingletonAspectInstanceFactory.
            getAspectMetadata().isLazilyInstantiated()) {
            Advisor instantiationAdvisor = new 
                SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
            advisors.add(0, instantiationAdvisor);
        }
        // 构造@DeclareParents注解的Advisor,这个配置是附加在属性上,所以单独处理
        // @DeclareParents主要是用于给Bean类增加新的方法,而不是在已有方法上附加行为
        for (Field field : aspectClass.getDeclaredFields()) {
            Advisor advisor = getDeclareParentsAdvisor(field);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
        return advisors;
    }
    

    ​ 接着上述逻辑,获取方法的Advisor的逻辑为:

    // ReflectiveAspectJAdvisorFactory.java
    public Advisor getAdvisor(Method candidateAdviceMethod, 
                              MetadataAwareAspectInstanceFactory aspectInstanceFactory,
                              int declarationOrderInAspect, String aspectName) {
        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
        // 获取Pointcut配置
        AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, 
            aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }
        // 根据查询到的注解初初始化Advisor
        return new InstantiationModelAwarePointcutAdvisorImpl(
            expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }
    
    private AspectJExpressionPointcut getPointcut(
        Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        // 获取@Before等注解
        AspectJAnnotation<?> aspectJAnnotation =
            AbstractAspectJAdvisorFactory
            .findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }
    
        AspectJExpressionPointcut ajexp =
            new AspectJExpressionPointcut(
            candidateAspectClass, new String[0], new Class<?>[0]);
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        ajexp.setBeanFactory(this.beanFactory);
        return ajexp;
    }
    // AbstractAspectJAdvisorFactory.java
    protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
        Class<?>[] classesToLookFor = new Class<?>[] {
            Before.class, Around.class, After.class, 
            AfterReturning.class, AfterThrowing.class, Pointcut.class};
        for (Class<?> c : classesToLookFor) {
            AspectJAnnotation<?> foundAnnotation = 
                findAnnotation(method, (Class<Annotation>) c);
            if (foundAnnotation != null) {
                return foundAnnotation;
            }
        }
        return null;
    }
    

    ​ 由查询到的注解配置信息构造Advisor(包含Advice,Pointcut等信息):

    // InstantiationModelAwarePointcutAdvisorImpl.java
    public InstantiationModelAwarePointcutAdvisorImpl(
        AspectJExpressionPointcut declaredPointcut,     
        Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, 
        int declarationOrder, String aspectName) {
            ...  
        if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
            ...
        }
        else {
            this.pointcut = this.declaredPointcut;
            this.lazy = false;
            // 根据@Before等初始化Advice
            this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        }
    }
    
    private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
        return this.aspectJAdvisorFactory.getAdvice(
            this.aspectJAdviceMethod, pcut,
            this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    }
    

    ​ 初始化Advice的逻辑,可以看到是根据不同的注解生成不同的Advice对象,主要由工厂生成:

    public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
                MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
        ....
        AbstractAspectJAdvice springAdvice;
    
        switch (aspectJAnnotation.getAnnotationType()) {
            case AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                AfterReturning afterReturningAnnotation = 
                    (AfterReturning) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            ...
                return null;
            default:
                throw new UnsupportedOperationException(
                    "Unsupported advice type on method: " + candidateAdviceMethod);
        }
        ...
    }
    

    ​ 到此逻辑,Spring已经可以拿到用户配置的所有Aspect,接下来是遍历这些配置,过滤出哪些Aspect配置可以应用于当前Bean类

    过滤可应用于Bean的interceptors

    ​ 上一步查询出已经配置的所有的Aspect的配置,Advisor列表,根据Advisor中的Pointcut配置,来比对Bean中的方法,如果可以匹配,那么Advisor可应用于当前Bean:

    // AbstractAdvisorAutoProxyCreator.java
    protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
        ProxyCreationContext.setCurrentProxiedBeanName(beanName);
        try {
            return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        }
        finally {
            ProxyCreationContext.setCurrentProxiedBeanName(null);
        }
    }
    // AopUtils.java
    public static List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        for (Advisor candidate : candidateAdvisors) {
            // @DeclareParents类型
            if (candidate instanceof IntroductionAdvisor 
                && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor) {
                // introduction类型已经处理
                continue;
            }
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
    

    ​ 主要判断逻辑处于canApply方法,主要逻辑是判断Bean的所有接口与Bean自己的所有方法是否可以应用Advisor中的Pointcut规则,如果任一方法可以,那就可以认为Advisor可以用于当前Bean:

    // AopUtils.java
    public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        if (advisor instanceof IntroductionAdvisor) {
            return ((IntroductionAdvisor) advisor)
                .getClassFilter().matches(targetClass);
        }
        else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor) advisor;
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
            return true;
        }
    }
    
    public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }
        // Pointcut配置的方法过滤为默认True类型,直接返回即可
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
            return true;
        }
        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = 
                (IntroductionAwareMethodMatcher) methodMatcher;
        }
        // 存放代理目标类的所有接口类
        Set<Class<?>> classes = new LinkedHashSet<Class<?>>(
            ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        // 把代理目标类也放入set
        classes.add(targetClass);
        // 上述所有类的任一方法可以匹配Pointcut,认为此Advisor可以应用于当前被代理类
        for (Class<?> clazz : classes) {
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                if ((introductionAwareMethodMatcher != null 
                     && introductionAwareMethodMatcher.matches(
                         method, targetClass, hasIntroductions)) 
                    || methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }
        return false;
    }
    

    ​ 至此,Spring已经拿到当前Bean可应用的Advisor列表,接下来就是利用Advisor和Bean来创建代理类

    代理创建逻辑

    ​ 前文提到的AbstractAutoProxyCreatorwrapIfNecessary方法中包含了实际代理创建的逻辑:

    // AbstractAutoProxyCreator.java
    protected Object createProxy(
                Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
        ... proxyFactory的初始化逻辑
        // 利用proxyFactory创建代理
        return proxyFactory.getProxy(getProxyClassLoader());
    }
    // ProxyFactory.java
    public Object getProxy(ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }
    // ProxyCreatorSupport.java
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }
    // DefaultAopProxyFactory.java
    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);
            }
            // ObjenesisCglibAopProxy是CglibAopProxy子类,做了一些逻辑优化
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
    

    ​ 可以看到,Spring根据代理目标类是否实现接口,配置中是否强制开启CGLIB,来决定使用哪一种方式来创建代理。

    JdkDynamicAopProxy

    ​ JdkDynamicAopProxy与JDK代理简单实例中的一致,实现了InvocationHandler接口,主要逻辑位于invoke方法中,主要是将所有interceptor组成一个链,然后调用链执行,最后执行被代理方法:

    // JdkDynamicAopProxy.java
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        ...
        try {
            Object retVal;
            ...
            // interceptor组成一个链,链式调用
            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();
            }
            ...
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                return retVal;
            }
            finally {
                ...
            }
        }
    

    ​ interceptor链执行:

    // ReflectiveMethodInvocation.java
    public Object proceed() throws Throwable {
        //  最后执行join point方法,也就是被代理方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
    
        Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers
            .get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice 
            instanceof InterceptorAndDynamicMethodMatcher) {
            // 匹配当前方法,执行拦截的代理逻辑
            InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, 
                                         this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // 不匹配当前方法,跳过
                return proceed();
            }
        }
        else {
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    
    CglibAopProxy

    ​ CGLIB构造代理的方式与示例类似,都是利用Enhancer类来进行构造:

    // CglibAopProxy.java
    public Object getProxy(ClassLoader classLoader) {
        try {
            ...
            // 配置Enhancer...
            Enhancer enhancer = createEnhancer();
            ...
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(
                AopProxyUtils.completeProxiedInterfaces(this.advised));
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setStrategy(
                new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
            // 获取关键的代理执行逻辑方法,callback方法
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }
            // 设置CallBackFilter
            enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), 
                this.fixedInterceptorMap, this.fixedInterceptorOffset));
            enhancer.setCallbackTypes(types);
            // 设置CallBack方法
            return createProxyClassAndInstance(enhancer, callbacks);
        }...
    }
    

    ​ 获取CallBack方法的主要逻辑为:

    // CglibAopProxy.java
    private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
        boolean exposeProxy = this.advised.isExposeProxy();
        boolean isFrozen = this.advised.isFrozen();
        boolean isStatic = this.advised.getTargetSource().isStatic();
    
        // 获取aop配置的CallBack
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
    
        // 一些优化策略
        ...
        Callback[] mainCallbacks = new Callback[] {
            aopInterceptor,  // xml和注解配置的aop代理逻辑
            targetInterceptor,  // 优化
            new SerializableNoOp(),  // 优化
            targetDispatcher, this.advisedDispatcher,
            new EqualsInterceptor(this.advised),
            new HashCodeInterceptor(this.advised)
        };
        Callback[] callbacks;
        // 一些优化策略
        ...
        return callbacks;
    }
    

    DynamicAdvisedInterceptor实现了MethodInterceptor接口,也就是CGLIB示例中的CallBack方法的实现:

    // DynamicAdvisedInterceptor.java
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Class<?> targetClass = null;
        Object target = null;
        try {
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            target = getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }
            List<Object> chain = this.advised
                .getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                // 直接调用目标类的方法
                Object[] argsToUse = AopProxyUtils
                    .adaptArgumentsIfNecessary(method, args);
                retVal = methodProxy.invoke(target, argsToUse);
            }
            else {
                // 同样是调用链的创建,CglibMethodInvocation直接继承JDK代理使用的
                // ReflectiveMethodInvocation,主要逻辑没有变化
                retVal = new CglibMethodInvocation(proxy, target, 
                                                   method, args, targetClass, 
                                                   chain, methodProxy).proceed();
            }
            retVal = processReturnType(proxy, target, method, retVal);
            return retVal;
        }
        finally {
            if (target != null) {
                releaseTarget(target);
            }
            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
    
    

    ​ 使用JDK或CGLIB创建代理后,Bean在AOP的Postprocess的流程就结束了。后续调用Bean方法时,就可以实现AOP方法的调用。

    相关文章

      网友评论

          本文标题:Spring AOP实现源码分析

          本文链接:https://www.haomeiwen.com/subject/enpkcqtx.html