深入源碼解析spring aop實現的三個過程

AOP實現中,可以看到三個主要的步驟,一個是代理對象的生成,然後是攔截器的作用,然後是Aspect編織的實現。


ProxyFactoryBean生成AopProxy

深入源碼解析spring aop實現的三個過程

ProxyFactoryBean生成AOP proxy

<code> 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     }/<code>

初始化Advisor chain

<code> 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     }/<code>

增加advisor chain(AdvisedSupport.java)

<code> 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     }/<code>

Spring AOP中攔截器鏈

1.開始步驟--獲取AopProxy主流程

ProxyCreatorSupport.java

<code>    /**     * Subclasses should call this to get a new AOP proxy. They should not     * create an AOP proxy with <code>this/<code> as an argument.     */    protected final synchronized AopProxy createAopProxy() {        if (!this.active) {            activate();        }        return getAopProxyFactory().createAopProxy(this);    }/<code>


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進行判斷。

<code>    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);        }    }/<code>

3.獲取AopProxy的執行路徑

<code>    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);    }/<code>

4.激發攔截器鏈主過程

<code> 1     /** 2      * Implementation of <code>InvocationHandler.invoke/<code>. 3      * 

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 direct49 // 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 directly52 // Note that the final invoker must be an InvokerInterceptor so we know it does53 // 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 method67 // is type-compatible. Note that we can't help if the target sets68 // 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 }

/<code>

5.獲取攔截器鏈DefaultAdvisorChainFactory.java

<code>    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;    }/<code>

6.激發攔截鏈工作實現 ---ReflectiveMethodInvocation.java

<code>    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);        }    }/<code>

Spring AOP中Aspect編織的實現

1.前面我們談到攔截器起作用時,實現代碼(ReflectiveMethodInvocation.java)如下:

<code>    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);        }    }/<code>

2.前置Advice MethodBeforeAdviceInterceptor.java

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

3.後置Advice AfterReturningAdviceInterceptor.java

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

總結

沒圖沒真相

深入源碼解析spring aop實現的三個過程

深入源碼解析spring aop實現的三個過程



分享到:


相關文章: