zoukankan      html  css  js  c++  java
  • 深入源码解析spring aop实现的三个过程

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

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

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

    ProxyFactoryBean生成AopProxy

     

    ProxyFactoryBean生成AOP proxy

     1     /**
     2      * Return a proxy. Invoked when clients obtain beans from this factory bean.
     3      * Create an instance of the AOP proxy to be returned by this factory.
     4      * The instance will be cached for a singleton, and create on each call to
     5      * <code>getObject()</code> for a proxy.
     6      * @return a fresh AOP proxy reflecting the current state of this factory
     7      */
     8     public Object getObject() throws BeansException {
     9         initializeAdvisorChain();
    10         if (isSingleton()) {
    11             return getSingletonInstance();
    12         }
    13         else {
    14             if (this.targetName == null) {
    15                 logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
    16                         "Enable prototype proxies by setting the 'targetName' property.");
    17             }
    18             return newPrototypeInstance();
    19         }
    20     }

    初始化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

        /**
         * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
         * create an AOP proxy with <code>this</code> as an argument.
         */
        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(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.激发拦截器链主过程

     1     /**
     2      * Implementation of <code>InvocationHandler.invoke</code>.
     3      * <p>Callers will see exactly the exception thrown by the target,
     4      * unless a hook method throws an exception.
     5      */
     6     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     7         MethodInvocation invocation = null;
     8         Object oldProxy = null;
     9         boolean setProxyContext = false;
    10 
    11         TargetSource targetSource = this.advised.targetSource;
    12         Class targetClass = null;
    13         Object target = null;
    14 
    15         try {
    16             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
    17                 // The target does not implement the equals(Object) method itself.
    18                 return (equals(args[0]) ? Boolean.TRUE : Boolean.FALSE);
    19             }
    20             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
    21                 // The target does not implement the hashCode() method itself.
    22                 return new Integer(hashCode());
    23             }
    24             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
    25                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {
    26                 // Service invocations on ProxyConfig with the proxy config...
    27                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
    28             }
    29 
    30             Object retVal = null;
    31 
    32             if (this.advised.exposeProxy) {
    33                 // Make invocation available if necessary.
    34                 oldProxy = AopContext.setCurrentProxy(proxy);
    35                 setProxyContext = true;
    36             }
    37 
    38             // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,
    39             // in case it comes from a pool.
    40             target = targetSource.getTarget();
    41             if (target != null) {
    42                 targetClass = target.getClass();
    43             }
    44 
    45             // Get the interception chain for this method.
    46             List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    47 
    48             // Check whether we have any advice. If we don't, we can fallback on direct
    49             // reflective invocation of the target, and avoid creating a MethodInvocation.
    50             if (chain.isEmpty()) {
    51                 // We can skip creating a MethodInvocation: just invoke the target directly
    52                 // Note that the final invoker must be an InvokerInterceptor so we know it does
    53                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
    54                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
    55             }
    56             else {
    57                 // We need to create a method invocation...
    58                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    59                 // Proceed to the joinpoint through the interceptor chain.
    60                 retVal = invocation.proceed();
    61             }
    62 
    63             // Massage return value if necessary.
    64             if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
    65                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
    66                 // Special case: it returned "this" and the return type of the method
    67                 // is type-compatible. Note that we can't help if the target sets
    68                 // a reference to itself in another returned object.
    69                 retVal = proxy;
    70             }
    71             return retVal;
    72         }
    73         finally {
    74             if (target != null && !targetSource.isStatic()) {
    75                 // Must have come from TargetSource.
    76                 targetSource.releaseTarget(target);
    77             }
    78             if (setProxyContext) {
    79                 // Restore old proxy.
    80                 AopContext.setCurrentProxy(oldProxy);
    81             }
    82         }
    83     }

    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框架会根据业务流程要求,自动把独立编写的功能代码切入到流程的合适位置。

     
  • 相关阅读:
    SqlServer数据库同步方案详解(包括跨网段)
    makefile 和shell文件相互调用
    处理百万级以上的数据处理
    makefile Template(添加多个lib)
    Linux下如何删除非空目录
    makefile Template
    g++ 编译和链接
    gcc include路径
    C++ XML解析之TinyXML篇
    利用Lucene.net搭建站内搜索(2)分词技术
  • 原文地址:https://www.cnblogs.com/davidwang456/p/12286164.html
Copyright © 2011-2022 走看看