引言
概述: AOP系列文章:
【1】Spring Aop初始化源碼分析
【2】Spring AOP建立代理對象源碼解析
【3】Spring AOP 鍊式調用過程源碼解析
【4】Spring 事務執行過程源碼解析
1 工程概述

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 結果
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 擷取調用鍊
描述: 從代理工廠中擷取目前類有效的advisor,周遊advisor。
描述: 如果pointCut 比對類,比對方法那麼把advice封裝成MethodInterceptor對象并且存入傳回鍊中。
描述: 擷取調用鍊
5.2 調取分析
描述: 終止條件,索引等于最後一個advice。
描述: 鍊式調用