@Aspect 註解切面解析
阿新 • • 發佈:2019-01-28
sin ace 抽象類 ast iso 異常 info his getmethod
註解切面解析
- 註解切面解析器
/** * 註解切面解析器 */ public class BeanFactoryAspectJAdvisorsBuilder { /** * Bean 工廠 */ private final ListableBeanFactory beanFactory; /** * 生成 Advisor 的工廠 */ private final AspectJAdvisorFactory advisorFactory; /** * 切面 Bean 名稱 */ @Nullable private volatile List<String> aspectBeanNames; /** * 通知者緩存 */ private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>(); /** * 切面實例緩存 */ private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = new ConcurrentHashMap<>(); public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory) { this(beanFactory, new ReflectiveAspectJAdvisorFactory(beanFactory)); } public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) { Assert.notNull(beanFactory, "ListableBeanFactory must not be null"); Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null"); this.beanFactory = beanFactory; this.advisorFactory = advisorFactory; } public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = aspectBeanNames; if (aspectNames == null) { final List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // 讀取容器中所有的類 final String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( beanFactory, Object.class, true, false); for (final String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // 讀取 Bean 的類型,不能執行初始化操作 final Class<?> beanType = beanFactory.getType(beanName); if (beanType == null) { continue; } // 指定的 bean 是否是一個註解切面 if (advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); // 創建切面元數據 final AspectMetadata amd = new AspectMetadata(beanType, beanName); // 切面是否是單例 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { final MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(beanFactory, beanName); // 基於目標切面創建相關的 Advisor final List<Advisor> classAdvisors = advisorFactory.getAdvisors(factory); // 切面 bean 是單例 && 將通知者加入緩存 if (beanFactory.isSingleton(beanName)) { advisorsCache.put(beanName, classAdvisors); } else { aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. if (beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name ‘" + beanName + "‘ is a singleton, but aspect instantiation model is not singleton"); } final MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(beanFactory, beanName); aspectFactoryCache.put(beanName, factory); advisors.addAll(advisorFactory.getAdvisors(factory)); } } } aspectBeanNames = aspectNames; return advisors; } } } // 無註解切面 if (aspectNames.isEmpty()) { return Collections.emptyList(); } final List<Advisor> advisors = new ArrayList<>(); for (final String aspectName : aspectNames) { // 獲取指定註解切面的所有 Advisor final List<Advisor> cachedAdvisors = advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { final MetadataAwareAspectInstanceFactory factory = aspectFactoryCache.get(aspectName); advisors.addAll(advisorFactory.getAdvisors(factory)); } } return advisors; } /** * 指定 bean 名稱的切面是否合格 */ protected boolean isEligibleBean(String beanName) { return true; } }
- 通知者創建工廠
/** * 基於標註了 AspectJ 註解的類創建 Spring AOP 通知者 */ public interface AspectJAdvisorFactory { /** * 指定類型是否是一個切面 */ boolean isAspect(Class<?> clazz); /** * 指定類型是否是一個有效的 AspectJ 切面類 */ void validate(Class<?> aspectClass) throws AopConfigException; /** * 將所有標註了 AspectJ 註解的方法轉換為 Advisor */ List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory); /** * 為給定的AspectJ通知方法構建一個Spring AOP通知 */ @Nullable Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName); /** * 為給定的AspectJ通知方法構建一個Spring AOP通知 * * @param candidateAdviceMethod 候選通知方法 * @param expressionPointcut AspectJ 切點表達式 * @param aspectInstanceFactory Aspect 實例工廠 * @param declarationOrder 通知方法在切面中的聲明順序 * @param aspectName 切面的名稱 * @return {@code null} 非通知方法和切點都返回 null * * @see org.springframework.aop.aspectj.AspectJAroundAdvice 環繞通知 * @see org.springframework.aop.aspectj.AspectJMethodBeforeAdvice 前置通知 * @see org.springframework.aop.aspectj.AspectJAfterAdvice 後置通知 * @see org.springframework.aop.aspectj.AspectJAfterReturningAdvice 正常返回通知 * @see org.springframework.aop.aspectj.AspectJAfterThrowingAdvice 異常通知 */ @Nullable Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName); } public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFactory { private static final String AJC_MAGIC = "ajc$"; /** * AspectJ 註解類型 */ private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] { Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class}; /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); protected final ParameterNameDiscoverer parameterNameDiscoverer = new AspectJAnnotationParameterNameDiscoverer(); /** * 目標類型是否是一個註解切面【目標類型上存在 @Aspect 註解並且不是由 ajc 編譯】 */ @Override public boolean isAspect(Class<?> clazz) { return hasAspectAnnotation(clazz) && !compiledByAjc(clazz); } /** * 目標類型上是否有 Aspect 註解【如果沒有直接標註,則嘗試遞歸查找父類及其類型上的註解、實現的接口及其類型上的註解】 */ private boolean hasAspectAnnotation(Class<?> clazz) { return AnnotationUtils.findAnnotation(clazz, Aspect.class) != null; } private boolean compiledByAjc(Class<?> clazz) { for (final Field field : clazz.getDeclaredFields()) { // 方法名稱由 ajc$ 開頭 if (field.getName().startsWith(AJC_MAGIC)) { return true; } } return false; } @Override public void validate(Class<?> aspectClass) throws AopConfigException { // 如果父類有註解而不是抽象類,那就是一個錯誤 if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null && !Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) { throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" + aspectClass.getSuperclass().getName() + "]"); } final AjType<?> ajType = AjTypeSystem.getAjType(aspectClass); if (!ajType.isAspect()) { throw new NotAnAtAspectException(aspectClass); } if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOW) { throw new AopConfigException(aspectClass.getName() + " uses percflow instantiation model: " + "This is not supported in Spring AOP."); } if (ajType.getPerClause().getKind() == PerClauseKind.PERCFLOWBELOW) { throw new AopConfigException(aspectClass.getName() + " uses percflowbelow instantiation model: " + "This is not supported in Spring AOP."); } } /** * 查找並返回給定方法上的第一個 AspectJ註釋。 * 查找順序:Pointcut.class, Around.class, Before.class, * After.class, AfterReturning.class, AfterThrowing.class */ @SuppressWarnings("unchecked") @Nullable protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) { for (final Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) { final AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz); if (foundAnnotation != null) { return foundAnnotation; } } return null; } @Nullable private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) { final A result = AnnotationUtils.findAnnotation(method, toLookFor); if (result != null) { return new AspectJAnnotation<>(result); } else { return null; } } /** * AspectJ 註解類型枚舉 */ protected enum AspectJAnnotationType { AtPointcut, AtAround, AtBefore, AtAfter, AtAfterReturning, AtAfterThrowing } /** * 對一個 AspectJ 註解進行建模,公開其類型枚舉和切點字符串 */ protected static class AspectJAnnotation<A extends Annotation> { private static final String[] EXPRESSION_ATTRIBUTES = new String[] {"pointcut", "value"}; private static Map<Class<?>, AspectJAnnotationType> annotationTypeMap = new HashMap<>(8); static { annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut); annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround); annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore); annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter); annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning); annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing); } /** * 目標註解 */ private final A annotation; /** * AspectJ 註解類型枚舉 */ private final AspectJAnnotationType annotationType; /** * 切點字符串 */ private final String pointcutExpression; /** * 參數名稱 */ private final String argumentNames; public AspectJAnnotation(A annotation) { this.annotation = annotation; this.annotationType = determineAnnotationType(annotation); try { this.pointcutExpression = resolveExpression(annotation); final Object argNames = AnnotationUtils.getValue(annotation, "argNames"); this.argumentNames = argNames instanceof String ? (String) argNames : ""; } catch (final Exception ex) { throw new IllegalArgumentException(annotation + " is not a valid AspectJ annotation", ex); } } private AspectJAnnotationType determineAnnotationType(A annotation) { final AspectJAnnotationType type = annotationTypeMap.get(annotation.annotationType()); if (type != null) { return type; } throw new IllegalStateException("Unknown annotation type: " + annotation); } private String resolveExpression(A annotation) { // "pointcut", "value" for (final String attributeName : EXPRESSION_ATTRIBUTES) { final Object val = AnnotationUtils.getValue(annotation, attributeName); if (val instanceof String) { final String str = (String) val; if (!str.isEmpty()) { return str; } } } throw new IllegalStateException("Failed to resolve expression: " + annotation); } public AspectJAnnotationType getAnnotationType() { return this.annotationType; } public A getAnnotation() { return this.annotation; } public String getPointcutExpression() { return this.pointcutExpression; } public String getArgumentNames() { return this.argumentNames; } @Override public String toString() { return this.annotation.toString(); } } /** * 解析在 AspectJ 註解級別定義的參數 */ private static class AspectJAnnotationParameterNameDiscoverer implements ParameterNameDiscoverer { @Override @Nullable public String[] getParameterNames(Method method) { if (method.getParameterCount() == 0) { return new String[0]; } // 讀取目標方法上的 AspectJ 註解 final AspectJAnnotation<?> annotation = findAspectJAnnotationOnMethod(method); if (annotation == null) { return null; } final StringTokenizer nameTokens = new StringTokenizer(annotation.getArgumentNames(), ","); if (nameTokens.countTokens() > 0) { final String[] names = new String[nameTokens.countTokens()]; for (int i = 0; i < names.length; i++) { names[i] = nameTokens.nextToken(); } return names; } else { return null; } } @Override @Nullable public String[] getParameterNames(Constructor<?> ctor) { throw new UnsupportedOperationException("Spring AOP cannot handle constructor advice"); } } } /** * 通過反射來執行 AspectJ 註解關聯的通知方法的 AdvisorFactory */ @SuppressWarnings("serial") public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable { private static final Comparator<Method> METHOD_COMPARATOR; static { final Comparator<Method> adviceKindComparator = new ConvertingComparator<>( // 根據聲明的類型順序進行排序 new InstanceComparator<>( Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class), (Converter<Method, Annotation>) method -> { final AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method); return annotation != null ? annotation.getAnnotation() : null; }); final Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName); METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator); } @Nullable private final BeanFactory beanFactory; public ReflectiveAspectJAdvisorFactory() { this(null); } public ReflectiveAspectJAdvisorFactory(@Nullable BeanFactory beanFactory) { this.beanFactory = beanFactory; } @Override public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { // 讀取切面類型 final Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); // 讀取切面名稱 final String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); // 驗證切面類 validate(aspectClass); // 只實例化切面一次的裝飾器 final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); final List<Advisor> advisors = new ArrayList<>(); // 讀取除切點外的所有方法 for (final Method method : getAdvisorMethods(aspectClass)) { // 嘗試從目標方法上構建 Advisor,創建 InstantiationModelAwarePointcutAdvisorImpl 時即初始化 final Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), 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()) { final Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // 是否需要動態地為指定的類型增加方法:讀取當前切面中定義的所有字段 for (final Field field : aspectClass.getDeclaredFields()) { final Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; } private List<Method> getAdvisorMethods(Class<?> aspectClass) { final List<Method> methods = new ArrayList<>(); ReflectionUtils.doWithMethods(aspectClass, method -> { // 排除切點方法 if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) { methods.add(method); } }); // 排序 methods.sort(METHOD_COMPARATOR); return methods; } /** * 嘗試為指定的類型新增方法 */ @Nullable private Advisor getDeclareParentsAdvisor(Field introductionField) { // 1)目標屬性上存在 DeclareParents 註解 final DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class); if (declareParents == null) { return null; } // 2)指定了增強實現 if (DeclareParents.class == declareParents.defaultImpl()) { throw new IllegalStateException("‘defaultImpl‘ attribute must be set on DeclareParents"); } return new DeclareParentsAdvisor( introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); } @Override @Nullable public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); // 讀取切點表達式 final AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); } @Nullable private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { /** * 查找並返回給定方法上的第一個 AspectJ 註釋。 * 查找順序:Pointcut.class, Around.class, Before.class, * After.class, AfterReturning.class, AfterThrowing.class */ final AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // 創建 AspectJ 表達式切點 final AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (beanFactory != null) { ajexp.setBeanFactory(beanFactory); } return ajexp; } @Override @Nullable public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { final Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); final AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // If we get here, we know we have an AspectJ method. Check that it‘s an AspectJ-annotated class if (!isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method ‘" + candidateAdviceMethod + "‘ in class [" + candidateAspectClass.getName() + "]"); } if (logger.isDebugEnabled()) { logger.debug("Found AspectJ method: " + candidateAdviceMethod); } AbstractAspectJAdvice springAdvice; switch (aspectJAnnotation.getAnnotationType()) { // 切點 case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut ‘" + candidateAdviceMethod.getName() + "‘"); } return null; // 環繞通知 case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; // 前置通知 case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; // 後置通知 case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; // 正常返回通知 case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); // 如果 AfterReturning 通知將方法返回結果綁定了命名參數 final AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; // 異常通知 case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); // 如果 AfterThrowing 通知將方法拋出的異常綁定了命名參數 final AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); } // 配置 Advice springAdvice.setAspectName(aspectName); // 聲明順序 springAdvice.setDeclarationOrder(declarationOrder); // 解析參數名稱 final String[] argNames = parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } // 計算參數綁定 springAdvice.calculateArgumentBindings(); return springAdvice; } /** * 實例化此切面的合成通知則 */ @SuppressWarnings("serial") protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor { public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) { super(aif.getAspectMetadata().getPerClausePointcut(), (MethodBeforeAdvice) (method, args, target) -> aif.getAspectInstance()); } } }
- 通知分類
/** * 封裝 AspectJ 切面或 AspectJ 註解的通知方法 */ @SuppressWarnings("serial") public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable { /** * Key used in ReflectiveMethodInvocation userAttributes map for the current joinpoint. */ protected static final String JOIN_POINT_KEY = JoinPoint.class.getName(); /** * 延遲初始化當前調用的連接點 */ public static JoinPoint currentJoinPoint() { final MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation(); if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } final ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; JoinPoint jp = (JoinPoint) pmi.getUserAttribute(JOIN_POINT_KEY); if (jp == null) { jp = new MethodInvocationProceedingJoinPoint(pmi); pmi.setUserAttribute(JOIN_POINT_KEY, jp); } return jp; } private final Class<?> declaringClass; private final String methodName; private final Class<?>[] parameterTypes; protected transient Method aspectJAdviceMethod; private final AspectJExpressionPointcut pointcut; private final AspectInstanceFactory aspectInstanceFactory; /** * 切面 bean 的名稱 */ private String aspectName = ""; /** * 通知在切面內的聲明順序 */ private int declarationOrder; /** * 通知方法參數名稱數組 */ @Nullable private String[] argumentNames; /** 異常通知:目標方法拋出的異常所綁定的參數名稱 */ @Nullable private String throwingName; /** 正常返回通知:目標方法的執行結果所綁定的參數名稱 */ @Nullable private String returningName; private Class<?> discoveredReturningType = Object.class; private Class<?> discoveredThrowingType = Object.class; /** * 通知方法的第一個參數為 JoinPoint,則為 0 */ private int joinPointArgumentIndex = -1; /** * 通知方法的第一個參數為 JoinPoint.StaticPart,則為 0 */ private int joinPointStaticPartArgumentIndex = -1; @Nullable private Map<String, Integer> argumentBindings; /** * 參數是否已經內省 */ private boolean argumentsIntrospected = false; @Nullable private Type discoveredReturningGenericType; // Note: Unlike return type, no such generic information is needed for the throwing type, // since Java doesn‘t allow exception types to be parameterized. public AbstractAspectJAdvice( Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) { Assert.notNull(aspectJAdviceMethod, "Advice method must not be null"); declaringClass = aspectJAdviceMethod.getDeclaringClass(); methodName = aspectJAdviceMethod.getName(); parameterTypes = aspectJAdviceMethod.getParameterTypes(); this.aspectJAdviceMethod = aspectJAdviceMethod; this.pointcut = pointcut; this.aspectInstanceFactory = aspectInstanceFactory; } public final Method getAspectJAdviceMethod() { return aspectJAdviceMethod; } public final AspectJExpressionPointcut getPointcut() { calculateArgumentBindings(); return pointcut; } /** * 構建一個排除了 AspectJ 通知方法本身的安全切入點 */ public final Pointcut buildSafePointcut() { final Pointcut pc = getPointcut(); final MethodMatcher safeMethodMatcher = MethodMatchers.intersection( new AdviceExcludingMethodMatcher(aspectJAdviceMethod), pc.getMethodMatcher()); return new ComposablePointcut(pc.getClassFilter(), safeMethodMatcher); } public final AspectInstanceFactory getAspectInstanceFactory() { return aspectInstanceFactory; } @Nullable public final ClassLoader getAspectClassLoader() { return aspectInstanceFactory.getAspectClassLoader(); } @Override public int getOrder() { return aspectInstanceFactory.getOrder(); } public void setAspectName(String name) { aspectName = name; } @Override public String getAspectName() { return aspectName; } public void setDeclarationOrder(int order) { declarationOrder = order; } @Override public int getDeclarationOrder() { return declarationOrder; } public void setArgumentNames(String argNames) { final String[] tokens = StringUtils.commaDelimitedListToStringArray(argNames); setArgumentNamesFromStringArray(tokens); } public void setArgumentNamesFromStringArray(String... args) { argumentNames = new String[args.length]; for (int i = 0; i < args.length; i++) { argumentNames[i] = StringUtils.trimWhitespace(args[i]); if (!isVariableName(argumentNames[i])) { throw new IllegalArgumentException( "‘argumentNames‘ property of AbstractAspectJAdvice contains an argument name ‘" + argumentNames[i] + "‘ that is not a valid Java identifier"); } } if (argumentNames != null) { if (aspectJAdviceMethod.getParameterCount() == argumentNames.length + 1) { // May need to add implicit join point arg name... final Class<?> firstArgType = aspectJAdviceMethod.getParameterTypes()[0]; if (firstArgType == JoinPoint.class || firstArgType == ProceedingJoinPoint.class || firstArgType == JoinPoint.StaticPart.class) { final String[] oldNames = argumentNames; argumentNames = new String[oldNames.length + 1]; argumentNames[0] = "THIS_JOIN_POINT"; System.arraycopy(oldNames, 0, argumentNames, 1, oldNames.length); } } } } public void setReturningName(String name) { throw new UnsupportedOperationException("Only afterReturning advice can be used to bind a return value"); } protected void setReturningNameNoCheck(String name) { // name could be a variable or a type... if (isVariableName(name)) { returningName = name; } else { // assume a type try { discoveredReturningType = ClassUtils.forName(name, getAspectClassLoader()); } catch (final Throwable ex) { throw new IllegalArgumentException("Returning name ‘" + name + "‘ is neither a valid argument name nor the fully-qualified " + "name of a Java type on the classpath. Root cause: " + ex); } } } protected Class<?> getDiscoveredReturningType() { return discoveredReturningType; } @Nullable protected Type getDiscoveredReturningGenericType() { return discoveredReturningGenericType; } public void setThrowingName(String name) { throw new UnsupportedOperationException("Only afterThrowing advice can be used to bind a thrown exception"); } protected void setThrowingNameNoCheck(String name) { // name could be a variable or a type... if (isVariableName(name)) { throwingName = name; } else { // assume a type try { discoveredThrowingType = ClassUtils.forName(name, getAspectClassLoader()); } catch (final Throwable ex) { throw new IllegalArgumentException("Throwing name ‘" + name + "‘ is neither a valid argument name nor the fully-qualified " + "name of a Java type on the classpath. Root cause: " + ex); } } } protected Class<?> getDiscoveredThrowingType() { return discoveredThrowingType; } private boolean isVariableName(String name) { final char[] chars = name.toCharArray(); if (!Character.isJavaIdentifierStart(chars[0])) { return false; } for (int i = 1; i < chars.length; i++) { if (!Character.isJavaIdentifierPart(chars[i])) { return false; } } return true; } /** * 1)如果第一個參數是 JoinPoint 或 ProceedingJoinPoint,則我們將傳遞一個 JoinPoint * 【如果是環繞通知,則傳遞 ProceedingJoinPoint】給它。 * 2)如果第一個參數是 JoinPoint.StaticPart,則我們將傳遞一個 JoinPoint.StaticPart 給它。 * 剩余的參數,切點將基於指定的連接點進行計算後執行綁定 */ public final synchronized void calculateArgumentBindings() { // 無需執行參數綁定操作 if (argumentsIntrospected || parameterTypes.length == 0) { return; } // 未綁定的參數個數 int numUnboundArgs = parameterTypes.length; // 通知方法的參數類型數組 final Class<?>[] parameterTypes = aspectJAdviceMethod.getParameterTypes(); /** * 第一個參數類型是 JoinPoint、ProceedingJoinPoint、JoinPoint.StaticPart, * 則將 numUnboundArgs 減 1 */ if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) || maybeBindJoinPointStaticPart(parameterTypes[0])) { numUnboundArgs--; } if (numUnboundArgs > 0) { // 按照匹配的切入點,返回的名稱綁定參數 bindArgumentsByName(numUnboundArgs); } argumentsIntrospected = true; } /** * 是否是 JoinPoint */ private boolean maybeBindJoinPoint(Class<?> candidateParameterType) { if (JoinPoint.class == candidateParameterType) { joinPointArgumentIndex = 0; return true; } else { return false; } } /** * 是否是 ProceedingJoinPoint */ private boolean maybeBindProceedingJoinPoint(Class<?> candidateParameterType) { if (ProceedingJoinPoint.class == candidateParameterType) { if (!supportsProceedingJoinPoint()) { throw new IllegalArgumentException("ProceedingJoinPoint is only supported for around advice"); } joinPointArgumentIndex = 0; return true; } else { return false; } } protected boolean supportsProceedingJoinPoint() { return false; } /** * 是否是 JoinPoint.StaticPart */ private boolean maybeBindJoinPointStaticPart(Class<?> candidateParameterType) { if (JoinPoint.StaticPart.class == candidateParameterType) { joinPointStaticPartArgumentIndex = 0; return true; } else { return false; } } /** * 根據名稱實現參數綁定 */ private void bindArgumentsByName(int numArgumentsExpectingToBind) { if (argumentNames == null) { // 讀取參數名稱數組 argumentNames = createParameterNameDiscoverer().getParameterNames(aspectJAdviceMethod); } if (argumentNames != null) { // 綁定顯示的參數 bindExplicitArguments(numArgumentsExpectingToBind); } else { throw new IllegalStateException("Advice method [" + aspectJAdviceMethod.getName() + "] " + "requires " + numArgumentsExpectingToBind + " arguments to be bound by name, but " + "the argument names were not specified and could not be discovered."); } } /** * 創建一個用於實現參數綁定的 ParameterNameDiscoverer */ protected ParameterNameDiscoverer createParameterNameDiscoverer() { final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); final AspectJAdviceParameterNameDiscoverer adviceParameterNameDiscoverer = new AspectJAdviceParameterNameDiscoverer(pointcut.getExpression()); adviceParameterNameDiscoverer.setReturningName(returningName); adviceParameterNameDiscoverer.setThrowingName(throwingName); // Last in chain, so if we‘re called and we fail, that‘s bad... adviceParameterNameDiscoverer.setRaiseExceptions(true); discoverer.addDiscoverer(adviceParameterNameDiscoverer); return discoverer; } private void bindExplicitArguments(int numArgumentsLeftToBind) { Assert.state(argumentNames != null, "No argument names available"); argumentBindings = new HashMap<>(); final int numExpectedArgumentNames = aspectJAdviceMethod.getParameterCount(); if (argumentNames.length != numExpectedArgumentNames) { throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames + " arguments to bind by name in advice, but actually found " + argumentNames.length + " arguments."); } // 需要顯式綁定的參數起始索引 final int argumentIndexOffset = parameterTypes.length - numArgumentsLeftToBind; for (int i = argumentIndexOffset; i < argumentNames.length; i++) { argumentBindings.put(argumentNames[i], i); } // 如果是 AfterReturning 通知 && 指定了綁定返回值的參數名稱 if (returningName != null) { // 通知方法中不存在此綁定參數,則拋出 IllegalStateException 異常 if (!argumentBindings.containsKey(returningName)) { throw new IllegalStateException("Returning argument name ‘" + returningName + "‘ was not bound in advice arguments"); } else { // 讀取參數索引 final Integer index = argumentBindings.get(returningName); // 寫入返回值類型 discoveredReturningType = aspectJAdviceMethod.getParameterTypes()[index]; // 寫入返回值泛型 discoveredReturningGenericType = aspectJAdviceMethod.getGenericParameterTypes()[index]; } } // 如果是 AfterThrowing 通知 && 指定了綁定異常的參數名稱 if (throwingName != null) { // 通知方法中不存在此綁定參數,則拋出 IllegalStateException 異常 if (!argumentBindings.containsKey(throwingName)) { throw new IllegalStateException("Throwing argument name ‘" + throwingName + "‘ was not bound in advice arguments"); } else { // 讀取參數索引 final Integer index = argumentBindings.get(throwingName); // 寫入異常類型 discoveredThrowingType = aspectJAdviceMethod.getParameterTypes()[index]; } } // 按需配置切點表達式 configurePointcutParameters(argumentNames, argumentIndexOffset); } private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) { int numParametersToRemove = argumentIndexOffset; if (returningName != null) { numParametersToRemove++; } if (throwingName != null) { numParametersToRemove++; } // 需要執行綁定的切點參數名稱數組 final String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove]; // 需要執行綁定的切點參數類型數組 final Class<?>[] pointcutParameterTypes = new Class<?>[pointcutParameterNames.length]; // 通知方法參數類型數組 final Class<?>[] methodParameterTypes = aspectJAdviceMethod.getParameterTypes(); int index = 0; for (int i = 0; i < argumentNames.length; i++) { // 嘗試跳過第一個參數 if (i < argumentIndexOffset) { continue; } // 嘗試跳過 returningName 和 throwingName 參數 if (argumentNames[i].equals(returningName) || argumentNames[i].equals(throwingName)) { continue; } pointcutParameterNames[index] = argumentNames[i]; pointcutParameterTypes[index] = methodParameterTypes[i]; index++; } // 寫入切點參數名稱數組 pointcut.setParameterNames(pointcutParameterNames); // 寫入切點參數名稱類型數組 pointcut.setParameterTypes(pointcutParameterTypes); } /** * 執行參數綁定並返回綁定後的參數列表 */ protected Object[] argBinding(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) { calculateArgumentBindings(); // AMC start final Object[] adviceInvocationArgs = new Object[parameterTypes.length]; int numBound = 0; if (joinPointArgumentIndex != -1) { adviceInvocationArgs[joinPointArgumentIndex] = jp; numBound++; } else if (joinPointStaticPartArgumentIndex != -1) { adviceInvocationArgs[joinPointStaticPartArgumentIndex] = jp.getStaticPart(); numBound++; } if (!CollectionUtils.isEmpty(argumentBindings)) { // binding from pointcut match if (jpMatch != null) { final PointcutParameter[] parameterBindings = jpMatch.getParameterBindings(); for (final PointcutParameter parameter : parameterBindings) { final String name = parameter.getName(); final Integer index = argumentBindings.get(name); adviceInvocationArgs[index] = parameter.getBinding(); numBound++; } } // binding from returning clause if (returningName != null) { final Integer index = argumentBindings.get(returningName); adviceInvocationArgs[index] = returnValue; numBound++; } // binding from thrown exception if (throwingName != null) { final Integer index = argumentBindings.get(throwingName); adviceInvocationArgs[index] = ex; numBound++; } } if (numBound != parameterTypes.length) { throw new IllegalStateException("Required to bind " + parameterTypes.length + " arguments, but only bound " + numBound + " (JoinPointMatch " + (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)"); } return adviceInvocationArgs; } /** * 執行通知方法 */ protected Object invokeAdviceMethod( @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex)); } protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable t) throws Throwable { return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t)); } protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable { Object[] actualArgs = args; if (aspectJAdviceMethod.getParameterCount() == 0) { actualArgs = null; } try { ReflectionUtils.makeAccessible(aspectJAdviceMethod); // TODO AopUtils.invokeJoinpointUsingReflection return aspectJAdviceMethod.invoke(aspectInstanceFactory.getAspectInstance(), actualArgs); } catch (final IllegalArgumentException ex) { throw new AopInvocationException("Mismatch on arguments to advice method [" + aspectJAdviceMethod + "]; pointcut expression [" + pointcut.getPointcutExpression() + "]", ex); } catch (final InvocationTargetException ex) { throw ex.getTargetException(); } } protected JoinPoint getJoinPoint() { return currentJoinPoint(); } @Nullable protected JoinPointMatch getJoinPointMatch() { final MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation(); if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } return getJoinPointMatch((ProxyMethodInvocation) mi); } @Nullable protected JoinPointMatch getJoinPointMatch(ProxyMethodInvocation pmi) { final String expression = pointcut.getExpression(); return expression != null ? (JoinPointMatch) pmi.getUserAttribute(expression) : null; } @Override public String toString() { return getClass().getName() + ": advice method [" + aspectJAdviceMethod + "]; " + "aspect name ‘" + aspectName + "‘"; } /** * 排除指定通知方法的 MethodMatcher * MethodMatcher that excludes the specified advice method. * @see AbstractAspectJAdvice#buildSafePointcut() */ private static class AdviceExcludingMethodMatcher extends StaticMethodMatcher { private final Method adviceMethod; public AdviceExcludingMethodMatcher(Method adviceMethod) { this.adviceMethod = adviceMethod; } @Override public boolean matches(Method method, Class<?> targetClass) { return !adviceMethod.equals(method); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof AdviceExcludingMethodMatcher)) { return false; } final AdviceExcludingMethodMatcher otherMm = (AdviceExcludingMethodMatcher) other; return adviceMethod.equals(otherMm.adviceMethod); } @Override public int hashCode() { return adviceMethod.hashCode(); } } } @SuppressWarnings("serial") public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable { public AspectJMethodBeforeAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public void before(Method method, Object[] args, @Nullable Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); } @Override public boolean isBeforeAdvice() { return true; } @Override public boolean isAfterAdvice() { return false; } } @SuppressWarnings("serial") public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable { public AspectJAroundAdvice( Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJAroundAdviceMethod, pointcut, aif); } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return false; } @Override protected boolean supportsProceedingJoinPoint() { return true; } @Override public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } final ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; final ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); final JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null, null); } /** * Return the ProceedingJoinPoint for the current invocation, */ protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) { return new MethodInvocationProceedingJoinPoint(rmi); } } @SuppressWarnings("serial") public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implements AfterReturningAdvice, AfterAdvice, Serializable { public AspectJAfterReturningAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return true; } @Override public void setReturningName(String name) { setReturningNameNoCheck(name); } @Override public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable { // 如果返回值類型和關聯的通知參數類型匹配,則執行返回通知 if (shouldInvokeOnReturnValueOf(method, returnValue)) { invokeAdviceMethod(getJoinPointMatch(), returnValue, null); } } private boolean shouldInvokeOnReturnValueOf(Method method, @Nullable Object returnValue) { final Class<?> type = getDiscoveredReturningType(); final Type genericType = getDiscoveredReturningGenericType(); // If we aren‘t dealing with a raw type, check if generic parameters are assignable. return matchesReturnValue(type, method, returnValue) && (genericType == null || genericType == type || TypeUtils.isAssignable(genericType, method.getGenericReturnType())); } /** * 返回值類型是否匹配 */ private boolean matchesReturnValue(Class<?> type, Method method, @Nullable Object returnValue) { if (returnValue != null) { return ClassUtils.isAssignableValue(type, returnValue); } else if (Object.class == type && void.class == method.getReturnType()) { return true; } else { return ClassUtils.isAssignable(type, method.getReturnType()); } } } @SuppressWarnings("serial") public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public Object invoke(MethodInvocation mi) throws Throwable { try { // 執行目標方法 return mi.proceed(); } finally { invokeAdviceMethod(getJoinPointMatch(), null, null); } } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return true; } } @SuppressWarnings("serial") public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterThrowingAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { super(aspectJBeforeAdviceMethod, pointcut, aif); } @Override public boolean isBeforeAdvice() { return false; } @Override public boolean isAfterAdvice() { return true; } @Override public void setThrowingName(String name) { setThrowingNameNoCheck(name); } @Override public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (final Throwable ex) { // 是否需要執行異常通知 if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } } /** * 異常類型是否和通知方法中的參數匹配 */ private boolean shouldInvokeOnThrowing(Throwable ex) { return getDiscoveredThrowingType().isAssignableFrom(ex.getClass()); } }
@Aspect 註解切面解析