相逢意气为君饮,系马高楼垂柳边。这篇文章主要讲述如果没有AspectJ,Spring中如何使用SpringAOP@Transactional?相关的知识,希望能为你提供帮助。
@TOC
前言Spring AOP 中使用 aspectJ 不是强制的,Spring 实现了 aspectJ 注解风格的 AOP,同时也实现了 Spring 自己风格的 AOP。
只不过, aspectJ 注解的方式来使用 Spring AOP 是最佳实践。
下面,我们就来探索一下:
- 没有 aspectJ,Spring AOP 还能正常使用吗?
- 没有 aspectJ,我们如何使用 Spring AOP?
@SpringBootApplication
@MapperScan("com.kvn.tx.mapper")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class TxApplication public static void main(String[] args)
SpringApplication.run(TxApplication.class, args);
如果我们去掉
@EnableAspectJAutoProxy
,同时也去掉 aspectjweaver.jar
的依赖,经测试 CarService 也产生了代理类,同样也可以使用 @Transactional 的功能。我们知道 @Transactional 是通过 Spring AOP 来实现的。这就证明了,如果没有 aspectj,我们也是可以正常使用 Spring AOP 的功能的。
这是为什么呢?下面就来分析一下
为什么不加 @EnableAspectJAutoProxy 也能使用 @Transactional ?@EnableAspectJAutoProxy 其实是开启 AspectJ 注解风格的 Aspect 时需要添加的。
理论上,我们不加 @EnableAspectJAutoProxy 也是可以使用 Spring AOP 功能的,因为 Spring 并没有完全依赖 AspectJ,只不过使用 AspectJ 注解定义的切面比其他方式更加简洁,而且 AspectJ 注解功能强大。
接下来,我们就再来研究一下:当我们不加 @EnableAspectJAutoProxy 时,@Transactional 标记的类是在哪里产生 AOP 代理类的?
我们首先要找到代理产生的地方。可以在
AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
处添加一个条件断点: condition 是 result != currentpublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors())
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null)
return result;
result = current;
return result;
通过断点调试,可以发现,在经过
InfrastructureAdvisorAutoProxyCreator
的处理之后,CarService 变成了 AOP 代理类。也就是说在不加 @EnableAspectJAutoProxy 时,是
InfrastructureAdvisorAutoProxyCreator
这个 BeanPostProcessor 产生的代理类。而且,这时 application context 中并没有
AnnotationAwareAspectJAutoProxyCreator
这个 BeanPostProcessor。【如果没有AspectJ,Spring中如何使用SpringAOP@Transactional?】也就是说,当我们不加 @EnableAspectJAutoProxy 时,其实是使用的 Spring 风格的 AOP。
Spring 风格的 AOP : 定义 PointcutAdvisor 来使用 Spring AOP 功能我们可以通过配置
RegexpMethodPointcutAdvisor
来使用 Spring AOP 的功能Spring xml 方式定义 Advisor
<
bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<
property name="pattern" value="https://www.songbingjia.com/android/.*FoooService.*" />
<
property name="advice">
<
bean id="advice" class="com.kvn.aop.advisor.MyAdvice">
<
/bean>
<
/property>
<
/bean>
Spring @Bean 方式定义 Advisor
@Bean
public RegexpMethodPointcutAdvisor myAdvisor()
RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
/**
* 设置的正则是匹配方法的全限定名
* @see AbstractRegexpMethodPointcut#matches(java.lang.reflect.Method, java.lang.Class)
*/
advisor.setPattern(".*FoooService.*");
advisor.setAdvice(new MethodBeforeAdvice()
@Override
public void before(Method method, Object[] args, Object target) throws Throwable
System.out.println("execute before advice:" + method);
);
return advisor;
@EnableAspectJAutoProxy 的作用是什么?
我们已经搞明白了:
当我们添加 @EnableAspectJAutoProxy 时,其实是使用了 AnnotationAwareAspectJAutoProxyCreator 来产生 AOP 代理类。
而不添加 @EnableAspectJAutoProxy 时,其实是使用了 InfrastructureAdvisorAutoProxyCreator 来产生 AOP 代理类。
而 @Transactional 的功能其实是使用的 Advisor 的方式实现的,没有和 AspectJ 强制绑定,所以,当我们去掉 @EnableAspectJAutoProxy 时,也能正常使用 @Transactional 的功能。
回过头来,我们再来看一下
@EnableAspectJAutoProxy
的作用是什么?@EnableAspectJAutoProxy 的作用是引入了
@Import(AspectJAutoProxyRegistrar.class)
。AspectJAutoProxyRegistrar 的作用是注册 AnnotationAwareAspectJAutoProxyCreator:
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.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) // 注册 AnnotationAwareAspectJAutoProxyCreator
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);
当使用 @EnableAspectJAutoProxy 之后,就会自动注册
AnnotationAwareAspectJAutoProxyCreator
,我们就可以使用 AspectJ 注解风格的 AOP 了。疑问:
当使用 @EnableAspectJAutoProxy 之后,就自动注册了 AnnotationAwareAspectJAutoProxyCreator,那么它会与 InfrastructureAdvisorAutoProxyCreator 产生冲突吗?
如果这两个同时存在的话,不是会根据 Advisor 产生两次代理?
这样肯定是不行的,那真相究竟是什么?我们就来一起分析一下吧
AutoProxyCreator 自动代理创建者的升级协议AbstractAdvisorAutoProxyCreator 主要有三个实现类:
- InfrastructureAdvisorAutoProxyCreator
- AspectJAwareAdvisorAutoProxyCreator
- AnnotationAwareAspectJAutoProxyCreator
通常来说,项目中只需要一个 AutoProxyCreator 就可以了,但是不同的场景下又需要不同的 AutoProxyCreator 来完成。
比如:
场景一:当用户没有添加 aspectj 依赖时,只需要找出 application context 下所有的 advisor 来创建 AOP 代理。
场景二:当用户添加了 aspectj 依赖,并开启了 aspectj 注解切面功能时(@EnableAspectJAutoProxy),就需要找出 application context 下所有的 advisor 和 aspectj 注解风格的切面来创建 AOP 代理类。
为了解决这个问题,Spring 通过
AopConfigUtils
提供了一个简单的升级协议,允许多次调用注册自动代理创建者的方法,但最终只会将更强大 AbstractAdvisorAutoProxyCreator 注册为 BeanPostProcessor。AopConfigUtils
org.springframework.aop.config.AopConfigUtils
:用于处理AOP自动代理创建者注册的工具类。AopConfigUtils 只会注册一个自动代理创建者
AutoProxyCreator
(即:AbstractAdvisorAutoProxyCreator) 的实现类,注册方法可能会被多次调用,但最终只会注册一个 AutoProxyCreator。可以看到,源码中定义了三个 AutoProxyCreator:
private static final List<
Class<
?>
>
APC_PRIORITY_LIST = new ArrayList<
>
(3);
static
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
自动代理创建者的升级协议:
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<
?>
cls, BeanDefinitionRegistry registry, @Nullable Object source) // 升级协议,排在后面的功能更强,优先级更高
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);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
可以看出,升级协议的逻辑是:
- 第一次调用注册时,registry 中没有,就会直接向 registry 中进行注册
- 第二次调用注册时(或者多次调用),会将待注册的 AutoProxyCreator 与 registry 中的进行比较,如果排在 APC_PRIORITY_LIST 的后面,则会将 bean class 进行替换
不添加 @EnableAspectJAutoProxy 时,使用的是 InfrastructureAdvisorAutoProxyCreator 来产生 AOP 代理类。
InfrastructureAdvisorAutoProxyCreator: 获取 application context 中的 advisor 来产生 AOP 代理类
AnnotationAwareAspectJAutoProxyCreator: 获取 application context 中的 advisor 和 aspectj 注解风格的 Aspect 来产生 AOP 代理类
当我们不依赖 aspectjweaver.jar 时,可以通过定义 Advisor 的方式来使用 Spring AOP 的功能!
总而言之:
不引入 aspectjweaver.jar 时,我们也可以正常的使用 @Transactional、@Async 等 AOP 的功能;
引入 aspectjweaver.jar 时,我们也可以使用,只是两种情况下创建 AOP 时使用的 AutoProxyCreator 不一样而已。
Spring 框架提供了三种 AutoProxyCreator,只会有一个会生效,它按照引入 jar 的不同来做了一个简单的升级协议,来保证只选用其中的一个。这是一种可以参考的框架封装的思路。
如果本文对你有所帮助,欢迎点赞收藏!
公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…
阅读更多文章,请关注公众号: 老王学源码
文章图片
博主好课推荐:
课程 | 地址 |
---|---|
Dubbo源码解读——通向高手之路 | https://edu.51cto.com/sd/2e565 |
正则表达式基础与提升 | https://edu.51cto.com/sd/59587 |
推荐阅读
- Nginx网站服务配置
- 智能化车间生产管理系统软件解决方案
- Linux环境中Clamav杀毒软件详细使用步骤
- 最新智能工厂mes管理系统软件解决方案
- MacBook软件安装和更新与卸载
- linux系统清除木马病毒解决流程
- 智慧工厂协同管控应用系统软件建设方案
- #yyds干货盘点#一什么是计算机
- Win10系统下怎样用虚拟键盘输入emoji表情