淺析:AOP的advice和advisor建立過程
@Aspect class AopAdviceConfig { @Before("execution(* *.*(..))") public void beforeAdvice(JoinPoint joinPoint) { System.out.println(joinPoint.getTarget()); System.out.println("前置通知...."); } } //定義一個介面 interface AspectJService { //測試前置通知 void beforeAdvice(); //測試後置通知 void afterAdvice(); } //實現類 class AspectJServiceImpl implements AspectJService { @Override public void beforeAdvice() { System.out.println("測試前置通知,我是第一個Service。。。。。。"); } //測試後置通知 @Override public void afterAdvice() { System.out.println("測試AspectJ後置通知。。。。"); } } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //手工建立一個例項 AspectJService aspectJService = new AspectJServiceImpl(); //使用AspectJ語法 自動建立代理物件 AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService); //新增切面和通知類 aspectJProxyFactory.addAspect(AopAdviceConfig.class); //建立代理物件 AspectJService proxyService = aspectJProxyFactory.getProxy(); //進行方法呼叫 proxyService.beforeAdvice(); }
對AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService)
進行分析
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-eysZ7rqp-1624286179017)(C:\Users\Itcod\AppData\Roaming\Typora\typora-user-images\image-20210621093703583.png)]
public AspectJProxyFactory(Object target) { Assert.notNull(target, "Target object must not be null"); setInterfaces(ClassUtils.getAllInterfaces(target)); setTarget(target); } // ClassUtils.$getAllInterfaces // 獲取instance類的所有的介面,包括超類介面 public static Class<?>[] getAllInterfaces(Object instance) { Assert.notNull(instance, "Instance must not be null"); return getAllInterfacesForClass(instance.getClass()); } public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz, @Nullable ClassLoader classLoader) { Assert.notNull(clazz, "Class must not be null"); // clazz: "class AspectJServiceImpl" 判斷是否可見、是否是介面 if (clazz.isInterface() && isVisible(clazz, classLoader)) { // 如果是介面且可見的直接返回 return Collections.singleton(clazz); } Set<Class<?>> interfaces = new LinkedHashSet<>(); // 根據當前介面進行向上搜尋,獲取所有的介面 Class<?> current = clazz; while (current != null) { Class<?>[] ifcs = current.getInterfaces(); for (Class<?> ifc : ifcs) { if (isVisible(ifc, classLoader)) { interfaces.add(ifc); } } current = current.getSuperclass(); } return interfaces; } // this.setInterfaces public void setInterfaces(Class<?>... interfaces) { Assert.notNull(interfaces, "Interfaces must not be null"); // 清除原來介面資訊,interfaces是一個ArrayList物件 this.interfaces.clear(); for (Class<?> ifc : interfaces) { addInterface(ifc); } } // 對target類包裝成SingletonTargetSource類 public void setTarget(Object target) { setTargetSource(new SingletonTargetSource(target)); } // SingletonTargetSource為TargetSource的子類 public void setTargetSource(@Nullable TargetSource targetSource) { this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE); }
新增切面類aspectJProxyFactory.addAspect(AopAdviceConfig.class);
這個方法主要呼叫了createAspectMetacdata、createAspectInstanceFactory、 addAdvisorsFromAspectInstanceFactory三個重要的方法
public void addAspect(Class<?> aspectClass) { // 獲取aspectClass的非限定類名 String aspectName = aspectClass.getName(); // 獲取Aspect的一個包裝類 AspectMetadata am = createAspectMetadata(aspectClass, aspectName); MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName); addAdvisorsFromAspectInstanceFactory(instanceFactory); }
private AspectMetadata createAspectMetadata(Class<?> aspectClass, String aspectName) {
// 將切面類和類名包裝到AspectMetadata
AspectMetadata am = new AspectMetadata(aspectClass, aspectName);
if (!am.getAjType().isAspect()) {
throw new IllegalArgumentException("Class [" + aspectClass.getName() + "] is not a valid aspect type");
}
return am;
}
public class AspectMetadata implements Serializable {
private final String aspectName;
private final Class<?> aspectClass;
// 類的型別 這個是AspectJ中定義的類 儲存了aspectClass類的類相關資訊 實現類為 AjTypeImpl
private transient AjType<?> ajType;
// 切面表示式
private final Pointcut perClausePointcut;
public AspectMetadata(Class<?> aspectClass, String aspectName) {
this.aspectName = aspectName;
Class<?> currClass = aspectClass;
AjType<?> ajType = null;
// 向上搜尋被@Aspect註解的類,直到Object
while (currClass != Object.class) {
// 原始碼解釋:這是 AspectJ 執行時型別系統的錨點,在執行時獲取給定型別的 AjType 表示的典型用法是呼叫
AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);
if (ajTypeToCheck.isAspect()) {
ajType = ajTypeToCheck;
break;
}
currClass = currClass.getSuperclass();
}
if (ajType == null) {
throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
}
if (ajType.getDeclarePrecedence().length > 0) {
throw new IllegalArgumentException("DeclarePrecedence not presently supported in Spring AOP");
}
// 被反向代理了,從包裝物件中獲取切面類
this.aspectClass = ajType.getJavaClass();
// 維護本代理的包裝物件
this.ajType = ajType;
switch (this.ajType.getPerClause().getKind()) {
}
}
}
/**
* Return the AspectJ runtime type representation of the given Java type.
* Unlike java.lang.Class, AjType understands pointcuts, advice, declare statements,
* and other AspectJ type members. AjType is the recommended reflection API for
* AspectJ programs as it offers everything that java.lang.reflect does, with
* AspectJ-awareness on top.
*/
// 獲取所傳類的AjType
public static <T> AjType<T> getAjType(Class<T> fromClass) {
WeakReference<AjType> weakRefToAjType = ajTypes.get(fromClass);
if (weakRefToAjType!=null) {
// 從快取獲取包裝類AjType
AjType<T> theAjType = weakRefToAjType.get();
if (theAjType != null) {
return theAjType;
} else {
theAjType = new AjTypeImpl<T>(fromClass);
ajTypes.put(fromClass, new WeakReference<AjType>(theAjType));
return theAjType;
}
}
// neither key nor value was found
// 對fromClass包裝成AjType型別,同時進行快取
AjType<T> theAjType = new AjTypeImpl<T>(fromClass);
ajTypes.put(fromClass, new WeakReference<AjType>(theAjType));
return theAjType;
}
createAspectInstanceFactory
從名稱可以看出這個方法是建立切面例項的一個工廠方法
private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(
AspectMetadata am, Class<?> aspectClass, String aspectName) {
MetadataAwareAspectInstanceFactory instanceFactory;
//是否是單例
if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// Create a shared aspect instance.
// 根據切面類建立一個切面類例項 需要無參構造方法
Object instance = getSingletonAspectInstance(aspectClass);
// 將instance封裝到SingletonMetadataAwareAspectInstanceFactory中
// 該類是一個單例的帶有切面元資料的切面工廠,內部再次封裝了一個AspectMetadata物件
instanceFactory = new SingletonMetadataAwareAspectInstanceFactory(instance, aspectName);
}
else {
// Create a factory for independent aspect instances.
// 將切面類封裝到SimpleMetadataAwareAspectInstanceFactory中
// 該類是一個單例的帶有切面元資料的切面工廠,內部也封裝了一個AspectMetadata物件
instanceFactory = new SimpleMetadataAwareAspectInstanceFactory(aspectClass, aspectName);
}
return instanceFactory;
}
private Object getSingletonAspectInstance(Class<?> aspectClass) {
// Quick check without a lock...
// 先嚐試從快取中嘗試獲取例項
Object instance = aspectCache.get(aspectClass);
if (instance == null) {
// 由於是單例設計,避免多執行緒的重複獲取,進行加鎖
synchronized (aspectCache) {
// To be safe, check within full lock now...
instance = aspectCache.get(aspectClass);
if (instance == null) {
instance = new SimpleAspectInstanceFactory(aspectClass).getAspectInstance();
/*
public final Object getAspectInstance() {
// 通過ReflectionUtils工具類獲取Class表示的物件
return ReflectionUtils.accessibleConstructor(this.aspectClass).newInstance();
}
*/
// 快取獲取的例項
aspectCache.put(aspectClass, instance);
}
}
}
return instance;
}
這個方法建立了一個MetaDataAwareAspectinstanceFactory的子類,用來組合切面例項和切面元資料。
addAdvisorsFromAspectInstanceFactory是一個重點的方法,獲取Advisor的邏輯都在裡面
private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
// 獲取切面類,是一個帶有Aspect註解的類,不一定是addAspect傳入的類可能是其父類
List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
// 目標類
Class<?> targetClass = getTargetClass();
Assert.state(targetClass != null, "Unresolvable target class");
advisors = AopUtils.findAdvisorsThatCanApply(advisors, targetClass);
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
AnnotationAwareOrderComparator.sort(advisors);
addAdvisors(advisors);
}
先看下getAdvisors實現
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 從aspectInstanceFactory中獲取上一步快取在其中的資料
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 驗證aspectClass例項
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
//將上一步獲取的MetadataAwareAspectInstanceFactory例項又包裝為LazySingletonAspectInstanceFactoryDecorator
//裝飾模式的一個使用
//確保只獲取到一個切面例項
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 獲取切面物件中所有的響應方法(advisor)包括父類中的
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 獲取切面類中的屬性
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 獲取切面類的切點方法的表示式例項
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 對錶達式例項,切點、aspectAdvisorFactory、切面例項工廠、、切面名進行統一包裝
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-L1S8JKqr-1624286179018)(C:\Users\Itcod\AppData\Roaming\Typora\typora-user-images\image-20210621222207939.png)]
可以看出InstantiationModelAwarePointcutAdvisorImpl是InstantiationModelAwarePointcutAdvisor的實現類同時是Advisor的一個子類。
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
/*
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
// 檢視響應方法是被哪個註解類註解的
// ASPECTJ_ANNOTATION_CLASSES =
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
*/
if (aspectJAnnotation == null) {
return null;
}
// 建立一個切面類切點表示式類
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 獲取切點表示式並進儲存在切面類切點表示式類例項中
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
// 返回例項
return ajexp;
}
可以看出在已經分析的這兩個方法中,對Aop的切面進行了驗證和向上搜尋可能包含的切面類、獲取了切面類中全部的切點方法,已經對切點方法的表示式進行了包裝儲存在AspectJProxyFactory的物件裡(粗淺概括)