标签:factory advice 动态 获取 包装 parse spec ntc lis
结合 Spring 后置处理器源码 和 Spring Aware源码 ,再来看下 Spring AOP 的源码。
使用 @EnableAspectJAutoProxy 这个注解来启用 AOP 的能力了。它使用 @Import 导入类 AspectJAutoProxyRegistrar,这个类实现了 ImportBeanDefinitionRegistrar,所以它会被 ConfigurationClassParser 扫描,并加入缓存中。然后 ConfigurationClassBeanDefinitionReader 从缓存中会拿到这个类,再执行其实现的方法 registerBeanDefinitions()。
AspectJAutoProxyRegistrar.registerBeanDefinitions() 源码
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
上述方法又使用 AOP 配置工具类 AopConfigUtils 将 AnnotationAwareAspectJAutoProxyCreator 也注册到 BeanFactory,其 name 为 org.springframework.aop.config.internalAutoProxyCreator。
下图,展示了 AnnotationAwareAspectJAutoProxyCreator 的类继承关系
可以看出来 AnnotationAwareAspectJAutoProxyCreator 就是 BeanPostProcessor 和 Aware,其顶层抽象类 AbstractAutoProxyCreator 实现它们的接口。
Spring Aware源码 中可知,BeanFactoryAware 实现类会在 invokeAwareMethods() 被回调 setBeanFactory() 方法,将 DefaultListableBeanFactory 注入给 AnnotationAwareAspectJAutoProxyCreator。
InstantiationAwareBeanPostProcessor 新增了后置处理器方法 postProcessBeforeInstantiation() 和 postProcessAfterInstantiation(),这两个方法会在 Bean 初始化之前,也就是在 BeanPostProcessor 定义的方法之前先调用。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 会返回一个代理对象,会执行 postProcessBeforeInstantiation()
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, mbdToUse, args);
}
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 从缓存获取
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 判断是否已经在 advisedBeans 缓存
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 判断 Bean 是否是 Advice/Pointcut/Advisor/AopInfrastructureBean 这些不需要代理的基础类型;或者是否 @Aspect 注解类
// 找到切面类中的所有通知方法,判断是否 AspectJPointcutAdvisor 类型,否则返回 false
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
return null;
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
// 属性赋值,会执行 postProcessAfterInstantiation()
populateBean(beanName, mbd, instanceWrapper);
// 执行 BeanPostProcessor 的方法
return initializeBean(beanName, exposedObject, mbd);
}
com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
),同时会设置回调方法,完成后返回。public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 包装
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// 包装类
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 找到所有的候选通知方法
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 从候选通知方法找到可用于当前 Bean 的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 获取所有的通知拦截器对象
Object[] specificInterceptors = eligibleAdvisors.toArray();
// 利用 AopProxy 来创建代理对象
// AopProxy 包含 JDK 和 CGLib 两种实现
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
至此,动态代理对象以及创建完成了,容器中就会有这个增强后的代理对象,方法执行时,也就会利用这个代理对象来执行通知方法了。
执行被代理的方法时,会被 CglibAopProxy 拦截器拦截,获取这个方法的拦截器链。如果有拦截器链,则创建 CglibMethodInvocation 对象,执行 proceed(),即执行通知方法,最后返回 retVal,即方法的返回值;如果没有拦截器链,则直接执行方法;
拦截器链实际上就是把方法拦截器放在 ArrayList 队列中,第一个默认是 ExposeInvocationInterceptor,剩下的默认顺序为 AspectJAfterThrowingAdvice、AspectJAfterReturningAdvice、AspectJAfterAdvice、AspectJAroundAdvice、AspectJMethodBeforeAdvice。
proceed() 按照上面 ArrayList 中的顺序递归调用,当遇到 AspectJAroundAdvice、AspectJMethodBeforeAdvice 类型的通知时,会利用反射直接执行它们的通知方法,其他类型通知不会立即执行,会等待递归返回之后再行调用 invoke() 方法。这样,就能保证通知和方法的执行顺序:
环绕通知执行 proceed() 前->前置通知->执行方法->环绕通知执行 proceed() 后->后置通知->返回通知->方法返回
com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
。标签:factory advice 动态 获取 包装 parse spec ntc lis
原文地址:https://www.cnblogs.com/bigshark/p/11324595.html