1. AOP介绍
1.1 AOP简介
在软件开发中,有些行为对于很多地方都是通用的;例如我们需要记录用户所有的操作日志,使用面向对象编程(OOP)的话,需要在每个方法里面去引用这种公共的行为,这样程序中就会产生大量的重复代码。
对于日志、安全、事物等分布于应用中多处而又相同的功能,是需要与应用的业务逻辑相分离的,所以就有了面向切面编程(AOP);在AOP中,关注的方向是横向的,不同于OOP的纵向,所以这些分布于应用中多处的功能被称为横切关注点。
- AOP使用场景:
- 记录用户操作日志;
- 记录方法执行时间;
- 接口鉴权;
- 事务管理;
1.2 AOP术语
用一段代码示例来进行解释说明:
@Aspect
public class AopDemo {
@Pointcut("execution(* *.test(..))")
public void test() {
}
@Before("test()")
public void beforeTest() {
System.out.println("beforeTest");
}
@After("test()")
public void afterTest() {
System.out.println("afterTest");
}
@Around("test()")
public Object aroundTest(ProceedingJoinPoint point) {
System.out.println("before1");
Object object = null;
try {
object = point.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("after1");
return object;
}
}
- 通知(Advice):
通知定义了切面要实现什么功能,以及什么时候执行这个功能(方法调用前/调用后/环绕?);其实在源码中Advice被称为增强,我也认为增强这个叫法更适合它所实现的功能(因为它是对所要执行的东西做了一些增强的操作(例如上面的打印、记录操作日志等));- 5种增强类型:
- Before:在方法被调用前,调用增强;(如上面的 @Before(“test()”))
- After:在方法调用完成之后,调用增强(无论方法是否执行成功);(如上面的 @After(“test()”))
- After-returning:在方法成功执行之后,调用增强;
- After-throwing:在方法抛出异常后,调用增强;
- Around:这个增强包裹了要执行的方法,可以在这个方法调用之前和调用之后,执行自定义的增强行为;(如上面的 @Around(“test()”))
- 5种增强类型:
- 切点(Poincut):
上面的增强定义了 “什么功能”和“什么时候”,这里的切点就是定义“什么地方”,即在什么地方去执行增强。
我们通常使用明确的类(注解)或者方法来指定切点,或者是利用正则表达式定义匹配的类和方法来指定切点。(如上面的 @Pointcut(“execution(* *.test(…))”) ,就是定义了这个test()方法就是切点) - 连接点(JoinPoint):
连接点是在应用中能够插入切面的一个点,切面代码可以利用这些点插入到应用的正常流程之中,进行增强;(如应用中所有能够满足上面切点定义的表达式条件的 test()方法 都是连接点) - 切面(Aspect):
切面是切点和增强的结合,即“什么时候”在“什么地方”完成“什么功能”;(如上面的标注了@Aspect注解的 AopDemo类,就是一个切面) - 引介(Introduction):
引介在不更改源代码的情况,给一个现有类增加属性、方法,以及让现有类实现其它接口或指定其它父类等,从而改变类的静态结构; - 织入(Weaving):
织入是将切面应用到目标对象来创建新的代理对象的过程;切面在指定的连接点被织入到目标对象中。
在目标对象的生命周期里有多个时机可以进行织入:- 编译期:切面在目标类编译时就被织入;这种方式需要特殊的编译器,AspectJ的织入编译器就是以这种方式织入切面的;
- 类加载器:切面在目标类加载到JVM时被织入;这种方式需要特殊的类加载器,它可以在目标类被引入之前就修改目标类的字节码。AspectJ5的LTW(load-time weaving)就是以这种方式织入切面;(又叫静态AOP)
- 运行期:切面在应用运行的某个时刻被织入;一般情况下,织入切面时,Spring会为目标对象动态地创建一个代理对象;Spring AOP就是以这种方式织入切面的;(又叫动态AOP)
1.2.1 定义切点
在Spring中,需要使用AspectJ的切点表达式语言来定义切点。
AspectJ指示器 | 描述 |
---|---|
execution | 用于匹配是连接点的执行方法 |
arg() | 限制连接点匹配参数为 指定类型的执行方法 |
@arg() | 限制连接点匹配参数为 由指定注解标注的执行方法 |
this() | 限制连接点匹配AOP代理的Bean引用为 指定类型的类 |
target() | 限制连接点匹配目标对象为指定类型的类 |
@target() | 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解 |
within() | 限制连接点匹配 指定的类型 |
@within() | 限制连接点匹配 指定注解所标注的类型(使用Spring AOP时,方法定义在由指定的注解所标注的类中)(对象级别) |
@annotation | 限制匹配带有指定注解的连接点(方法级别) |
1.2.2 编写切点
示例1:
- execution指示器定义了一个切点,这个切点是Instrument类的play()方法;
- 表达式由 * 开头,表示任意方法返回值;
- 以 com.xxx.xxx.play() 指定了方法全限定名;也可以 *.play() 直接表示任意包和类下面的play()方法都满足;
- 使用 (…), 表示方法参数;
示例2:
- 使用within()表达式限制方法的执行范围在com.xxx.xxx.springidol包下;
- 使用 && 操作符把 execution 和 within() 指示器连接在一起形成and关系(即切点必须匹配所有的操作指示器);
- 类似地,可以使用 || 操作符来标识 or关系,使用 ! 操作符来标识 非关系;
示例3:(bean()指示器的使用)
execution(* com.springinaction.springidol.Instrument.play()) and bean(eddie)
- 使用 bean()指示器,限制了必须是bean的Id为 eddie的bean执行play() 方法时才满足条件;
execution(* com.springinaction.springidol.Instrument.play()) and !bean(eddie)
- 使用了 bean()指示器和 ! 关系符,限制了必须是bean的Id不为 eddie的地方执行play() 方法时才满足条件;
2. AOP源码实现
2.1 AOP简单使用示例
- 创建一个用于被增强的bean:
在实际应用中,这个bean可能是满足业务需求的核心逻辑,test方法可能用于实现某个核心业务;如果我们需要在这种类似的test方法执行前后加入日志来跟踪调试,直接修改的源码的话会导致大量的重复代码,并且不太优雅;
所以我们使用AOP来实现:public class TestBean { public void test() { System.out.println("---------test---------"); } }
- 创建切面Advisor:
Spring摒弃了以前原始的繁杂配置方式而采用了@AspectJ注解来使用AOP;
我们要实现的就是在所有的test()方法 执行之前打印 beforeTest,执行之后打印afterTest,同时又使用环绕的方式在所有test()方法执行前后再次 分别打印before1和 after1(即可以把这些打印操作看做我们实际应用中的比如记录日志等操作):@Aspect public class AopDemo { @Pointcut("execution(* *.test(..))") public void test() { } @Before("test()") public void beforeTest() { System.out.println("beforeTest"); } @After("test()") public void afterTest() { System.out.println("afterTest"); } @Around("test()") public Object aroundTest(ProceedingJoinPoint point) { System.out.println("before1"); Object object = null; try { object = point.proceed(); } catch (Throwable t) { t.printStackTrace(); } System.out.println("after1"); return object; } }
- 创建配置文件:
需要使用 <aop:aspectj-autoproxy/> 来开启AOP功能spring-aspectj-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy/> <bean id="test" class="org.bgy.spring.study.spring.aop.simple.demo.TestBean"/> <bean id="aopDemo" class="org.bgy.spring.study.spring.aop.simple.demo.AopDemo"/> </beans>
- 创建测试类:
可以看到,除了打印的 ---------test--------- 之外,在它打印的前后,还对我们的增强操作进行了打印;这样就实现了对所有类的test()方法进行了增强,使切面功能可以独立于核心逻辑之外,方便程序的扩展和解耦。public class AopTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-aspectj-context.xml"); TestBean testBean = applicationContext.getBean("test", TestBean.class); testBean.test(); } } // Output: before1 beforeTest ---------test--------- after1 afterTest
2.2 AOP实现
2.2.1 AOP自定义标签
上面写到了开启Spring AOP的方法是使用配置 <aop:aspectj-autoproxy/>
,这是一个自定义注解;我们在Spring——3. 自定义标签的解析中讲过,如果声明了自定义注解,就一定会在程序中注册对应的处理器和解析器。
我们使用 aspectj-autoproxy 进行全局搜索,搜到了在 AopNamespaceHandler类中存在这样一段代码:
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
所以,AopNamespaceHandler类是这个自定义注解的处理器,里面 aspectj-autoproxy对应的 AspectJAutoProxyBeanDefinitionParser类是自定义注解的解析器。
按照以前讲的自定义注解的解析的内容我们可以知道,在解析配置文件的时候,一旦遇到 <aop:aspectj-autoproxy/>注解,就会使用解析器 AspectJAutoProxyBeanDefinitionParser 进行解析。
2.2.1.1 注册 AnnotationAwareAspectJAutoProxyCreator
所有的解析器都是对 BeanDefinitionParser接口的统一实现,所以入口都是从parse()方法开始的,AspectJAutoProxyBeanDefinitionParser的parse():
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册 AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 注解中子类的处理
extendBeanDefinition(element, parserContext);
return null;
}
其中的关键逻辑在于 registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册或升级 AutoProxyCreator定义beanName为
// org.springframework.aop.config.internalAutoProxyCreator 的BeanDefinition
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 对于proxy-target-class以及 expose-proxy属性的处理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注册组件并通知,便于监听器做进一步的处理;
// 其中BeanDefinition的 className为 AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
这个方法中主要完成了3件事情:
- 注册或者升级(替换) AnnotationAwareAspectJAutoProxyCreator:
Spring中对于AOP的实现,基本都是靠 AnnotationAwareAspectJAutoProxyCreator完成的,它可以根据 @Point注解定义的切点来自动代理相匹配的bean。
为了配置简便,Spring使用了自定义配置来帮助我们自定义注册 AnnotationAwareAspectJAutoProxyCreator,注册过程就是在这里实现的:public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { // 注册或者升级 AnnotationAwareAspectJAutoProxyCreator // 实现了自动注册 AnnotationAwareAspectJAutoProxyCreator 类的功能 return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }
private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 如果存在了自动代理创建器; if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 且自动代理创建器和现在的不同 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { // 就需要根据优先级来判断到底需要使用哪个 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { // 改变bean最重要的就是改变bean所对应的className属性 apcDefinition.setBeanClassName(cls.getName()); } } // 如果跟现在相同,直接返回 return null; } // 如果不存在,或者存在了不同的创建器,都需要重新进行注册 BeanDefinition; // 使用 AnnotationAwareAspectJAutoProxyCreator 来创建一个 BeanDefinition,并注册到 internalAutoProxyCreator 中 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
- 处理 proxy-target-class以及 expose-proxy属性
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) { if (sourceElement != null) { // 对于 proxy-target-class属性的处理(proxy-target-class属性:用于指定CGLIB的代理) boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); if (proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 对于 expose-proxy属性的处理(expose-proxy属性:解决目标对象内部的自我调用无法实现切面的增强) boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); if (exposeProxy) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }
- proxy-target-class:
- Spring AOP使用 JDK动态代理和CGLIB代理来为目标对象创建代理(建议尽量使用JDK动态代理);
- JDK动态代理和CGLIB代理的区别:
- JDK动态代理:目标对象必须实现了一个接口,通过在运行期间创建一个接口的实现类,来完成对目标对象的代理;
- CGLIB代理:目标对象没有实现任何接口,通过在运行期间创建一个针对目标类的扩展的子类,来实现对目标对象的代理(因为是子类继承父类并覆盖其中的方法,所以该类或者方法最好不要声明为final);
- 如果希望强制使用CGLIB代理(即使目标对象实现了接口,你希望代理目标对象所有方法,而不只是接口方法),可以使用 proxy-target-class属性进行设置:
<aop:aspectj-autoproxy proxy-target-class="true"/>
- expose-proxy:
- 有时候目标对象内部的自我调用将无法实现切面中的增强,例如:
此处的this执行目标对象,所以调用this.b()将不会执行b事务切面,即不会执行事务的增强;为了解决这个问题,我们需要设置:public interface AService { public void a(); public void b(); } @Service public class AServiceImpl1 implements AService { @Transactional(propagation = Propagation.REQUIRED) public void a(){ this.b(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void b(){ } }
<aop:aspectj-autoproxy expose-proxy="true"/>
然后将上面的this.b()调用,修改为代理对象的调用:((AService)AopContext.currentProxy()).b(),这样才能完成对a(),b()的同时增强。
- 有时候目标对象内部的自我调用将无法实现切面中的增强,例如:
- proxy-target-class:
- 注册 AnnotationAwareAspectJAutoProxyCreator这个bean,并通知监听器便于做进一步的处理;
2.2.2 创建AOP代理
上面讲到了通过自定义配置来完成了对 AnnotationAwareAspectJAutoProxyCreator的bean的自动注册,下面就来看看这个类到底是怎么实现了AOP的。
先来看看AnnotationAwareAspectJAutoProxyCreator 类的层次结构:
可以看到,AnnotationAwareAspectJAutoProxyCreator 类实现了InstantiationAwareBeanPostProcessor接口,来看看InstantiationAwareBeanPostProcessor接口的源码:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
}
InstantiationAwareBeanPostProcessor接口又实现了 BeanPostProcessor接口:
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
所以对于 InstantiationAwareBeanPostProcessor 来说除了具有父接口以外的两个方法还自己定义了四个方法,这6个方法的作用分别是:
方法 | 描述 |
---|---|
postProcessBeforeInstantiation | 最先执行的方法;在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走 |
postProcessAfterInstantiation | 在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true,postProcessPropertyValues就会被执行 |
postProcessProperties | 调用时机为postProcessAfterInstantiation执行之后并返回true, 返回的PropertyValues将作用于给定bean属性赋值 |
postProcessPropertyValues | 已经被标注@Deprecated,将会被postProcessProperties取代 |
postProcessBeforeInitialization | BeanPostProcessor接口中的方法;在Bean的自定义初始化方法之前执行 |
postProcessAfterInitialization | BeanPostProcessor接口中的方法;在Bean的自定义初始化方法执行完成之后执行 |
回到代码,再来看看AnnotationAwareAspectJAutoProxyCreator的父类 AbstractAutoProxyCreator中的代码,可以看到这个类中主要重写了 postProcessBeforeInstantiation() 和 postProcessAfterInitialization()方法,所以我们对于AOP的分析,应该由这两个方法入手。
根据上面写到的执行顺序,应该先执行postProcessBeforeInstantiation()方法,再执行postProcessAfterInitialization()方法。
2.2.2.1 执行postProcessBeforeInstantiation()方法
AbstractAutoProxyCreator.java
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// shouldSkip:在这里就会首先去加载一次增强器
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
AspectJAwareAdvisorAutoProxyCreator.java
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// 获取增强器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
可以看到,在执行shouldSkip()方法的时候,就会首先去加载一次切面中的所有增强器,然后判断是否需要跳过。
2.2.2.1.1 加载所有增强器
接着上面看,由于我们分析的是使用注解完成的AOP,所以对于 findCandidateAdvisors()方法的实现是由 AnnotationAwareAspectJAutoProxyCreator类完成的,跟下去:
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持;所以这里保留了父类方法: 先加载配置文件中定义的增强
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 并添加了:获取注解定义的增强
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
我们这里使用的是注解,所以应该是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来完成对于增强器的获取:
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 获取所有的beanName(包括系统自己注入的bean)
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!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.
// 获取bean对应的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 判断这个bean是否被@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);
// 增强器的获取(获取标记AspectJ注解中的增强方法)
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 把获取到的增强器加入缓存中
this.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<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> 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;
}
这一段看起来很多的代码,其实思路非常清晰,总结下来就是实现了以下几个功能:
- 从 this.aspectBeanNames中获取aspectNames;如果没有获取到说明是第一次处理,需要进行advisors的提取;如果获取到了说明已经处理过了,直接从缓存中获取advisors;
- aspectNames没有获取到时,进行advisors的提取;先获取所有在BeanFactory中注册的bean的beanNames;
- 遍历所有的beanNames,找出声明了@Aspect注解的bean,先把这些bean加入到aspectNames,再并对这些bean进行增强器的提取;
- 将提取到的增强器都加入到 this.advisorsCache缓存中;
- 将aspectNames赋值给this.aspectBeanNames,便于下次处理时进行判断;
- aspectNames获取到时,不再进行处理,直接从 this.advisorsCache缓存中获取advisors;
在上面实现的功能中,最重要也最复杂的就是对于bean进行增强器的提取,并把这一功能委托给了 getAdvisors()方法进行实现:
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
再看上面一行代码:
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
这行代码中创建了一个MetadataAwareAspectInstanceFactory类型的factory对象:
public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
AspectMetadata getAspectMetadata();
@Nullable
Object getAspectCreationMutex();
}
通过这个factory我们可以获取到AspectMetadata对象:
public class AspectMetadata implements Serializable {
private final String aspectName;
private final Class<?> aspectClass;
private transient AjType<?> ajType;
private final Pointcut perClausePointcut;
.......
}
所以是这个对象中封装了被@Aspect注解标注的bean的 name,class,ajType等…
回到getAdvisors()方法:
ReflectiveAspectJAdvisorFactory.java
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取标记为 AspectJ 的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 获取增强方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 获取增强器,包含了 切点,切面方法名称,增强的类名...等等
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
// 判断如果配置了增强 延迟初始化
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
// 就需要在首位加入 同步实例化增强器
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 获取 DeclaredParents 注解(DeclaredParents 主要用于 引介增强的注解形式 的实现,实现方式与普通增强很类似
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
- 这里首先使用上面的factory获取到声明了@Aspect注解的bean的class和name,然后根据class通过反射获取到bean里面的所有方法,再遍历这些方法配合aspectName完成增强器的获取。
- 然后如果在配置中将增强配置成延迟初始化,需要在首位加入同步实例化增强器以保证增强使用之前的实例化。
- 最后是对DeclaredParents注解的获取。
2.2.2.1.1.1 增强器的获取
增强器的获取逻辑通过 getAdvisor()方法实现,包括了对切点信息的获取和根据切点信息生成增强器:
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 切点信息的获取(即指定注解的表达式信息的获取,如 @Around("test()") )
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 根据切点信息生成增强器,所有的增强器都由 Advisor 的实现类 InstantiationModelAwarePointcutAdvisorImpl 进行封装
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
-
切点信息的获取,即指定注解的表达式信息的获取,如 @Around(“test()”):
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { // 获取方法上的注解(示例:@org.aspectj.lang.annotation.Around(argNames=, value=test()) ) AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // 使用 AspectJExpressionPointcut 实例封装获取的信息 AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); // 提取注解中的表达式(示例:@Around("test()") 中的 test() 、@Pointcut("execution(* *.test(..))") 中的 execution(* *.test(..))) ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (this.beanFactory != null) { ajexp.setBeanFactory(this.beanFactory); } return ajexp; } protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) { // 根据这些注解类型去跟方法进行匹配来获取(只获取这些方法的注解) // (Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class) for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) { AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz); if (foundAnnotation != null) { return foundAnnotation; } } return null; } private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) { // 获取指定方法上的注解,并使用 AspectJAnnotation封装;method要和toLookFor匹配 A result = AnnotationUtils.findAnnotation(method, toLookFor); if (result != null) { return new AspectJAnnotation<>(result); } else { return null; } } private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
首先是获取方法上声明的注解,注解的获取是根据常量 ASPECTJ_ANNOTATION_CLASSES 定义的类型来匹配获取的(即只能获取Pointcut、Around…等注解)。
然后使用 AspectJExpressionPointcut类型的ajexp对象 封装了切点信息,再把获取到的注解中定义的表达式设置到 ajexp对象的 expression属性中。 -
根据切点信息生成增强;所有的增强器都由 Advisor的实现类 InstantiationModelAwarePointcutAdvisorImpl统一封装:
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
InstantiationModelAwarePointcutAdvisorImpl.java
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { // 示例: // test() this.declaredPointcut = declaredPointcut; // class org.bgy.spring.study.spring.aop.simple.demo.AspectJDemo this.declaringClass = aspectJAdviceMethod.getDeclaringClass(); // beforeTest this.methodName = aspectJAdviceMethod.getName(); this.parameterTypes = aspectJAdviceMethod.getParameterTypes(); // public void org.bgy.spring.study.spring.aop.simple.demo.AspectJDemo.beforeTest() this.aspectJAdviceMethod = aspectJAdviceMethod; this.aspectJAdvisorFactory = aspectJAdvisorFactory; this.aspectInstanceFactory = aspectInstanceFactory; // 1 (Around: 0; Before: 1; After: 2) this.declarationOrder = declarationOrder; // aspectName this.aspectName = aspectName; if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { // Static part of the pointcut is a lazy type. Pointcut preInstantiationPointcut = Pointcuts.union( aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut); // Make it dynamic: must mutate from pre-instantiation to post-instantiation state. // If it's not a dynamic pointcut, it may be optimized out // by the Spring AOP infrastructure after the first evaluation. this.pointcut = new PerTargetInstantiationModelPointcut( this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory); this.lazy = true; } else { // A singleton aspect. this.pointcut = this.declaredPointcut; this.lazy = false; // 根据注解中的信息初始化对应的增强器(@Before、@After标签的不同,会使增强器增强的位置不同) this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); } }
这个封装(也就是实例化对象)的过程,就是把切点的信息简单的赋值给新对象的各个属性;在简单属性赋值完成之后,还需要完成对于增强器的初始化。
因为不同类型的增强器实现的逻辑是不一样的,例如 @Before(“test()”)和@After(“test()”)两种增强器增强的位置就不相同,所以需要不同的增强器实现类来完成不同的逻辑; 这个不同增强器实现类的初始化过程,就是在instantiateAdvice()方法中完成的。
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) { Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); return (advice != null ? advice : EMPTY_ADVICE); }
ReflectiveAspectJAdvisorFactory.java
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { // 获取标注了 @Aspect 注解的类 Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); // 获取 candidateAdviceMethod 方法上面标注的 切面注解 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 afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); 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); } // Now to configure the advice... springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }
在这里,会首先去获取方法上面标注的Aspect相关的注解,然后根据注解的不同类型来生成不同的增强器;例如 AtAround会对应生成 AspectJAroundAdvice、AtBefore会对应生成 AspectJMethodBeforeAdvice…等。
这里各种不同类型的增强器里面具体的执行方法(也就是invoke()方法),我们等到后面在讲代理对象调用时的方法调用顺序的时候一起来讲。
下面接着看剩下的两个步骤。
2.2.2.1.1.2 增加同步实例化增强器
如果获取到的增强器不为空,并且配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器:
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
// 就需要在首位加入 同步实例化增强器
advisors.add(0, instantiationAdvisor);
}
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor {
public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) {
super(aif.getAspectMetadata().getPerClausePointcut(), (MethodBeforeAdvice)
// 目标方法前调用,类似@Before
// 简单初始化aspect
(method, args, target) -> aif.getAspectInstance());
}
}
2.2.2.1.1.3 获取 DeclaredParents 注解
DeclaredParents 主要用于引介增强的注解形式的实现,它的实现方式也与普通增强很类似,只是使用了 DeclareParentsAdvisor 对功能进行封装:
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
// 最后再添加到 advisors中
advisors.add(advisor);
}
}
private Advisor getDeclareParentsAdvisor(Field introductionField) {
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
if (declareParents == null) {
// Not an introduction field
return null;
}
if (DeclareParents.class == declareParents.defaultImpl()) {
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
}
// 使用 DeclareParentsAdvisor 进行封装
return new DeclareParentsAdvisor(
introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}
到这里,已经完成了对于标注了@Aspect的bean中的所有增强器的获取。
2.2.2.1.2 判断 shouldSkip
return super.shouldSkip(beanClass, beanName);
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
return AutoProxyUtils.isOriginalInstance(beanName, beanClass);
}
static boolean isOriginalInstance(String beanName, Class<?> beanClass) {
if (!StringUtils.hasLength(beanName) || beanName.length() !=
beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {
return false;
}
return (beanName.startsWith(beanClass.getName()) &&
beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
}
2.2.2.2 执行postProcessAfterInitialization()方法
AbstractAutoProxyCreator.java
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果需要被代理,则需要封装指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已经被处理过了,不处理
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果不需要增强,不处理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// bean是否是基础设施类,基础设施类不应被代理;配置了需要跳过的bean也不需要代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 获取增强器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果获取到了,即需要代理,则针对增强器创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
这里也会先去获取一下增强器,如果获取到了,才会创建代理;所以我们总结一下,创建代理主要包含了两个步骤:
- 先获取增强器;
- 根据获取到的增强器进行代理;
2.2.2.2.1 获取所有的增强器
AbstractAutoProxyCreator.java
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
AbstractAdvisorAutoProxyCreator.java
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有的增强
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 获取所有增强中适用于当前bean的增强
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
可以看到,这里对于增强器的获取分成了两个步骤:
-
获取所有的增强器:
List<Advisor> candidateAdvisors = findCandidateAdvisors();
可以看到这里对于增强器的获取还是使用的 findCandidateAdvisors()方法,所以从上面2.2.2.1.1 加载所有增强器小节的分析来看,我们已经获取过了所有的增强器,所以这里的获取就直接从缓存中进行获取了:
// 从缓存中获取 List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } }
-
寻找匹配的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
在获取完所有的增强器之后,还存在一个问题:对于所有的增强器来讲,并不一定都适用于当前的bean,也就是需要满足上面1.2.1 定义切点小节中讲到的一些表达式中限制连接点匹配的指定类型,指定bean等条件。
所以还需要挑选出能够满足我们配置的通配符的bean:
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { // 过滤出满足当前bean的增强器 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } }
AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { // 如果传入的Advisor集合为空的话,直接返回这个空集合 if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { // 首先处理引介增强(引介增强:可以为目标类通过AOP的方式添加一些接口实现) if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { // 如果是引介增强,上面已经处理了,跳过 if (candidate instanceof IntroductionAdvisor) { // already processed continue; } // 对于普通bean的处理 if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { // 如果是IntroductionAdvisor的话,则调用IntroductionAdvisor类型的实例进行类的过滤 if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } // 通常我们的Advisor都是PointcutAdvisor类型 else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; // 从Advisor中获取Pointcut的实现类 这里是AspectJExpressionPointcut return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } }
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); // 进行切点表达式的匹配最重要的就是 ClassFilter 和 MethodMatcher这两个方法的实现 // 先进行ClassFilter的matches方法校验 if (!pc.getClassFilter().matches(targetClass)) { return false; } // 再进行 MethodMatcher 方法级别的校验 MethodMatcher methodMatcher = pc.getMethodMatcher(); if (methodMatcher == MethodMatcher.TRUE) { // No need to iterate the methods if we're matching any method anyway... return true; } IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<?>> classes = new LinkedHashSet<>(); if (!Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); for (Class<?> clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); // 只要有一个方法能匹配到就返回true;这里就会有一个问题: // 因为在一个目标中可能会有多个方法存在,有的方法是满足这个切点的匹配规则的,但是也可能有一些方法是不匹配切点规则的 // 所以在运行时进行方法拦截的时候还会有一次运行时的方法切点规则匹配 for (Method method : methods) { if (introductionAwareMethodMatcher != null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) { return true; } } } return false; }
然后这里的 pc.getClassFilter().matches(targetClass) 是要从 AspectJExpressPointcut中获取ClassFilter;再然后就是到AspectJExpressPointcut中去进行定义的表达式中去进行匹配和过滤了,这个过程aspectj的内容了,很复杂,我觉得就没必要去深究了…
到这里,获取到了所有标注了@Aspect的bean中所有的增强器,并且筛选出了匹配当前bean的增强器,增强器的获取到此结束。
我们先来总结一下增强器的获取步骤:
- 获取所有的beanNames;
- 遍历所有的beanNames,获取标注了@Aspect注解的bean;
- 获取增强器:
3.1 获取这个bean的所有方法;
3.2 遍历每个方法,获取方法对应的增强器:- 3.2.1 把方法中对应的表达式,封装成切点信息对象;
- 3.3.2 根据这个切点信息对象,生成对应的增强器;(不同类型的增强器,有不同的实现类)
- 过滤能够匹配当前bean的增强器;
2.2.2.2.2 创建代理
在获取了所有对应bean的增强器后,就可以进行代理的创建了。
为了避免文章篇幅过长,就把创建代理放到下一篇文章Spring——6. AOP介绍及源码实现(二)中继续分析。