zoukankan      html  css  js  c++  java
  • AOP源码解析:AspectJExpressionPointcutAdvisor类

      先看看 AspectJExpressionPointcutAdvisor 的类图

      再了解一下切点(Pointcut)表达式,它指定触发advice的方法,可以精确到返回参数,参数类型,方法名

    1 package concert;
    2 
    3 public interface Performance {
    4     void perform();
    5 }

     

      AspectJExpressionPointcutAdvisor 源码,官方文档解释说这是可以用于任何AspectJ切入点表达式的 Spring AOP Advisor。

     1 @SuppressWarnings("serial")
     2 public class AspectJExpressionPointcutAdvisor extends AbstractGenericPointcutAdvisor implements BeanFactoryAware {
     3 
     4     private final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); // AspectJ表达式切点匹配器
     5 
     6 
     7     public void setExpression(@Nullable String expression) {
     8         this.pointcut.setExpression(expression);
     9     }
    10 
    11     @Nullable
    12     public String getExpression() {
    13         return this.pointcut.getExpression();
    14     }
    15 
    16     public void setLocation(@Nullable String location) {
    17         this.pointcut.setLocation(location);
    18     }
    19 
    20     @Nullable
    21     public String getLocation() {
    22         return this.pointcut.getLocation();
    23     }
    24 
    25     public void setParameterNames(String... names) {
    26         this.pointcut.setParameterNames(names);
    27     }
    28 
    29     public void setParameterTypes(Class<?>... types) {
    30         this.pointcut.setParameterTypes(types);
    31     }
    32 
    33     @Override
    34     public void setBeanFactory(BeanFactory beanFactory) {
    35         this.pointcut.setBeanFactory(beanFactory);
    36     }
    37 
    38     @Override
    39     public Pointcut getPointcut() {
    40         return this.pointcut;
    41     }
    42 
    43 }

      再看看 AspectJExpressionPointcutAdvisor 的抽象父类 AbstractGenericPointcutAdvisor 的源码

     1 @SuppressWarnings("serial")
     2 public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {
     3 
     4     private Advice advice = EMPTY_ADVICE; // Advisor接口中定义的占位符
     5 
     6 
     7     /**
     8      * Specify the advice that this advisor should apply.
     9      */
    10     public void setAdvice(Advice advice) {
    11         this.advice = advice;
    12     }
    13 
    14     @Override
    15     public Advice getAdvice() {
    16         return this.advice;
    17     }
    18 
    19 
    20     @Override
    21     public String toString() {
    22         return getClass().getName() + ": advice [" + getAdvice() + "]";
    23     }
    24 
    25 }

      看完源码后,可以了解到一个 AspectJExpressionPointcutAdvisor 是用来处理对应 AspectJ 的 advice 和切点的,可以在代码中看见有advice的设置和获取、切点表达式的一些处理、设置切点的Bean工厂,还有获取该切点。该 AspectJExpressionPointcutAdvisor 创建了一个 AspectJExpressionPointcut,它们之间的关系是一对一的组合关系,如同字面意思,AspectJExpressionPointcut 与切点表达式有关。

      下面是 AspectJExpressionPointcut 的类图

       AspectJExpressionPointcut 的源码(过长折叠起来了)

      1 public class AspectJExpressionPointcut extends AbstractExpressionPointcut implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
      2     private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet();
      3     private static final Log logger;
      4     @Nullable
      5     private Class<?> pointcutDeclarationScope;
      6     private String[] pointcutParameterNames = new String[0];
      7     private Class<?>[] pointcutParameterTypes = new Class[0];
      8     @Nullable
      9     private BeanFactory beanFactory;
     10     @Nullable
     11     private transient ClassLoader pointcutClassLoader;
     12     @Nullable
     13     private transient PointcutExpression pointcutExpression;
     14     private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap(32);
     15 
     16     public AspectJExpressionPointcut() {
     17     }
     18 
     19     public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
     20         this.pointcutDeclarationScope = declarationScope;
     21         if (paramNames.length != paramTypes.length) {
     22             throw new IllegalStateException("Number of pointcut parameter names must match number of pointcut parameter types");
     23         } else {
     24             this.pointcutParameterNames = paramNames;
     25             this.pointcutParameterTypes = paramTypes;
     26         }
     27     }
     28 
     29     public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
     30         this.pointcutDeclarationScope = pointcutDeclarationScope;
     31     }
     32 
     33     public void setParameterNames(String... names) {
     34         this.pointcutParameterNames = names;
     35     }
     36 
     37     public void setParameterTypes(Class<?>... types) {
     38         this.pointcutParameterTypes = types;
     39     }
     40 
     41     public void setBeanFactory(BeanFactory beanFactory) {
     42         this.beanFactory = beanFactory;
     43     }
     44 
     45     public ClassFilter getClassFilter() {
     46         this.obtainPointcutExpression();
     47         return this;
     48     }
     49 
     50     public MethodMatcher getMethodMatcher() {
     51         this.obtainPointcutExpression();
     52         return this;
     53     }
     54 
     55     private PointcutExpression obtainPointcutExpression() {
     56         if (this.getExpression() == null) {
     57             throw new IllegalStateException("Must set property 'expression' before attempting to match");
     58         } else {
     59             if (this.pointcutExpression == null) {
     60                 this.pointcutClassLoader = this.determinePointcutClassLoader();
     61                 this.pointcutExpression = this.buildPointcutExpression(this.pointcutClassLoader);
     62             }
     63 
     64             return this.pointcutExpression;
     65         }
     66     }
     67 
     68     @Nullable
     69     private ClassLoader determinePointcutClassLoader() {
     70         if (this.beanFactory instanceof ConfigurableBeanFactory) {
     71             return ((ConfigurableBeanFactory)this.beanFactory).getBeanClassLoader();
     72         } else {
     73             return this.pointcutDeclarationScope != null ? this.pointcutDeclarationScope.getClassLoader() : ClassUtils.getDefaultClassLoader();
     74         }
     75     }
     76 
     77     private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
     78         PointcutParser parser = this.initializePointcutParser(classLoader);
     79         PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
     80 
     81         for(int i = 0; i < pointcutParameters.length; ++i) {
     82             pointcutParameters[i] = parser.createPointcutParameter(this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
     83         }
     84 
     85         return parser.parsePointcutExpression(this.replaceBooleanOperators(this.resolveExpression()), this.pointcutDeclarationScope, pointcutParameters);
     86     }
     87 
     88     private String resolveExpression() {
     89         String expression = this.getExpression();
     90         Assert.state(expression != null, "No expression set");
     91         return expression;
     92     }
     93 
     94     private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
     95         PointcutParser parser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader);
     96         parser.registerPointcutDesignatorHandler(new AspectJExpressionPointcut.BeanPointcutDesignatorHandler());
     97         return parser;
     98     }
     99 
    100     private String replaceBooleanOperators(String pcExpr) {
    101         String result = StringUtils.replace(pcExpr, " and ", " && ");
    102         result = StringUtils.replace(result, " or ", " || ");
    103         result = StringUtils.replace(result, " not ", " ! ");
    104         return result;
    105     }
    106 
    107     public PointcutExpression getPointcutExpression() {
    108         return this.obtainPointcutExpression();
    109     }
    110 
    111     public boolean matches(Class<?> targetClass) {
    112         PointcutExpression pointcutExpression = this.obtainPointcutExpression();
    113 
    114         try {
    115             try {
    116                 return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    117             } catch (ReflectionWorldException var5) {
    118                 logger.debug("PointcutExpression matching rejected target class - trying fallback expression", var5);
    119                 PointcutExpression fallbackExpression = this.getFallbackPointcutExpression(targetClass);
    120                 if (fallbackExpression != null) {
    121                     return fallbackExpression.couldMatchJoinPointsInType(targetClass);
    122                 }
    123             }
    124         } catch (Throwable var6) {
    125             logger.debug("PointcutExpression matching rejected target class", var6);
    126         }
    127 
    128         return false;
    129     }
    130 
    131     public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
    132         this.obtainPointcutExpression();
    133         ShadowMatch shadowMatch = this.getTargetShadowMatch(method, targetClass);
    134         if (shadowMatch.alwaysMatches()) {
    135             return true;
    136         } else if (shadowMatch.neverMatches()) {
    137             return false;
    138         } else if (hasIntroductions) {
    139             return true;
    140         } else {
    141             RuntimeTestWalker walker = this.getRuntimeTestWalker(shadowMatch);
    142             return !walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass);
    143         }
    144     }
    145 
    146     public boolean matches(Method method, Class<?> targetClass) {
    147         return this.matches(method, targetClass, false);
    148     }
    149 
    150     public boolean isRuntime() {
    151         return this.obtainPointcutExpression().mayNeedDynamicTest();
    152     }
    153 
    154     public boolean matches(Method method, Class<?> targetClass, Object... args) {
    155         this.obtainPointcutExpression();
    156         ShadowMatch shadowMatch = this.getTargetShadowMatch(method, targetClass);
    157         ProxyMethodInvocation pmi = null;
    158         Object targetObject = null;
    159         Object thisObject = null;
    160 
    161         try {
    162             MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    163             targetObject = mi.getThis();
    164             if (!(mi instanceof ProxyMethodInvocation)) {
    165                 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    166             }
    167 
    168             pmi = (ProxyMethodInvocation)mi;
    169             thisObject = pmi.getProxy();
    170         } catch (IllegalStateException var11) {
    171             if (logger.isDebugEnabled()) {
    172                 logger.debug("Could not access current invocation - matching with limited context: " + var11);
    173             }
    174         }
    175 
    176         try {
    177             JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
    178             if (pmi != null && thisObject != null) {
    179                 RuntimeTestWalker originalMethodResidueTest = this.getRuntimeTestWalker(this.getShadowMatch(method, method));
    180                 if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
    181                     return false;
    182                 }
    183 
    184                 if (joinPointMatch.matches()) {
    185                     this.bindParameters(pmi, joinPointMatch);
    186                 }
    187             }
    188 
    189             return joinPointMatch.matches();
    190         } catch (Throwable var10) {
    191             if (logger.isDebugEnabled()) {
    192                 logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) + " - falling back to non-match", var10);
    193             }
    194 
    195             return false;
    196         }
    197     }
    198 
    199     @Nullable
    200     protected String getCurrentProxiedBeanName() {
    201         return ProxyCreationContext.getCurrentProxiedBeanName();
    202     }
    203 
    204     @Nullable
    205     private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
    206         try {
    207             ClassLoader classLoader = targetClass.getClassLoader();
    208             if (classLoader != null && classLoader != this.pointcutClassLoader) {
    209                 return this.buildPointcutExpression(classLoader);
    210             }
    211         } catch (Throwable var3) {
    212             logger.debug("Failed to create fallback PointcutExpression", var3);
    213         }
    214 
    215         return null;
    216     }
    217 
    218     private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
    219         return shadowMatch instanceof AspectJExpressionPointcut.DefensiveShadowMatch ? new RuntimeTestWalker(((AspectJExpressionPointcut.DefensiveShadowMatch)shadowMatch).primary) : new RuntimeTestWalker(shadowMatch);
    220     }
    221 
    222     private void bindParameters(ProxyMethodInvocation invocation, JoinPointMatch jpm) {
    223         invocation.setUserAttribute(this.resolveExpression(), jpm);
    224     }
    225 
    226     private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
    227         Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
    228         if (targetMethod.getDeclaringClass().isInterface()) {
    229             Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
    230             if (ifcs.size() > 1) {
    231                 try {
    232                     Class<?> compositeInterface = ClassUtils.createCompositeInterface(ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
    233                     targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
    234                 } catch (IllegalArgumentException var6) {
    235                 }
    236             }
    237         }
    238 
    239         return this.getShadowMatch(targetMethod, method);
    240     }
    241 
    242     private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
    243         ShadowMatch shadowMatch = (ShadowMatch)this.shadowMatchCache.get(targetMethod);
    244         if (shadowMatch == null) {
    245             synchronized(this.shadowMatchCache) {
    246                 PointcutExpression fallbackExpression = null;
    247                 shadowMatch = (ShadowMatch)this.shadowMatchCache.get(targetMethod);
    248                 if (shadowMatch == null) {
    249                     Method methodToMatch = targetMethod;
    250 
    251                     try {
    252                         try {
    253                             shadowMatch = this.obtainPointcutExpression().matchesMethodExecution(methodToMatch);
    254                         } catch (ReflectionWorldException var13) {
    255                             try {
    256                                 fallbackExpression = this.getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
    257                                 if (fallbackExpression != null) {
    258                                     shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
    259                                 }
    260                             } catch (ReflectionWorldException var12) {
    261                                 fallbackExpression = null;
    262                             }
    263                         }
    264 
    265                         if (targetMethod != originalMethod && (shadowMatch == null || ((ShadowMatch)shadowMatch).neverMatches() && Proxy.isProxyClass(targetMethod.getDeclaringClass()))) {
    266                             methodToMatch = originalMethod;
    267 
    268                             try {
    269                                 shadowMatch = this.obtainPointcutExpression().matchesMethodExecution(methodToMatch);
    270                             } catch (ReflectionWorldException var11) {
    271                                 try {
    272                                     fallbackExpression = this.getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
    273                                     if (fallbackExpression != null) {
    274                                         shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
    275                                     }
    276                                 } catch (ReflectionWorldException var10) {
    277                                     fallbackExpression = null;
    278                                 }
    279                             }
    280                         }
    281                     } catch (Throwable var14) {
    282                         logger.debug("PointcutExpression matching rejected target method", var14);
    283                         fallbackExpression = null;
    284                     }
    285 
    286                     if (shadowMatch == null) {
    287                         shadowMatch = new ShadowMatchImpl(FuzzyBoolean.NO, (Test)null, (ExposedState)null, (PointcutParameter[])null);
    288                     } else if (((ShadowMatch)shadowMatch).maybeMatches() && fallbackExpression != null) {
    289                         shadowMatch = new AspectJExpressionPointcut.DefensiveShadowMatch((ShadowMatch)shadowMatch, fallbackExpression.matchesMethodExecution(methodToMatch));
    290                     }
    291 
    292                     this.shadowMatchCache.put(targetMethod, shadowMatch);
    293                 }
    294             }
    295         }
    296 
    297         return (ShadowMatch)shadowMatch;
    298     }
    299 
    300     public boolean equals(Object other) {
    301         if (this == other) {
    302             return true;
    303         } else if (!(other instanceof AspectJExpressionPointcut)) {
    304             return false;
    305         } else {
    306             AspectJExpressionPointcut otherPc = (AspectJExpressionPointcut)other;
    307             return ObjectUtils.nullSafeEquals(this.getExpression(), otherPc.getExpression()) && ObjectUtils.nullSafeEquals(this.pointcutDeclarationScope, otherPc.pointcutDeclarationScope) && ObjectUtils.nullSafeEquals(this.pointcutParameterNames, otherPc.pointcutParameterNames) && ObjectUtils.nullSafeEquals(this.pointcutParameterTypes, otherPc.pointcutParameterTypes);
    308         }
    309     }
    310 
    311     public int hashCode() {
    312         int hashCode = ObjectUtils.nullSafeHashCode(this.getExpression());
    313         hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutDeclarationScope);
    314         hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterNames);
    315         hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.pointcutParameterTypes);
    316         return hashCode;
    317     }
    318 
    319     public String toString() {
    320         StringBuilder sb = new StringBuilder();
    321         sb.append("AspectJExpressionPointcut: ");
    322         sb.append("(");
    323 
    324         for(int i = 0; i < this.pointcutParameterTypes.length; ++i) {
    325             sb.append(this.pointcutParameterTypes[i].getName());
    326             sb.append(" ");
    327             sb.append(this.pointcutParameterNames[i]);
    328             if (i + 1 < this.pointcutParameterTypes.length) {
    329                 sb.append(", ");
    330             }
    331         }
    332 
    333         sb.append(")");
    334         sb.append(" ");
    335         if (this.getExpression() != null) {
    336             sb.append(this.getExpression());
    337         } else {
    338             sb.append("<pointcut expression not set>");
    339         }
    340 
    341         return sb.toString();
    342     }
    343 
    344     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    345         ois.defaultReadObject();
    346         this.shadowMatchCache = new ConcurrentHashMap(32);
    347     }
    348 
    349     static {
    350         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    351         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
    352         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
    353         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
    354         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
    355         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
    356         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
    357         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
    358         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
    359         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
    360         logger = LogFactory.getLog(AspectJExpressionPointcut.class);
    361     }
    362 
    363     private static class DefensiveShadowMatch implements ShadowMatch {
    364         private final ShadowMatch primary;
    365         private final ShadowMatch other;
    366 
    367         public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
    368             this.primary = primary;
    369             this.other = other;
    370         }
    371 
    372         public boolean alwaysMatches() {
    373             return this.primary.alwaysMatches();
    374         }
    375 
    376         public boolean maybeMatches() {
    377             return this.primary.maybeMatches();
    378         }
    379 
    380         public boolean neverMatches() {
    381             return this.primary.neverMatches();
    382         }
    383 
    384         public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
    385             try {
    386                 return this.primary.matchesJoinPoint(thisObject, targetObject, args);
    387             } catch (ReflectionWorldException var5) {
    388                 return this.other.matchesJoinPoint(thisObject, targetObject, args);
    389             }
    390         }
    391 
    392         public void setMatchingContext(MatchingContext aMatchContext) {
    393             this.primary.setMatchingContext(aMatchContext);
    394             this.other.setMatchingContext(aMatchContext);
    395         }
    396     }
    397 
    398     private class BeanContextMatcher implements ContextBasedMatcher {
    399         private final NamePattern expressionPattern;
    400 
    401         public BeanContextMatcher(String expression) {
    402             this.expressionPattern = new NamePattern(expression);
    403         }
    404 
    405         /** @deprecated */
    406         @Deprecated
    407         public boolean couldMatchJoinPointsInType(Class someClass) {
    408             return this.contextMatch(someClass) == org.aspectj.weaver.tools.FuzzyBoolean.YES;
    409         }
    410 
    411         /** @deprecated */
    412         @Deprecated
    413         public boolean couldMatchJoinPointsInType(Class someClass, MatchingContext context) {
    414             return this.contextMatch(someClass) == org.aspectj.weaver.tools.FuzzyBoolean.YES;
    415         }
    416 
    417         public boolean matchesDynamically(MatchingContext context) {
    418             return true;
    419         }
    420 
    421         public org.aspectj.weaver.tools.FuzzyBoolean matchesStatically(MatchingContext context) {
    422             return this.contextMatch((Class)null);
    423         }
    424 
    425         public boolean mayNeedDynamicTest() {
    426             return false;
    427         }
    428 
    429         private org.aspectj.weaver.tools.FuzzyBoolean contextMatch(@Nullable Class<?> targetType) {
    430             String advisedBeanName = AspectJExpressionPointcut.this.getCurrentProxiedBeanName();
    431             if (advisedBeanName == null) {
    432                 return org.aspectj.weaver.tools.FuzzyBoolean.MAYBE;
    433             } else if (BeanFactoryUtils.isGeneratedBeanName(advisedBeanName)) {
    434                 return org.aspectj.weaver.tools.FuzzyBoolean.NO;
    435             } else if (targetType != null) {
    436                 boolean isFactory = FactoryBean.class.isAssignableFrom(targetType);
    437                 return org.aspectj.weaver.tools.FuzzyBoolean.fromBoolean(this.matchesBean(isFactory ? "&" + advisedBeanName : advisedBeanName));
    438             } else {
    439                 return org.aspectj.weaver.tools.FuzzyBoolean.fromBoolean(this.matchesBean(advisedBeanName) || this.matchesBean("&" + advisedBeanName));
    440             }
    441         }
    442 
    443         private boolean matchesBean(String advisedBeanName) {
    444             return BeanFactoryAnnotationUtils.isQualifierMatch(this.expressionPattern::matches, advisedBeanName, AspectJExpressionPointcut.this.beanFactory);
    445         }
    446     }
    447 
    448     private class BeanPointcutDesignatorHandler implements PointcutDesignatorHandler {
    449         private static final String BEAN_DESIGNATOR_NAME = "bean";
    450 
    451         private BeanPointcutDesignatorHandler() {
    452         }
    453 
    454         public String getDesignatorName() {
    455             return "bean";
    456         }
    457 
    458         public ContextBasedMatcher parse(String expression) {
    459             return AspectJExpressionPointcut.this.new BeanContextMatcher(expression);
    460         }
    461     }
    462 }
    View Code

      那下面就挑一部分代码来看,首先看静态代码块,里面的Set放的是切面表达式所支持的类型

     1     private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
     2 
     3     static {
     4         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
     5         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
     6         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
     7         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
     8         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
     9         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
    10         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
    11         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
    12         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
    13         SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
    14     }

      切点表达式类型:

    1. execution表达式:能在运行指定方法时拦截指定方法,用的最多。

    2. args:匹配参数,当执行的方法的参数是指定类型时生效。

    3. reference:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持

    4. this:Spring Aop是基于代理的,生成的bean也是一个代理对象,this就是这个代理对象,当这个对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。

    5. target:当被代理的对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。

    6. within:指定某些类型的全部方法执行,也可用来指定一个包。

    7. @target:当代理的目标对象上拥有指定的注解时生效。

    8. @args:当执行的方法参数类型上拥有指定的注解时生效。

    9. @within:与@target类似,看官方文档和网上的说法都是@within只需要目标对象的类或者父类上有指定的注解,则@within会生效,而@target则是必须是目标对象的类上有指定的注解。而根据笔者的测试这两者都是只要目标类或父类上有指定的注解即可。

    10. @annotation:当执行的方法上拥有指定的注解时生效。

      还有一种是Spring Aop扩展的类型 bean:当调用的方法是指定的bean的方法时生效。

      AspectJExpressionPointcut 的属性里面还有 PointcutExpression,org.aspectj.weaver.tools.PointcutExpression 中的类 ,经过一系列操作后由org.aspectj.weaver.tools.PointcutParser#parsePointcutExpression 从字符串表达式解析出来。

    1     @Nullable
    2     private transient PointcutExpression pointcutExpression;

      这个是ClassFilter 接口的实现方法,借助的 PointcutExpression#couldMatchJoinPointsInType 去匹配,其参数为一个代表被检测类Class的实例,如果切入点适合该类,则返回true

     1     @Override
     2     public boolean matches(Class<?> targetClass) {
     3         PointcutExpression pointcutExpression = obtainPointcutExpression();
     4         try {
     5             try {
     6                 return pointcutExpression.couldMatchJoinPointsInType(targetClass);
     7             }
     8             catch (ReflectionWorldException ex) {
     9                 logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
    10                 // Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
    11                 PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
    12                 if (fallbackExpression != null) {
    13                     return fallbackExpression.couldMatchJoinPointsInType(targetClass);
    14                 }
    15             }
    16         }
    17         catch (Throwable ex) {
    18             logger.debug("PointcutExpression matching rejected target class", ex);
    19         }
    20         return false;
    21     }

      下面这个是 MethodMatcher 接口中的 match 方法,作为Spring支持静态和动态的MethodMatcher。执行静态检查给定的方法是否匹配。

     1   @Override
     2     public boolean matches(Method method, Class<?> targetClass, Object... args) {
     3         obtainPointcutExpression();
     4         ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
     5 
     6         // Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
     7         // consistent with return of MethodInvocationProceedingJoinPoint
     8         ProxyMethodInvocation pmi = null;
     9         Object targetObject = null;
    10         Object thisObject = null;
    11         try {
    12             MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
    13             targetObject = mi.getThis();
    14             if (!(mi instanceof ProxyMethodInvocation)) {
    15                 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
    16             }
    17             pmi = (ProxyMethodInvocation) mi;
    18             thisObject = pmi.getProxy();
    19         }
    20         catch (IllegalStateException ex) {
    21             // No current invocation...
    22             if (logger.isDebugEnabled()) {
    23                 logger.debug("Could not access current invocation - matching with limited context: " + ex);
    24             }
    25         }
    26 
    27         try {
    28             JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
    29 
    30             /*
    31              * Do a final check to see if any this(TYPE) kind of residue match. For
    32              * this purpose, we use the original method's (proxy method's) shadow to
    33              * ensure that 'this' is correctly checked against. Without this check,
    34              * we get incorrect match on this(TYPE) where TYPE matches the target
    35              * type but not 'this' (as would be the case of JDK dynamic proxies).
    36              * <p>See SPR-2979 for the original bug.
    37              */
    38             if (pmi != null && thisObject != null) {  // there is a current invocation
    39                 RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(getShadowMatch(method, method));
    40                 if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
    41                     return false;
    42                 }
    43                 if (joinPointMatch.matches()) {
    44                     bindParameters(pmi, joinPointMatch);
    45                 }
    46             }
    47 
    48             return joinPointMatch.matches();
    49         }
    50         catch (Throwable ex) {
    51             if (logger.isDebugEnabled()) {
    52                 logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
    53                         " - falling back to non-match", ex);
    54             }
    55             return false;
    56         }
    57     }

      初始化一个基础的AspectJ切入点解析器,BeanPointcutDesignatorHandler 这个是Spring实现真正解析的内部类。

     1     /**
     2      * Initialize the underlying AspectJ pointcut parser.
     3      */
     4     private PointcutParser initializePointcutParser(@Nullable ClassLoader classLoader) {
     5         PointcutParser parser = PointcutParser
     6                 .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(
     7                         SUPPORTED_PRIMITIVES, classLoader);
     8         parser.registerPointcutDesignatorHandler(new BeanPointcutDesignatorHandler()); // 注册了一个BeanPointcutDesignatorHandler它是处理Spring自己支持的bean()的切点表达式的
     9         return parser;
    10     }

     总结

  • 相关阅读:
    Spark SQL saveMode 方式
    Spark SQL 读取json 里面的数据 ,jason 是 结构的数据
    SPark SQL 从 DB 读取数据方法和方式 scala
    SPark SQL 从 DB 读取数据方法和方式
    spark parquet 从hdfs 上读 和写 scala 版本
    spark parquet 从hdfs 上读 和写
    Spark streaming 采用直接读kafka 方法获取数据
    Topbeat --Metricbeat 在Windows上设置 centos kafka 打数据 成功
    php代码加入frameset后框架不显示
    【TP5笔记】TinkPHP5中引入资源文件
  • 原文地址:https://www.cnblogs.com/magic-sea/p/11735470.html
Copyright © 2011-2022 走看看