长沙网站seo技巧,亚马逊雨林有多恐怖,政务门户网站建设方案,网络推广常见的方法事务拦截器TransactionInterceptor1. 事务拦截器项目配置2. 切面2.1 核心故事#xff1a;一份油泼面#x1f37d;️的旅程2.2 AOP核心概念#x1f4da;2.3 两种代码#x1f4bb;风格实现“餐厅切面”风格一#xff1a;基于Aspect注解#xff08;现代、声明式、更常用一份油泼面️的旅程2.2 AOP核心概念2.3 两种代码风格实现“餐厅切面”风格一基于Aspect注解现代、声明式、更常用风格二基于Advisor编程式配置底层、灵活、更精确核心关系与选择3. Transactional解释两种方式的直观对比5. 结论与选择1. 事务拦截器项目配置在Spirng架构中如果不想使用 Transactional注解有时候会忘记处写这个注解太麻烦我们就可以使用Aspect配置式AOP 来装配 事务拦截器TransactionInterceptor的方案完全摆脱Transactional注解。这是Spring框架内更原生的编程式事务管理方式。importorg.aspectj.lang.annotation.Aspect;importorg.springframework.aop.Advisor;importorg.springframework.aop.aspectj.AspectJExpressionPointcut;importorg.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;importorg.springframework.aop.support.DefaultPointcutAdvisor;importorg.springframework.aop.support.NameMatchMethodPointcut;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.transaction.PlatformTransactionManager;importorg.springframework.transaction.TransactionDefinition;importorg.springframework.transaction.interceptor.*;importjava.util.Collections;importjava.util.HashMap;importjava.util.Map;AspectConfigurationpublicclassTransactionConfig{// 1. 定义切入点拦截 com.pro.service 包下所有方法privatestaticfinalStringAOP_POINTCUT_EXPRESSIONexecution(* com.sh.service..*.*(..));// 2. 定义增删改方法前缀自动加事务privatestaticfinalString[]REQUIRED_RULE_TRANSACTION{insert*,create*,add*,save*,update*,modify*,del*,delete*,remove*};// 3. 定义查询方法前缀自动加只读事务privatestaticfinalString[]READ_RULE_TRANSACTION{select*,get*,query*,search*,count*,find*,list*,page*};// 4. 注入事务管理器AutowiredprivatePlatformTransactionManagertransactionManager;// 5. 核心配置事务拦截器 (TransactionInterceptor)【这就是个Adivce通知】BeanpublicTransactionInterceptortxAdvice(){// 5.1 创建事务属性源NameMatchTransactionAttributeSourcetasnewNameMatchTransactionAttributeSource();// 5.2 配置增删改事务属性REQUIREDRuleBasedTransactionAttributerequiredTxnewRuleBasedTransactionAttribute();requiredTx.setRollbackRules(Collections.singletonList(newRollbackRuleAttribute(Exception.class)));// 发生异常回滚requiredTx.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);// 事务隔离级别读已提交requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 事务传播行为REQUIREDrequiredTx.setTimeout(30);// 超时30秒// 5.3 配置查询事务属性只读RuleBasedTransactionAttributereadOnlyTxnewRuleBasedTransactionAttribute();readOnlyTx.setRollbackRules(Collections.singletonList(newRollbackRuleAttribute(Exception.class)));readOnlyTx.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);// 支持当前事务不存在也不新建readOnlyTx.setReadOnly(true);// 关键设置为只读readOnlyTx.setTimeout(20);// 查询超时可设短些// 5.4 将方法名模式映射到事务属性MapString,TransactionAttributetxMapnewHashMap();for(StringmethodName:REQUIRED_RULE_TRANSACTION){txMap.put(methodName,requiredTx);}for(StringmethodName:READ_RULE_TRANSACTION){txMap.put(methodName,readOnlyTx);}tas.setNameMap(txMap);// 5.5 创建并返回事务拦截器returnnewTransactionInterceptor(transactionManager,tas);}// 6. 核心配置切面Advisor将切入点和拦截器关联BeanpublicAdvisortxAdviceAdvisor(){// 6.1 创建切入点使用AspectJ表达式AspectJExpressionPointcutpointcutnewAspectJExpressionPointcut();pointcut.setExpression(AOP_POINTCUT_EXPRESSION);// 6.2 创建 Advisor通知器将切入点 和 事务通知 绑定returnnewDefaultPointcutAdvisor(pointcut,txAdvice());}}在了解AOP之前先看一张图2. 切面用一个生活化的例子——“餐厅点餐服务”解释AOP的相关概念。2.1 核心故事一份油泼面️的旅程想象你去一家面馆点了一份油泼面。它的核心流程是你点餐 → 厨师烹饪 → 你享用。现在面馆为了提升体验和管理在核心流程前后加入了一些“通用服务”点餐前服务员确认你是VIP会员以决定是否赠送餐前冰封饮料。点餐后、烹饪前系统自动打印订单日志到后厨。烹饪后、上桌前厨师检查面有没有煮熟。你吃完后服务员邀请你进行满意度评价。核心思想煮面是“核心业务逻辑”而身份验证、日志、检查、评价这些都是“横切关注点”。AOP的作用就是在不改动“煮面”这段核心代码的情况下优雅地插入这些通用服务。2.2 AOP核心概念让我们把这个故事映射到AOP的各个概念上AOP 概念专业解释面馆通俗理解连接点 (Join Point)程序执行过程中一个明确的点如方法调用、异常抛出等。流程中所有可以插入服务的节点。例如点餐()、烹饪()、上菜()这些方法 被调用的【时刻】。切点 (Pointcut)一个表达式用来匹配和筛选你感兴趣的连接点。选择器。例如“匹配所有点餐()方法”或“匹配所有以process开头的方法”。它决定了 “通用服务” 要在哪里生效。通知 (Advice)在切点处执行的动作代码本身。通用服务的具体内容。例如“验证VIP身份”、“打印日志”这段代码逻辑。切面 (Aspect)切点 通知的完整结合体。它定义了“在何处切点执行何种操作通知”。一个完整的服务方案。例如“在点餐()方法执行前切点执行验证VIP()操作通知”这就是一个完整的切面。Aspect一个注解用来把一个普通的Java类声明为一个切面类。给一个服务方案团队Java类挂上牌子上面写着“我们是提供横切服务的”。Before一种通知类型注解表示该通知在目标方法执行之前运行。前置服务。例如“在厨师烹饪之前先打印订单日志”。AdvisorSpring AOP中更原始、更底层的切面表示。一个Advisor通常只包含一个通知 和 一个切点。一个最小化的、不可分割的服务指令。好比一张工单严格写着“仅当客户点油泼面时切点才在烹饪后做熟度检查通知”。它非常精准、直接。2.3 两种代码风格实现“餐厅切面”现在我们用两种风格来实现上述的“打印日志”切面在烹饪方法前打印。风格一基于Aspect注解现代、声明式、更常用这种方式像用高级语言描述需求。// 1. 声明这是一个切面类同时它也是一个Spring管理的BeanComponentAspectpublicclassRestaurantAspect{// 2. 定义切点匹配所有在 CookingService 类中的 cook 方法Pointcut(execution(* com.example.service.CookingService.cook(..)))publicvoidcookMethod(){}// 3. 定义通知并与切点绑定在烹饪方法执行前Before(cookMethod())publicvoidprintOrderLogBeforeCooking(){System.out.println([日志] 后厨收到订单开始烹饪...);// 这里可以拿到请求参数、方法名等信息实现复杂逻辑}// 其他通知AfterReturning(cookMethod())publicvoidcheckSteakDoneness(){System.out.println([质检] 检查油泼面熟了没...);}}看完这个类可以回过头再看一下上面的事务拦截器AOP。通俗理解你写了一个服务手册RestaurantAspect在里面用标签Before写明“在做饭这个环节之前要执行打印日志这个动作”。Spring 看到Aspect这个牌子后会自动帮你安排。风格二基于Advisor编程式配置底层、灵活、更精确这种方式更像直接编写部署指令。ConfigurationpublicclassRestaurantAdvisorConfig{BeanpublicAdvisorcookingLogAdvisor(){// 1. 创建通知Advice定义要做什么MethodBeforeAdvicelogAdvicenewMethodBeforeAdvice(){Overridepublicvoidbefore(Methodmethod,Object[]args,Objecttarget){System.out.println([Advisor日志] 准备烹饪食材: args[0]);}};// 2. 创建切点Pointcut定义在哪里做精确到方法名匹配NameMatchMethodPointcutpointcutnewNameMatchMethodPointcut();pointcut.addMethodName(cook);// 只匹配名为 cook 的方法// 也可以用 pointcut.setClassFilter() 来限制类// 3. 将通知和切点组装成最小的切面单元AdvisorreturnnewDefaultPointcutAdvisor(pointcut,logAdvice);}}通俗理解你直接发了一张精确的工单Advisor给系统。工单上明确指令“听着只有当一个方法名严格叫cook时切点才在它之前执行这个打印动作通知。”这个工单自成一体非常精准。核心关系与选择Aspect和Advisor是什么关系最终效果一致在运行时Spring都会把Aspect注解的切面转换成一个或多个内部的Advisor去执行。抽象层级不同Aspect是声明式的像写配置清单更符合人类思维一个类里可以定义很多相关通知。Advisor是编程式的API是Spring AOP的工作基石更底层、更灵活一个Advisor通常只做一件事。为什么两种都存在Aspect更简洁易用涵盖了90%的场景。但当需要极其精细的控制比如根据复杂条件动态决定是否应用通知或者与一些旧框架集成时直接使用Advisor这个底层API会更强大。我们可以通过Order确定切面的先后顺序然后在Spring的调度下完美合作共同增强业务方法而业务方法本身对此一无所知——这就是AOP的魅力。3. Transactional解释“定义一个Advisor绑定拦截器” 是一种编程式、集中配置的方式。使用 Transactional 注解是另一种声明式、分散标注的方式。但两者的终点完全相同都是为了让 TransactionInterceptor 来拦截方法并管理事务。当你使用 Transactional 注解时Spring Boot在启动阶段通过自动配置TransactionAutoConfiguration完成了一系列幕后工作其本质是自动创建了所需的Advisor。在spring中有这样一个源码Configuration(proxyBeanMethodsfalse)Role(BeanDefinition.ROLE_INFRASTRUCTURE)ImportRuntimeHints(TransactionRuntimeHints.class)publicclassProxyTransactionManagementConfigurationextendsAbstractTransactionManagementConfiguration{Bean(nameTransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)Role(BeanDefinition.ROLE_INFRASTRUCTURE)publicBeanFactoryTransactionAttributeSourceAdvisortransactionAdvisor(TransactionAttributeSourcetransactionAttributeSource,TransactionInterceptortransactionInterceptor){BeanFactoryTransactionAttributeSourceAdvisoradvisornewBeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource);advisor.setAdvice(transactionInterceptor);if(this.enableTx!null){advisor.setOrder(this.enableTx.IntegergetNumber(order));}returnadvisor;// 最终还是一个Advisor}BeanRole(BeanDefinition.ROLE_INFRASTRUCTURE)// 创建一个默认的事务拦截器// 这里的入参原本是 TransactionAttributeSource为了便于理解修改为 AnnotationTransactionAttributeSourcepublicTransactionInterceptortransactionInterceptor(AnnotationTransactionAttributeSourcetransactionAttributeSource){TransactionInterceptorinterceptornewTransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource);if(this.txManager!null){interceptor.setTransactionManager(this.txManager);}returninterceptor;}}整个流程可以概括为Transactional注解 → 被AnnotationTransactionAttributeSource解析为规则 → 与TransactionInterceptor一起被包装进BeanFactoryTransactionAttributeSourceAdvisor→ 该Advisor被应用到所有Bean的创建过程中。两种方式的直观对比为了让区别更清晰我们可以用下面的表格来对比这两种方式方面编程式AdvisorTransactional方式声明式配置核心在Configuration类中显式定义一个AdvisorBean。在方法或类上添加Transactional注解。规则定义在NameMatchTransactionAttributeSource中通过方法名模式匹配来定义规则。在注解的属性中直接定义规则如Transactional(readOnly true)。切点(Pointcut)显式指定如execution(* com.pro.service..*.*(..))。隐式生成切点逻辑是“匹配所有有Transactional注解的地方”。底层实现直接操控了Spring AOP最底层的Advisor、Advice、Pointcut三大件。利用了Spring的自动配置和EnableTransactionManagement在底层帮我们创建了Advisor。优点集中管理规则一目了然与业务代码完全解耦适合基于方法名的批量规则。使用简单贴近业务逻辑粒度更细可以针对单个方法特殊配置是Spring生态的标准做法。缺点不够灵活如果某个方法需要例外规则如REQUIRES_NEW很难单独配置。注解分散在代码各处对业务代码有侵入性无法根据方法名等动态规则批量处理。5. 结论与选择TransactionInterceptor始终在工作无论你用哪种方式最终都是TransactionInterceptor这个“事务引擎”在执行拦截和管理。区别只在于“启动引擎的开关”是编程式装配的Advisor还是由注解触发的自动装配Advisor。可以混合使用但需谨慎Spring允许两者共存。如果绝大多数方法遵循统一规则但极个别方法需要特殊事务行为比如一个特殊的handlePayment方法需要REQUIRES_NEW你可以在那个方法上单独添加Transactional(propagation Propagation.REQUIRES_NEW)。编程式配置的规则是全局的而Transactional注解的规则是局部的局部注解通常会覆盖全局规则。