深入源码解析spring aop实现的三个过程

Spring AOP的面向切面编程,是面向对象编程的一种补充,用于处理系统中分布的各个模块的横切关注点,比如说事务管理、日志、缓存等。它是使用动态代理实现的,在内存中临时为方法生成一个AOP对象,这个对象包含目标对象的所有方法,在特定的切点做了增强处理,并回调原来的方法。

Spring AOP的动态代理主要有两种方式实现,JDK动态代理和cglib动态代理。JDK动态代理通过反射来接收被代理的类,但是被代理的类必须实现接口,核心是InvocationHandler和Proxy类。cglib动态代理的类一般是没有实现接口的类,cglib是一个代码生成的类库,可以在运行时动态生成某个类的子类,所以,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

AOP实现中,可以看到三个主要的步骤,一个是代理对象的生成,然后是拦截器的作用,然后是Aspect编织的实现。

ProxyFactoryBean生成AopProxy

ProxyFactoryBean生成AOP proxy

getObject()

初始化Advisor chain

1     /**
 2      * Create the advisor (interceptor) chain. Aadvisors that are sourced
 3      * from a BeanFactory will be refreshed each time a new prototype instance
 4      * is added. Interceptors added programmatically through the factory API
 5      * are unaffected by such changes.

 6      */
 7     private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
 8         if (this.advisorChainInitialized) {
 9             return;
10         }
11
12         if (!ObjectUtils.isEmpty(this.interceptorNames)) {
13             if (this.beanFactory == null) {
14                 throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
15                         "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
16             }
17
18             // Globals can't be last unless we specified a targetSource using the property...

19             if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
20                     this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
21                 throw new AopConfigException("Target required after globals");
22             }
23
24             // Materialize interceptor chain from bean names.

25             for (int i = 0; i < this.interceptorNames.length; i++) {
26                 String name = this.interceptorNames[i];
27                 if (logger.isTraceEnabled()) {
28                     logger.trace("Configuring advisor or advice '" + name + "'");
29                 }
30
31                 if (name.endsWith(GLOBAL_SUFFIX)) {
32                     if (!(this.beanFactory instanceof ListableBeanFactory)) {
33                         throw new AopConfigException(
34                                 "Can only use global advisors or interceptors with a ListableBeanFactory");
35                     }
36                     addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
37                             name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
38                 }
39
40                 else {
41                     // If we get here, we need to add a named interceptor.

42                     // We must check if it's a singleton or prototype.

43                     Object advice = null;
44                     if (this.singleton || this.beanFactory.isSingleton(this.interceptorNames[i])) {
45                         // Add the real Advisor/Advice to the chain.

46                         advice = this.beanFactory.getBean(this.interceptorNames[i]);
47                     }
48                     else {
49                         // It's a prototype Advice or Advisor: replace with a prototype.

50                         // Avoid unnecessary creation of prototype bean just for advisor chain initialization.

51                         advice = new PrototypePlaceholderAdvisor(this.interceptorNames[i]);
52                     }
53                     addAdvisorOnChainCreation(advice, this.interceptorNames[i]);
54                 }
55             }
56         }
57
58         this.advisorChainInitialized = true;
59     }

增加advisor chain(AdvisedSupport.java)

1     private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
 2         Assert.notNull(advisor, "Advisor must not be null");
 3         if (isFrozen()) {
 4             throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
 5         }
 6         if (pos > this.advisors.size()) {
 7             throw new IllegalArgumentException(
 8                     "Illegal position " + pos + " in advisor list with size " + this.advisors.size());
 9         }
10         this.advisors.add(pos, advisor);
11         updateAdvisorArray();
12         adviceChanged();
13     }

Spring AOP中拦截器链

1.开始步骤–获取AopProxy主流程

ProxyCreatorSupport.java

this

2.获取AopProxy实现 –DefaultAopProxyFactory.java

ProxyFactoryBean类继承了AdvisedSupport类,后者继承了ProxyConfig类并定义了操作advisor 和interceptor的接口,以支持AOP。当BeanFactory实例化ProxyFactoryBean时,根据配置文件的定义将关于 advice,pointcut,advisor,所代理的接口和接口实现类的所有信息传给ProxyFactoryBean。

当客户程序调用BeanFactory的getBean方法时,ProxyFactory使用JdkDynamicAopProxy实例化 BeanImpl类,并用JdkDynamicAopProxy的invoke方法执行advice。至于执行advice的时机,由 ProxyFactoryBean调用RegexpMethodPointcutAdvisor进行判断。

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()) {
                return new JdkDynamicAopProxy(config);
            }
            if (!cglibAvailable) {
                throw new AopConfigException(
                        "Cannot proxy target class because CGLIB2 is not available. " +
                        "Add CGLIB to the class path or specify proxy interfaces.");
            }
            return CglibProxyFactory.createCglibProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

3.获取AopProxy的执行路径

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);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

4.激发拦截器链主过程

InvocationHandler.invokenull

5.获取拦截器链DefaultAdvisorChainFactory.java

public List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class targetClass) {
        // This is somewhat tricky... we have to process introductions first,
        // but we need to preserve order in the ultimate list.

        List interceptorList = new ArrayList(config.getAdvisors().length);
        boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        Advisor[] advisors = config.getAdvisors();
        for (int i = 0; i < advisors.length; i++) {
            Advisor advisor = advisors[i];
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.

                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.

                            for (int j = 0; j < interceptors.length; j++) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j], mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        return interceptorList;
    }
6.激发拦截链工作实现 ---ReflectiveMethodInvocation.java

    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;
            if (dm.methodMatcher.matches(this.method, this.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);
        }
    }

Spring AOP中Aspect编织的实现

1.前面我们谈到拦截器起作用时,实现代码(ReflectiveMethodInvocation.java)如下:

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;
            if (dm.methodMatcher.matches(this.method, this.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);
        }
    }

2.前置Advice MethodBeforeAdviceInterceptor.java

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

3.后置Advice AfterReturningAdviceInterceptor.java

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

总结

没图没真相

深入源码解析spring aop实现的三个过程

Spring框架的AOP机制可以让开发者把业务流程中的通用功能抽取出来,单独编写功能代码。在业务流程执行过程中,Spring框架会根据业务流程要求,自动把独立编写的功能代码切入到流程的合适位置。

Original: https://www.cnblogs.com/davidwang456/p/12286164.html
Author: 一天不进步,就是退步
Title: 深入源码解析spring aop实现的三个过程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541968/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球