前面文章已经分析了SpringAop原生的运行原理,本节将分析使用频率最高场景: Spring环境下的AOP运行原理。本文会涉及到Spring启动期间注入Bean的流程,默认你已经非常熟悉了,本文不再详细赘述相关流程。
在SpingBoot项目中使用AOP一般会做如下操作:
- 主启动类上添加@EnableAspectJAutoProxy注解开启SpringAop功能
- 自定义切面并注入到Spring中即可
@SpringBootApplication
@EnableAspectJAutoProxy
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
@Aspect
@Component
public class TestAspect {
@Pointcut(value = "execution(* com.ssm.test.aop.ATMService.withdrawMoney())")
public void pointcut() {}
@Before(value = "pointcut()")
public void before() {
System.out.println("TestAspect.before.....");
}
@After(value = "pointcut()")
public void after() {
System.out.println("TestAspect.after.....");
}
}
@Service
public class ATMService implements BankService {
@Override
public void withdrawMoney() {
System.out.println("ATMService : 取钱成功");
}
}
如上代码所示是一个简单的AOP增强案例,本节就基于这个案例分析Spring环境下AOP的运行原理。
@EnableAspectJAutoProxy原理分析
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
首先分析下在主启动类上添加的的@EnableAspectJAutoProxy注解 , 该注解主要是用于配置proxyTargetClass、exposeProxy属性,这个两个属性在之前的文章也分析过了,此处不再赘述。如上图源码所示该注解还有有一个非常关键的作用 : @import(AspectJAutoProxyRegistrar.class), 了解过Spring原理可以知道这边@import注解是用来注入AspectJAutoProxyRegistrar这个Bean的.
AspectJAutoProxyRegistrarclass AspectJAutoProxyRegistrar implements importBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassmetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
如上图源码所示,AspectJAutoProxyRegistrar将 BeanDefinitionRegistry作为参数将主要逻辑都委托给了AopConfigUtils这个工具类。BeanDefinitionRegistry接口并不陌生,主要提供注册、删除、获取Bean的功能,所以可以大致判断出AopConfigUtils在这边主要是注入了某个Bean :
AopConfigUtilspublic abstract class AopConfigUtils {
//The bean name of the internally managed auto-proxy creator.
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
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) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
//将当前要注入的Bean的优先级设置为最高
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
.....
}
结合上图源码可知AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);这行代码实际上是手动向Spring注入了beanName为org.springframework.aop.config.internalAutoProxyCreator, Bean类型为 : AnnotationAwareAspectJAutoProxyCreator.class的Bean. 有个细节需要注意:registerOrEscalateApcAsRequired()方法注入Bean时会为该Bean设置order属性,将Bean的优先级调整为最高级别,这样做的目的是可以优先注入该Bean, 但优先注入这个Bean具体有何意义此处先Mark一下。
forceAutoProxyCreatorToUseClassProxying()、forceAutoProxyCreatorToExposeProxy()两个方法实际上是为上面注入的AnnotationAwareAspectJAutoProxyCreator这个Bean设置proxyTargetClass、exposeProxy属性值。虽然@EnableAspectJAutoProxy注解中这两个属性值默认值为false, 但是底层源码却直接将属性值置为了true, 从而可以知道SpringBoot中使用SpringAop默认会使用强制使用CGLIB代理,并且会将当前的代理对象暴露在当前线程中,可以直接使用AopContext获取到当前代理对象。
综上所述可以总结出: 主启动类上添加@EnableAspectJAutoProxy这个注解可以向Spring中注入AnnotationAwareAspectJAutoProxyCreator这个Bean, 具体它是用来干嘛的此处先不表,下面会详细分析它。
AnnotationAwareAspectJAutoProxyCreator如上图所示是AnnotationAwareAspectJAutoProxyCreator的UML图,由于涉及的比较多所以分析时只会贴出关键代码。上图可以很清楚的看出AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor、InstantiationAwareBeanPostProcessor接口,所以本质上是一个BeanPostProcessor. 对Spring了解的同学应该都知道Spring在启动期间注入Bean时,会使用IOC中的BeanPostProcessor类型的Bean对当前Bean的注入做增强处理(相当于是一个埋点处理), 我们简单贴个代码回顾一下 :
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
......
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
try {
//Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException("", ex);
}
}
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
......
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//调用BeanPostProcessor接口中的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException("Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//调用BeanPostProcessor接口中的postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
//调用BeanPostProcessor接口InstantiationAwareBeanPostProcessor接口中的postProcessBeforeInstantiation方法
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
//调用BeanPostProcessor接口中的postProcessAfterInitialization方法
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
......
}
如上图所示是Spring遍历注入一个Bean时会调用到AbstractAutowireCapableBeanFactory#createBean()方法,在这个方法中有这样一行代码 : Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 这行代码上有一行非常重要的注释 : 给BeanPostProcessor一个机会返回代理实例而不是目标实例。 仔细观察resolveBeforeInstantiation()方法逻辑可以看到它主要是遍历调用IOC中所有的BeanPostProcessor的postProcessBeforeInstantiation方法(该方法属于InstantiationAwareBeanPostProcessor)和postProcessAfterInitialization方法(该方法属于BeanPostProcessor).
createBean还会委托到AbstractAutowireCapableBeanFactory#initializeBean()方法 :
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
......
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()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这个方法会在执行Spring初始化方法afterPropertiesSet前后分别遍历调用IOC中所有BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法。
根据上面AnnotationAwareAspectJAutoProxyCreator UML图可知它实现了BeanPostProccesor和InstantiationAwareBeanPostProcessor接口,所以我们重点关注一下它和BeanPostProcessor有关的接口实现 ,这些逻辑在AnnotationAwareAspectJAutoProxyCreator的父类AbstractAutoProxyCreator中 :
AbstractAutoProxyCreatorpublic abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
//保存那些有指定TargetSource的Bean的名称
private final Set targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//保存需要被AOP拦截的Bean的名称与它的代理对象Class类型的映射关系
private final Map
流程总结
SpringBoot集成SpringAop后会注入AnnotationAwareAspectJAutoProxyCreator这个Bean, 它是一个BeanPostProcessor类型. Spring在启动期间遍历注入Bean时会遍历调用IOC中所有BeanPostProcessor类型的postProcessBeforeInitialization、postProcessAfterInitialization方法。 AnnotationAwareAspectJAutoProxyCreator也属于BeanPostProcessor,所以Spring注入每个Bean时也会调用到它的这个两个方法,方法是在它的父类AbstractAutoProxyCreator中实现的。 AbstractAutoProxyCreator中的这两个方法会判断当前Spring正在注入的这个Bean是否需要被IOC中的切面拦截,如果不需要则直接返回不做任何处理,否则会调用它的createProxy方法使用之前文章分析过的ProxyFactory方式生成当前Bean的代理对象并返回,之后的逻辑就和之前文章分析过的代理过程一样了。



