天天看點

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

引言

概述: AOP系列文章:

【1】Spring Aop初始化源碼分析

【2】Spring AOP建立代理對象源碼解析

【3】Spring AOP 鍊式調用過程源碼解析

【4】Spring 事務執行過程源碼解析

1 工程概述

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

1.1 pom

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.2.8.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
        <!-- 日志相關依賴 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.10</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
           

1.2 配置檔案

@Configuration
@EnableAspectJAutoProxy
@Import(ServiceAopConfig.class)
public class AopConfig {


}

@Configuration
@Aspect
public class ServiceAopConfig {

    /**
     * 聲明切點
     */
    @Pointcut("execution(* com.rosh.service.*.*(..))")
    public void pointCut() {

    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("ServiceAopConfig invoke around start");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("ServiceAopConfig invoke around end");
        return proceed;
    }

    @Before("pointCut()")
    public void before(){
        System.out.println("ServiceAopConfig invoke before");
    }

    @After("pointCut()")
    public void after() {
        System.out.println("ServiceAopConfig invoke after");
    }
}


           

1.3 Service

public interface StudentService {

     void addStudent();

}


@Service
public class StudentServiceImpl implements StudentService {

    @Override
    public void addStudent() {
        System.out.println("StudentServiceImpl invoke addStudent()");
    }
}


           

1.4 RoshTest

public class RoshTest {

    @Test
    public void mainTest(){

        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext("com.rosh");
        StudentService studentService = (StudentService) applicationContext.getBean("studentServiceImpl");
        studentService.addStudent();


    }

}

           

1. 5 結果

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

2 前置步驟概述

(1) BeanFactoryAspectJAdvisorsBuilder會收集項目中所有advisor(pointCut+advice)。
(2) AbstractAutoProxyCreator在進行後置增強時,會擷取目前bean的有效advisor清單。
(3) 如果advisor清單不為空那麼建立代理對象,首先建立ProxyFactory工廠配置增強類型(預設使用JDK,如果目前增強bean不是接口實作類,那麼使用cglib),一個代理對象對應一個代理工廠,并把有效的advisor存入工廠中,并且把工廠資訊存入代理對象,最後傳回代理對象。
           
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		/**
		 *  【1】建立代理工廠,指派。
		 */
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		/**
		 * 【2】 proxyTargetClass為true時代表使用cglib,為false使用jdk,預設值是false。
		 *  判斷目前被代理對象是使用jdk增強還是使用cglib增強
		 *
		 */
		if (!proxyFactory.isProxyTargetClass()) {
			//根據最開始@EnableAspectJAutoProxy注解中的proxyTargetClass參數判斷是否應該使用cglib代理
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				//如果是接口增強那麼使用jdk,否則使用cglib
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		//建構advisor
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		//把advisor加入到代理工廠中
		proxyFactory.addAdvisors(advisors);
		//把targetSource對象加入代理工廠(實際對象、被代理對象)
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		/**
		 * 【3】 擷取代理對象
		 */
		return proxyFactory.getProxy(getProxyClassLoader());
	}
           

3 調取源碼解析

描述: JdkDynamicAopProxy invoke方法詳解:

@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		/**
		 * 【1】擷取代理工廠
		 */
		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			/**
			 * 【2】 擷取真實對象
			 */
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			/**
			 * 【3】 擷取方法鍊
			 *
			 *  (1) 根據代理工廠擷取有效的advisors
			 *  (2) 周遊advisors,比對類、比對方法為true的advisor,擷取advice,封裝成MethodInterceptor對象。
			 *  (3) 将建構出來的MethodInterceptor對象,添加到攔截鍊中。
			 *
			 */
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.

			/**
			 * 【4】 如果沒有調用鍊,直接反射調用方法
			 */
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.

				/**
				 * 【5】 鍊式調取
				 */
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}
           

4 擷取調用鍊源碼解析

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {

			/**
			 * 擷取調用鍊
			 */
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}
           
@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

		/**
		 * 【1】 從代理工廠中擷取真實對象(被代理對象)的advisor
		 */
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;

				/**
				 * 【2】 判斷advisor是否比對類和方法
				 */
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					}
					else {
						match = mm.matches(method, actualClass);
					}

					/**
					 * 【3】 如果pointcut 比對類 并且比對方法
					 */
					if (match) {
						//擷取advisor中的advice,并且包裝成MethodInterceptor類型的對象
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

           

5 debug

5.1 擷取調用鍊

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

描述: 從代理工廠中擷取目前類有效的advisor,周遊advisor。

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

描述: 如果pointCut 比對類,比對方法那麼把advice封裝成MethodInterceptor對象并且存入傳回鍊中。

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

描述: 擷取調用鍊

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

5.2 調取分析

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

描述: 終止條件,索引等于最後一個advice。

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug

描述: 鍊式調用

Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug
Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug
Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug
Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug
Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug
Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug
Spring AOP 鍊式調用過程源碼解析引言1 工程概述2 前置步驟概述3 調取源碼解析4 擷取調用鍊源碼解析5 debug