深入原始碼解析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; }
總結
沒圖沒真相
&nbs