package com.markus.spring.aop.feature.blog.aspect;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;/*** @author: markus* @date: 2022/12/1 1:27 PM* @Description: 横切点表达式使用演示* @Blog: http://markuszhang.com* It's my honor to share what I've learned with you!*/
@Aspect
public class AspectJPointcutExpressionConfig {// 表示 方法的访问类型为public 任意返回类型 任意类型的specialReferenceDemo方法 参数可有可无@Pointcut(value = "execution(public * *.specialReferenceDemo(..))")public void executionPointcut() {}// 表示 匹配在com.markus.spring.aop.feature.blog子模块下的方法@Pointcut(value = "within(com.markus.spring.aop.feature.blog.domain.*)")public void withinPointcut() {}// 表示 匹配目标对象是com.markus.spring.aop.feature.blog.domain.DefaultPointcutDemo下的方法@Pointcut(value = "target(com.markus.spring.aop.feature.blog.domain.DefaultPointcutDemo)")public void targetPointcut() {}// 表示 匹配代理对象是com.markus.spring.aop.feature.blog.domain.PointcutDemo下的方法@Pointcut(value = "this(com.markus.spring.aop.feature.blog.domain.PointcutDemo)")public void thisPointcut(){}// 表示 匹配的方法中参数是ArgsDemo类型@Pointcut(value = "args(com.markus.spring.aop.feature.blog.domain.ArgsDemo)")public void argsPointcut(){}// 表示 匹配被@EchoInterface定义的对象下的方法// 它是动态匹配的,会为所有目标对象生成代理,所以慎用!例如AOP动态代理通过cglib实现,遇到被final修饰的bean对象,就会抛出异常@Pointcut(value = "@target(com.markus.aop.overview.annotation.EchoInterface)")public void atTargetPointcut(){}// 表示 匹配被@EchoInterface定义的对象下的方法// 与@target不同,它是属于静态匹配,描述为定义方法的对象被@EchoInterface注释@Pointcut(value = "@within(com.markus.aop.overview.annotation.EchoInterface)")public void atWithinPointcut(){}// 表示 匹配参数所属的类型被@EchoInterface注释的所有方法@Pointcut(value = "@args(com.markus.aop.overview.annotation.EchoInterface)")public void atArgsPointcut(){}// 表示 匹配被@EchoInterface注释的所有方法@Pointcut(value = "@annotation(com.markus.aop.overview.annotation.EchoInterface)")public void atAnnotationPointcut(){}@Before("executionPointcut()")public void executionPointcutBefore() {System.out.println("this is execution pointcut");}@Before("withinPointcut()")public void withinPointcutBefore() {System.out.println("this is within pointcut");}@Before("targetPointcut()")public void targetPointcutBefore(){System.out.println("this is target pointcut");}@Before("thisPointcut()")public void thisPointcutBefore(){System.out.println("this.is this pointcut");}@Before("argsPointcut())")public void argsPointcutBefore(){System.out.println("this is args pointcut");}@Before("atTargetPointcut()")public void atTargetPointcutBefore(){System.out.println("this is @target pointcut");}@Before("atWithinPointcut()")public void atWithinPointcutBefore(){System.out.println("this is @within pointcut");}@Before("atArgsPointcut()")public void atArgsPointcutBefore(){System.out.println("this is @args pointcut");}@Before("atAnnotationPointcut()")public void atAnnotationPointBefore(){System.out.println("this is @annotation pointcut");}
}
客户端
package com.markus.spring.aop.feature.blog;import com.markus.spring.aop.feature.blog.aspect.AspectJPointcutExpressionConfig;
import com.markus.spring.aop.feature.blog.domain.ArgsDemo;
import com.markus.spring.aop.feature.blog.domain.DefaultPointcutDemo;
import com.markus.spring.aop.feature.blog.domain.PointcutDemo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** @author: markus* @date: 2022/12/1 10:24 PM* @Description: 横切点表达式使用示例* @Blog: http://markuszhang.com* It's my honor to share what I've learned with you!*/
@EnableAspectJAutoProxy
public class AspectJPointcutExpressionDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(AspectJPointcutExpressionDemo.class, AspectJPointcutExpressionConfig.class);context.refresh();PointcutDemo pointcutDemo = context.getBean(PointcutDemo.class);ArgsDemo argsDemo = context.getBean(ArgsDemo.class);System.out.println("-----start-----");pointcutDemo.specialReferenceDemo(argsDemo);System.out.println("-----end-----");context.close();}@Beanpublic PointcutDemo pointcutDemo() {return new DefaultPointcutDemo();}@Beanpublic ArgsDemo argsDemo() {return new ArgsDemo("Hello World!");}
}
控制台
-----start-----
this is args pointcut
this is @annotation pointcut
this is @args pointcut
this is @target pointcut
this is @within pointcut
this is execution pointcut
this is target pointcut
this.is this pointcut
this is within pointcut
special reference demo content is
-----end-----Process finished with exit code 0
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 重点在这,通过@Import导入具体的注册器类,在该类下注册相应的BeanDefinition 这也是使用@EnableXXX注解驱动的大致逻辑
@Import(AspectJAutoProxyRegistrar.class)
// 值得注意的是该注解是要注释到配置类上的
public @interface EnableAspectJAutoProxy {/*** Indicate whether subclass-based (CGLIB) proxies are to be created as opposed* to standard Java interface-based proxies. The default is {@code false}.* 可以通过该字段标注Spring是采用jdk动态代理还是CGLIB字节码提升创建代理* true 使用CGLIB* false 使用标准方式*/boolean proxyTargetClass() default false;/*** Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.* Off by default, i.e. no guarantees that {@code AopContext} access will work.* @since 4.3.1* 标识代理是否被可以被当前线程本地缓存 AopContext#setCurrentProxy(proxy)*/boolean exposeProxy() default false;}
AspectJAutoProxyRegistrar
// 定义AspectJAutoProxyRegistrar 实现ImportBeanDefinitionRegistrar的registerBeanDefinitions方法,在加载BeanDefinition的时候注册自定义的BeanDefinition
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {/*** Register, escalate, and configure the AspectJ auto proxy creator based on the value* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing* {@code @Configuration} class.*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 向BeanDefinitionRegistry中注册AnnotationAwareAspectJAutoProxyCreatorAopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {// @EnableAspectJAutoProxy中的proxyTargetClass配置if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}// @EnableAspectJAutoProxy中的exposeProxy配置if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}}
@Override
// 重写AbstractAdvisorAutoProxyCreator中的findCandidateAdvisors方法
protected List findCandidateAdvisors() {// Add all the Spring advisors found according to superclass rules.// 父类提供的查询规则List advisors = super.findCandidateAdvisors();// Build Advisors for all AspectJ aspects in the bean factory.// 基于AspectJ注解,搜寻其切面下的Advice方法 并转换为Advisorif (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;
}
BeanFactoryAspectJAdvisorBuilderAdapter
public List buildAspectJAdvisors() {// <1> 找到IoC容所有的Aspect Bean名称List aspectNames = this.aspectBeanNames;if (aspectNames == null) {synchronized (this) {aspectNames = this.aspectBeanNames;if (aspectNames == null) {List advisors = new ArrayList<>();aspectNames = new ArrayList<>();// 也是通过依赖查找,是查找到所有的Bean名称集合String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {// 遍历所有的Bean名称,排除一些不符合条件的Beanif (!isEligibleBean(beanName)) {continue;}// We must be careful not to instantiate beans eagerly as in this case they// would be cached by the Spring container but would not have been weaved.// 这里作者解释了,为什么采用类型查找,而不是实例查找Class> beanType = this.beanFactory.getType(beanName);if (beanType == null) {continue;}// 通过AspectJAdvisorFactory判断当前类是否被@Aspect注释if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 获取该切面下的所有advisorList classAdvisors = this.advisorFactory.getAdvisors(factory);if (this.beanFactory.isSingleton(beanName)) {// 缓存切面下对应的advisorthis.advisorsCache.put(beanName, classAdvisors);}else {// 缓存切面下对应的实例工厂this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}else {// Per target or per this.if (this.beanFactory.isSingleton(beanName)) {throw new IllegalArgumentException("Bean with name '" + beanName +"' is a singleton, but aspect instantiation model is not singleton");}// 原型模式MetadataAwareAspectInstanceFactory factory =new PrototypeAspectInstanceFactory(this.beanFactory, beanName);this.aspectFactoryCache.put(beanName, factory);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}}this.aspectBeanNames = aspectNames;return advisors;}}}if (aspectNames.isEmpty()) {return Collections.emptyList();}// 利用缓存进行性能优化List advisors = new ArrayList<>();for (String aspectName : aspectNames) {List cachedAdvisors = this.advisorsCache.get(aspectName);if (cachedAdvisors != null) {advisors.addAll(cachedAdvisors);}else {MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}return advisors;
}
ReflectiveAspectJAdvisorFactory
@Override
// 通过AspectInstanceFactory获取Advisor集合
public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();// <1> 校验切面类validate(aspectClass);// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator// so that it will only instantiate once.// 装饰者模式-增强AspectJInstanceFactory功能,使得该切面只被实例化一次MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);List advisors = new ArrayList<>();// <2> 查找该类下所有的非Pointcut注解的方法for (Method method : getAdvisorMethods(aspectClass)) {// <3> 获取AdvisorAdvisor 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.// <4> 如果切面是延迟初始化特性,则在执行链最开始增加一个advisor,直到目标方法被调用时再被初始化if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// Find introduction fields.// <5> 接口增强特性-@DeclareParents字段为拦截器增强动作for (Field field : aspectClass.getDeclaredFields()) {Advisor advisor = getDeclareParentsAdvisor(field);if (advisor != null) {advisors.add(advisor);}}// <6> 返回所有的Advisor数据return advisors;
}
private List getAdvisorMethods(Class> aspectClass) {final List methods = new ArrayList<>();// 通过反射 查找Advisor目标方法,通过排除Pointcut注解方式实现ReflectionUtils.doWithMethods(aspectClass, method -> {// Exclude pointcutsif (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {methods.add(method);}}, ReflectionUtils.USER_DECLARED_METHODS);methods.sort(METHOD_COMPARATOR);return methods;
}
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());// 根据候选Advice方法的AspectJ注解 构建AspectJExpressionPointcutAspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}// 将方法包装为Advisor并返回return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
@Override
@Nullable
// 调用目标方法的回调
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;// 获取代理配置的目标源TargetSource targetSource = this.advised.targetSource;Object target = null;try {// 没有定义equal方法并且当前调用的还是equals方法,则调用代理类实现的equals方法if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}// 和equals方法一样的情况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);}// Advise接口上的方法调用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;// 1. 是否曝光代理类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.// 获取目标对象target = targetSource.getTarget();Class> targetClass = (target != null ? target.getClass() : null);// Get the interception chain for this method.// 获取该方法的拦截器执行链,这里是将advisor适配为MethodInterceptor并且返回和方法匹配的MethodInterceptor执行链。List
AdvisedSupport
public List
DefaultAdvisorChainFactory
public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {@Overridepublic List 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.// 获取Advisor适配器注册工厂AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();// 获取配置中的AdvisorAdvisor[] advisors = config.getAdvisors();List 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.// 下面这一大串则是将配置中Advisor与当前方法进行匹配,如果匹配的上则加入到执行链中,否则跳过PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) 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);}if (match) {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) {// 需要处理接口增强AdvisorIntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}else {// 其他类型的AdvisorInterceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;}/*** Determine whether the Advisors contain matching introductions.*/private static boolean hasMatchingIntroductions(Advisor[] advisors, Class> actualClass) {for (Advisor advisor : advisors) {if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (ia.getClassFilter().matches(actualClass)) {return true;}}}return false;}}
ReflectiveMethoInvocation
@Override
@Nullable
public Object proceed() throws Throwable {// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {// 执行目标连接点return invokeJoinpoint();}Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;Class> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}
}