原文:Spring AOP 的实现过程
1. 什么是 aop?
aop 的作用是在书写上将辅助业务逻辑从主业务的逻辑中拆出来,实现主业务和辅助业务的解耦,但在执行主业务逻辑的时候,辅助业逻辑业也会执行。从而保证拆前拆后功能不变。
那辅助业务拆出来放在哪里?
辅助业务封装在切面中,所以 面向切面编程。
什么是切面?
切面就是一个类,并且被 @Aspect 注释。
辅助业务在切面的哪里?
辅助业务封装在切面的方法里,不同的方法封装不同的辅助业务逻辑。
切面中的方法是怎么触发的呢?
给封装辅助业务逻辑所在的方法标注 @Before 、@After、@AfterRunning 、@AfterThrowing、@Around 其中一个或几个注解。这样当主业务方法执行时,辅助业务的逻辑所在的方法就知道何时触发了。
切面中的辅助业务逻辑所在的方法由两个作用:1. 辅助业务内容是什么?2. 辅助业务何时触发。切面中具有这两个作用的方法叫做:
通知 。
主业主逻辑执行时,通知也会在恰当时机执行,那到底是哪个主业执行时会触发通知?
总不能随便执行一个类的方法,通知就跟着触发一遍吧,这不乱套了咩。
在切面里还有一样东西,它规定了哪几个类的哪些方法执行时,触发当前切面中的通知。
这样东西就叫切点,一个被@Pointcut 注释切面中的方法。
所以:
aop 是啥?面向切面编程,将辅助业务和主业务解耦,但要保证功能不变。
切面是啥?通知和切点同时所在的那个类,就叫切面,脑门上还被@Aspect 注释了。
通知和切点有都是啥?自己去上面重新看一遍,放心,不长。
切面长什么样子?
// 一个简单的切面。 @Aspect public class LoggerAspect {
// 切点,“切” com.forum.controller 包下的所有类的所有方法。 @Pointcut("execution(public * com.forum.controller.*.*(..))") public void log() {
} // 通知1,在目标方法开始执行时,执行该通知。 @Before("log()") public void doBefore(JoinPoint joinPoint) {
// ....... // 辅助业务1 // ....... } // 通知2,在目标方法开始执行结束后,执行该通知。 @After("log()") public void doAfter() {
// ....... // 辅助业务2 // ....... } }
讯享网
2. aop的实现过程
主业务在 A 类中,辅助业务在切面 B 类中,在 Spring 项目的启动过程中,会将 A 和 B 类“组合”成一个新的类 C,C 在执行 A 的主业务时,在恰当的时机,会调用 B 中的方法。C 就是就是常说的代理类。
重点:当且仅当 代理对象执行目标方法时,aop 功能才会触发!
先规定几个术语:
- 主业务类 A 叫做目标类,A 中的方法叫做目标方法。
- 辅助业务类 B 叫做切面,B中的方法要么是通知、要么是切点。
- C 类叫做代理类。
所以,AOP 的实现过程有两个阶段:
- 目标类是怎么变成代理类的?
- 代理类是怎么执行目标方法的?
2.1 目标类变成代理类的过程
这个准确的说是目标对象变成代理对象的过程,因为类不实例化不能使用。所以首先是目标类实例化成目标对象,这是 IOC 的构成,这里就不详细描述了。
讯享网// AbstractAutoWireCapableBeanFactory.java 的 doCreateBean() 方法中。 // A 的 bean 被创建出来,仅仅是一个内存空间,属性值都是默认的初始值。 Object bean = instanceWrapper.getWrappedInstance(); // 一直往下走.... // 如果 bean 被 aop ”切“了,在 initializeBean 方法中 bean 会被变成代理对象返回。 exposedObject = initializeBean(beanName, exposedObject, mbd);
先有的 bean ,再为其创建代理对象。
// AbstractAutoWireCapableBeanFactory.java。 protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else {
invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {
invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) {
throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) {
// 这个方法将 bean 变成了代理对象。 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
那怎么变的呢?
bean 被创建后,接下来会调用所有的BeanPostProcessor 作用在 bean 上,其中有一个名叫 AnnotationAwareAspectJAutoProxyCreator 的 BeanPostProcessor,是它将 bean 变成了对应的代理类。
注意类中的Aspect,意思是处理切面的处理器
(至于 AnnotationAwareAspectJAutoProxyCreator 是怎么来的,在后面会写到。)
讯享网// AbstractAutoWireCapableBeanFactory.java。 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean; // 遍历所有的 beanPostProcessor。 for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 在 bean 上执行每一个 beanPostProcessor 的 postProcessAfterInitialization() 方法。 Object current = processor.postProcessAfterInitialization(result, beanName); // 下面的代码就是将结果返回。 if (current == null) {
return result; } result = current; } return result; }
先看下 AnnotationAwareAspectJAutoProxyCreator 继承的类图,不然后面走方法会有点懵。

讯享网
接下来看下代理类是怎么生成的,通过ctrl+F12,找到方法postProcessAfterInitialization(@Nullable Object bean, String beanName)
// AbstractAutoProxyCreator.java public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 缓存 cacheKey 类似 bean 的 id。 Object cacheKey = getCacheKey(bean.getClass(), beanName); // 如果 bean 已经生成了代理,那就跳过,不再重复生成。 if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 为 bean 创建代理对象并返回。 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
为什么要判断 bean 是否已经生成了代理?因为在工程启动过程中有两个地方可以将目标对象变成 aop 代理,一个在这里,另一个是目标对象从三级缓存转到二级缓存的时候,所以在这里需要判断下。
讯享网// 如果 bean 需要被代理,为他创建一个代理对象。 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果 beanName 是有效的,且 beanName 已经被代理了。 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
// 此时不需再创建代理,直接返回 bean。 return bean; } // 不需要处理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
// 不需要创建代理,直接返回 bean。 return bean; } // 基础设施类(Advice、Pointcut、Advisor、AopInfrastructureBean 这些类为接口的子类)不应该为其创建代理; // 或者 beanName 以 ".ORIGINAL" 结尾,也不应该为其创建代理。 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 如果 bean 有方法被"切"了,为其创建代理。 // 获取针对 bean 的所有增强器,(每一个通知都会被构建成一个增强器。) Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 判断 specificInterceptors 不为空。如果是空,说明当前 bean 没有被”切“。 if (specificInterceptors != DO_NOT_PROXY) {
// 设置需要为 cacheKey 创建代理。 this.advisedBeans.put(cacheKey, Boolean.TRUE); // 创建代理。 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 保存 cacheKey 的代理。 this.proxyTypes.put(cacheKey, proxy.getClass()); // 返回创建好的代理对象。 return proxy; } // 如果拿不到 advices,标识 bean 不需要增强。(都没被切,增强个毛线) this.advisedBeans.put(cacheKey, Boolean.FALSE); // 返回 bean 或者 bean的代理对象。 return bean; }
这块的逻辑简单,判断有没有针对 bean 的 切面,如果没有,直接将 bean 返回。如果有,为 bean 创建代理对象。(至于代理对象是怎么创建的,这个后面再写。)
这里就有个问题了:
- 切面信息是怎么拿到的?(更确切的说切面是怎么被解析的)
- 怎么判断有没有针对当前 bean 的切面?其实找的是有没有作用在当前 bean 上的通知。
2.1.1 获取切面信息
继续往下看代码,简单的逻辑就不解释了,直接看注释吧。
通过ctrl+F12,找到方法protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource )
// AbstractAutoProxyCreator.java, // 但是记住,因为被继承了,所以此时应该是是在 AnnotationAwareAspectJAutoProxyCreator.java 中 protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource ) {
// 为 beanClass 寻找符合条件的增强器(advisors),增强器就是通知,这个后面有解释。 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); // 如果找不到 if (advisors.isEmpty()) {
// 返回 null return DO_NOT_PROXY; } // 找到了增强器,以数组格式将这些增强器返回。 return advisors.toArray(); }
继续往下走…,找到findEligibleAdvisors(Class<?> beanClass, String beanName)方法
讯享网protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到所有的 advisors,包括事务的 advisor 和 普通 aop 的 advisor。。 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 在所有的 advisors 中筛选符合 beanClass 使用的 advisor。(通过切点那块的表达式判定有没有切到 beanClass) List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 向 eligibleAdvisors 中额外再添加一个 ExposeInvocationInterceptor 类型的 advisor。 extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) {
// 如果有多个 advisor,谁先谁后,在这里排序。 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } // 返回符合条件的 advisor return eligibleAdvisors; }
findCandidateAdvisors()这个方法中把上面两个问题都回答了,去方法里面看看。
// 这里一定要进到 AnnotationAwareAspectJAutoProxyCreator.java 中,走错地方就找不到这个方法了。 protected List<Advisor> findCandidateAdvisors() {
// 这是是找事务相关的 advisor。因为事务相关的 advisor 少,而且是现成的。 List<Advisor> advisors = super.findCandidateAdvisors(); if (this.aspectJAdvisorsBuilder != null) {
// 接下来才找 aspectJ 的 advisor。 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } // 返回找到的所有通知。 return advisors; }
事务相关的,这里不解释了。主要看自定义的切面。
2.1.2 切面是怎么被解析的。
切面刚开始也只是个 class 文件,只有被注入、解析后才能使用。先大概简述下切面被注入和解析的思路:
- 切面类上有
@Component注解,所以在工程启动时调用ConfigurationClassPostProcessor会加载切面的 java 文件,创建对应的 BeanDefinition,最后再遍历所有的 BeanDefinition 并为每一个创建对应的 bean 保存到applicationContext中的beanFactory字段的beanDefinitionMaps字段中。(切面就这样注入了)。 - 接下来就是解析切面了,最终解析到切面的通知上去,因为辅助逻辑都在通知里面写着。
2.1 去
beanFactory中拿所有的 object 的 beanName,即获取所有的 bean 的名字。2.2 遍历 beanNames,为每一个 beanName 创建 Class 对象。
2.3 判断该 Class 对象上有没有
@Aspect注解,如果有,那这个类就是切面类了。2.4 切面类的 Class 对象都拿到了,获取类中的全部方法肯定也是能办到的。遍历类中的每一个方法,判断方法上有没有
@Before、@After、@Around、等注解,如果有,拿这个方法就是通知,为每一个通知创建一个 Advisor 对象。最后将所有的 Advisor 对象 保存到 advisors 列表中。最后返回。
解析切面的流程大概就是这样,详细的源码如下,先不管缓存的事情,后面会写切面缓存,以及解析切面的执行时机。
讯享网public List<Advisor> buildAspectJAdvisors() {
// aspectBeansNames 中保存的是已经解析的切面的名称。 // 因为不止这一个地方有解析切面的代码,在doCreateBean() 方法之前也解析过切面。 // 并且将解析到的通知都缓存起来。并标记该切面已被解析,下次再要解析时直接从缓存中拿。 List<String> aspectNames = this.aspectBeanNames; // aspectNames == null 说明这是第一次解析,那就要执行正真的解析流程了。 if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames; if (aspectNames == null) {
// 用于保存所有解析出来的 Advisors 集合对象。 List<Advisor> advisors = new ArrayList<>(); // 用于保存所切面名称的集合。 aspectNames = new ArrayList<>(); / * aop 功能在这里传入的是 Object 对象,表示从容器中获取所有组件的名称,然后遍历所有组件, * 这个遍历过程是非常消耗性能的,所以 Spring 在这个过程中加入了保存切面信息的缓存。但是事务 * 功能不一样,事务模块的功能是直接去容器中获取 Advisor 类型的,选择范围小,且不消耗性能。 * 所以 Spring 在事务模块中没有加入缓存来保存事务相关的 advisor。 */ String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); // 遍历从 IOC 容器中拿到的所有 beanName。 for (String beanName : beanNames) {
// 判断 beanName 是合法的。 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. // 通过 beanName 去容器中获取到 class 对象。(能拿到 class对象,bean的全部信息也就都拿到了) Class<?> beanType = this.beanFactory.getType(beanName, false); if (beanType == null) {
continue; } // 根据 class 对象判断是不是切面。(有没有被 @Aspect 注解) if (this.advisorFactory.isAspect(beanType)) {
// 是切面, // beanName 加到缓存中。 aspectNames.add(beanName); // 用 class 对象和 beanName 构建一个 AspectMetadata 对象。 AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 构建切面注解的实例工厂 MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 获取切面中的所有通知。 / * 思想:都已经拿到 class 对象了,从中可以获取到类中的所有方法,遍历每一个方法, * 判断方法上有没有 @Before、@After、@Around、等注解。如果有,就为这个方法 new 对应类型的 Advisor()。 */ 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(); } // 能走到这里,切面已经被解析了,通知已经被转换成 advisor 缓存起来了。 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; }
2.1.3 解析切面的执行时机
在上面的代码中可以看到,只有当 this.aspectBeanNames为空的时候才执行解析,否则去 this.advisorsCache 中直接拿advisor,最后返回。那就说明在前面某个地方已经解析过切面了,并且将解析的结果缓存了起来。

答案1:在 createBean() 方法中 doCreateBean()方法之前解析的。
// AbstractAutowireCapableBeanFactory.java Object bean = resolveBeforeInstantiation(beanName, mbdToUse); // ----- protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null; if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd); // beanName 的 Class 对象是能拿到的。 if (targetType != null) {
// 在这里解析的切面。 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
讯享网protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // AnnotationAwareAspectJAutoProxyCreator 调用 postProcessBeforeInstantiation 方法。 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); if (result != null) {
return result; } } } return null; }
@Override 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(beanClass, beanName) 方法里解析了切面。 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } 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; }
讯享网protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 这个方法是不是很熟悉。 List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true; } } return super.shouldSkip(beanClass, beanName); }
@Override protected List<Advisor> findCandidateAdvisors() {
// 这是是找事务相关的 advisor。因为事务相关的 advisor 少,而且是现成的。 List<Advisor> advisors = super.findCandidateAdvisors(); if (this.aspectJAdvisorsBuilder != null) {
// 接下来才找 aspectJ 的 advisor。 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } // 返回找到的所有通知。 return advisors; }
答案2:自定义切面的解析过程是,从 beanFactory 中拿出所有的 bean 执行遍历,看脑门上有没有 @Aspect注解(确认是不是切面),如果有再去遍历这个类的方法,也是根据脑门上的注解判断方法是不是通知,最后为每个通知构建一个 Advisor 对象。
这就会出现两个开销和大的地方:
- 如果 beanFactory 中的 bean 非常多,全部遍历一遍解析本身就很花时间。(这个过程是解析了项目中全部切面)
- beanFactory 中的 beanDefinition 非常多时,每个 beanDefinition 变成 bean 时都要解析一遍切面,那么1过程将会被重复执行好多遍,这就更费性能了。
所以缓存是有必要的。只需要将全部切面解析一遍缓存起来,下次直接从缓存中获取,就能降低开销。
那缓存到哪里了呢?
前面说到过,AnnotationAwareAspectJAutoProxyCreator 的 bean 是已经被注入到 beanFactory 中了。 AnnotationAwareAspectJAutoProxyCreator里面有个字段叫 BeanFactoryAspectJAdvisorsBuilder,BeanFactoryAspectJAdvisorsBuilder中有两个字段
讯享网// 缓存所有被解析的切面的 beanName。 List<String> aspectBeanNames // 缓存解析的所有切面的通知。 key: 切面 beanName, value: 切面下的所有通知构成的list。 Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>()
beanFactory 中的 bean 是全局的,而且只要项目处于启动状态,bean就一直存在。所以下次如果再要解析切面,直接从缓存中拿。
2.1.4 筛选作用于当前 bean 的增强器
在上面拿到了所有项目中所有的增强器,但不是每个增强器都作用在当前bean 上的,所以还需要筛选出那些作用在当前bean上的增强器。
先补一个概念,上面提到的 为每一个通知构建一个 Advisor() 对象,增强器里不只有通知,还有切点。
// 这是项目中增强器的类型 final class InstantiationModelAwarePointcutAdvisorImpl{
private final Pointcut pointcut; // 切点 private Advice instantiatedAdvice; // 通知 // 其他字段就不贴了。 }
代码中是这么筛选增强器的,candidateAdvisors 是所有的增强器,beanClass, beanName 表示当前bean,通过切点筛选有木有作用在 bean 上的增强器。
讯享网// 在所有的 advisors 中筛选符合 beanClass 使用的 advisor。(通过切点那块的表达式判定有没有切到 beanClass) List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
细节代码不贴了,套的太深…
2.1.5 创建代理对象
bean有了,作用在 bean上的增强器也被找到了,接下来就是拿着两个东西创建代理对象。
这块的思路很简单:
- 创建代理工厂。
ProxyFactory proxyFactory = new ProxyFactory(); - 将目标对象和它的增强器都 set 到 代理工厂中。
讯享网
proxyFactory.setTargetSource(targetSource); proxyFactory.addAdvisors(advisors); - 代理工厂创建代理对象,并返回。
proxyFactory.getProxy(getProxyClassLoader())
代理工厂返回的是
AopProxy接口,它有两个实现CglibAopProxy和JdkDynamicAopProxy。至于创建的到底是哪一个,要根据条件判断的,这篇文章不对这一部分进行描述。
(到这里,目标对象变成代理对象的流程就算是描述完了。)
再加一个小点,AnnotationAwareAspectJAutoProxyCreator 干了那么多事情,有没有好奇它是怎么来的?
2.1.7 AnnotationAwareAspectJAutoProxyCreator 怎么被加载的?
前面写到 AnnotationAwareAspectJAutoProxyCreator 解析了切面,创建了增强器,最后将目标对象变成了代理对象,那这个类是怎么被加载到的呢?
Spring 项目启动一般都会有一个配置类。
讯享网@Configuration @EnableAspectJAutoProxy @ComponentScan("com.aop") public class AppConfig {
}
@EnableAspectJAutoProxy表面上被翻译成 “启动自动代理”,看看它里面到底干了啥。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy {
}
@Import(AspectJAutoProxyRegistrar.class) 这个很关键。
讯享网class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
// 注册一个 BeanDefinition。 // 注册了 beanDefinition, 那后面肯定会有对应的 bean 产生, // 关键是 注册了哪个类的 beanDefinition。 @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 答案在这里。 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 剩下的代码就不贴了。 } } // ----- // 顺着上面的方法一直走下去,会走到这个方法 registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); // 看下它的方法体。 private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
// 多余的代码这里不贴了。 // cls = AnnotationAwareAspectJAutoProxyCreator.class // 为 cls 创建 beanDefinition。 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 注册 beanDefinition。 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
到这里就清楚了:
@EnableAspectJAutoProxy注解将AnnotationAwareAspectJAutoProxyCreator的 beanDefinition 注入了 applicationContext 中。- 接下来走 beanDefinition 创建对应 bean 的过程,
AnnotationAwareAspectJAutoProxyCreator的 bean 也就注入了 applicationConext 中。AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor接口,所以在对目标类的 bean 执行初始化时,会调用所有的 BeanPostProcessor,当然少不了annotationAwareAspectJAutoProxyCreator,它执行postProcessAfterInitialization(Object bean, String beanName)方法,将目标类变成了代理类。(它解析切面的时机,不在赘述了)- 至于
@Import注解是什么时候执行的,不用猜都知道它在ConfigurationClassPostProcessor类的processConfigBeanDefinitions()方法中执行的。
2.2. 代理类执行目标方法的过程
代理对象创建好了,最关键的时刻来了:代理对对象执行目标方法并在恰当时机将通知织入。
2.2.1 一个 aop 的例子
// 目标对象。 @Component public interface TestBean {
void test(int numberA,int numberB); } @Component public class TestBeanImpl implements TestBean {
public void test(int numberA, int numberB) {
System.out.println("目标方法执行: "+ numberA/numberB); } }
讯享网// 切面 @Aspect @Component public class AspectJTest {
@Pointcut("execution(* com.aop.domain..test(..))") public void test() {
} @Before("test()") public void beforeTest() {
System.out.println("before ..."); } @After("test()") public void afterTest() {
System.out.println("after ..."); } @Around("test()") public Object aroundTest(ProceedingJoinPoint p) {
System.out.println("around before ..."); Object object = null; try {
object = p.proceed(); } catch (Throwable e) {
e.printStackTrace(); } System.out.println("around after ...."); return object; } @AfterReturning("test()") public void afterReturn() {
System.out.println("after return ..."); } @AfterThrowing("test()") public void afterThrow() {
System.out.println("after throw ..."); } }
// 主程序 public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( AppConfig.class); // 此时拿出来的 bean 已经是代理对象了。 TestBean bean = (TestBean) context.getBean("testBeanImpl"); // 代理对象执行目标方法。 bean.test(6,3); } }
结果:
讯享网around before ... before ... 目标方法执行: 2 after return ... after ... around after ....
除了异常通知没有执行以外,其他通知都执行了。
2.2.2 底层流程
在上面的例子中代理代理对象 bean 中已经包含了所有的增强器。
当执行目标方法 bean.test(6,3); 时,代理将调用:
// JdkDynamicAopProxy.java // proxy 是代理对象。 method 是目标方法。 agrs 是[6,3] 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 {
// 如果执行代理对象的 equals 方法,不需要代理。 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself. return equals(args[0]); } // 如果执行代理对象的 hashCode 方法,不需要代理。 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself. return hashCode(); } // 如果执行的 class 对象是 DecoratingProxy,也不要执行拦截器。 else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// “采用反射执行连接点” 意思就是采用反射的方式直接执行方法。 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; // 暴露代理。把我们的代理对象暴露到线程中。这个跟 ThreadLocal 有关。 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 对象。 Class<?> targetClass = (target != null ? target.getClass() : null); // Get the interception chain for this method. // 从目标类的所有通知中找出作用与当前方法的那些通知(增强器),保存到 chain 中。 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) {
// 如果拦截器链为空,说明没有作用于当前方法的通知,则通过反射直接执行目标方法。 // 先获取方法的入口参数。 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); // 再通过反执行方法。(JoinPoint,连接点说的就是方法) retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else {
// We need to create a method invocation... // 如果拦截器不为空,就要织入了。所谓织入就是在执行目标方法的时候,将它的通知在恰当的地方一并执行。 // 先创建 MethodInvocation 对象,将所有需要的信息都封装在里面。 // (代理、目标对象、目标方法、方法参数、目标对象的Class对象 、拦截链) MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. // 开始执行链式调用。 retVal = invocation.proceed(); } // Massage return value if necessary. Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) {
// Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } }
看看 chain里面到底有多少个通知,因为自定义切面中写了 5 个,解析切面时还会额外添加 1 个。
chain 中增强器的排列顺序就是执行目标方法时通知的织入顺序。
那具体是怎么执行的呢?
讯享网public Object proceed() throws Throwable {
// currentInterceptorIndex 的初始值是 -1. // interceptorsAndDynamicMethodMatchers 是个列表里面存放着那 6 个增强器。 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 当遍历完所有拦截器后,执行目标方法。 return invokeJoinpoint(); } // 根据索引拿出拦截器。 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
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 {
return proceed(); } } else {
// 拦截器执行 invoke 方法。 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
这里肯定看懵了吧。
画了一张图,可以直观的看看拦截器的执行顺序。

3. 几小问题
问题1:aop 的底层实现是什么?
底层实现是 java 动态代理 和 cglib。
问题2:为什么jdk动态代理必须是接口?
jdk 动态代理会生成一个字节码文件,也就是 xxx.class 文件。将这个文件反编译后就会看到
public final class $Proxy extends Proxy implements CustomDefinedInterface{
// ....... }
因为生成的代理对象默认继承了 Proxy 类,又因为 java 是单继承的,所以我们的被代理对象必须是接口。
问题3:aop实现到默认是使用 jdk动态代理还是 cglib?
aop没有默认使用哪个代理,都是根据条件判断的。
注解是 @EnableAspectJAutoProxy时,如果目标类有父接口,采用 jdk 动态代理;如果目标类没有父接口,采用 cglib 代理。
注解是 @EnableAspectJAutoProxy(proxyTargetClass = true)时,采用 cglib 代理。
问题4:切面解析的顺序怎么确定?
使用 @order(number) 注解,number 越小,优先级越高。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/57606.html