spring使用基于注解的AOP事务管理
掌握常用框架的基本用法与应用场景
掌握常用框架的基本用法与应用场景常用框架的基本用法和应用场景可以根据具体的框架来进行讨论。
以下是几个常用框架的基本用法和应用场景。
1. Spring框架:Spring是一个轻量级的Java开发框架,提供了一站式的解决方案,包括依赖注入、AOP、事务管理、Web开发等。
在Spring框架中,可以通过注解或XML配置来管理各个组件之间的依赖关系,并利用Spring的IOC容器来管理对象的生命周期。
应用场景包括Web应用开发、企业应用开发、中小型项目开发等。
2. Hibernate框架:Hibernate是一个Java持久化框架,它提供了将Java对象映射到数据库表的解决方案。
通过Hibernate,开发人员可以简化数据库操作,使用面向对象的方式来进行数据库访问,提高开发效率。
应用场景包括ORM映射、事务管理、性能优化等。
3. Django框架:Django是一个基于Python的Web开发框架,致力于提供高效的、安全的Web应用程序开发解决方案。
它采用了MTV (Model-Template-View)的设计模式,通过模型(Model)与数据库交互,通过模板(Template)生成HTML页面,通过视图(View)处理用户请求。
应用场景包括Web应用开发、数据分析平台搭建等。
4. React框架:React是一个用于构建用户界面的JavaScript库,它提供了高效的组件化开发方式,通过虚拟DOM的技术实现了高性能的界面渲染。
React可以与其他框架或库(如Redux、React Router)结合使用,用于构建单页应用、移动应用等。
应用场景包括前端开发、跨平台移动应用开发等。
除了以上几个框架,还有许多其他常用框架,如Angular、Vue.js、Express等,它们都有各自的特点和适用场景。
掌握这些常用框架的基本用法和应用场景,可以帮助开发人员更高效地进行软件开发,提高开发质量和效率。
此外,不仅要掌握框架的基本用法,还要提升自己的拓展能力,如深入学习框架的源码、参与开源社区、阅读相关的技术文章和书籍等,才能更好地应对各种应用场景和解决复杂问题。
基于SpringBootAOP与自定义注解转义字典值
基于SpringBootAOP与自定义注解转义字典值要基于SpringBoot、AOP和自定义注解来转义字典值,可以按照以下步骤进行:1.创建一个字典表,存储字典值和对应的转义值。
例如,可以创建一个数据库表或者在配置文件中定义一个字典映射关系。
4.在切面方法中,获取需要转义的字段的值,然后根据字典表中的映射关系,找到对应的转义值,并将转义值设置回字段。
5.在需要使用转义值的地方,直接使用被转义后的字段值即可。
下面是一个简单的示例代码:1.创建字典表,例如在配置文件中定义:```yamldict.mapping:gender:0:男1:女``````javaString value( default "";```3.创建AOP切面类:```javapublic class DictTransAspectprivate DictMapping dictMapping;public Object dictTrans(ProceedingJoinPoint joinPoint) throws ThrowableObject result = joinPoint.proceed(;//获取被标记的字段或方法Field field =ReflectionUtils.findField(joinPoint.getTarget(.getClass(, ((MethodSignature) joinPoint.getSignature().getName();DictTrans dictTrans = field.getAnnotation(DictTrans.class);if (dictTrans != null)//获取字段值Object value = field.get(joinPoint.getTarget();//获取字段的字典映射关系Map<String, String> mapping =dictMapping.getMapping(dictTrans.value();//根据字典映射关系转义字段值String transValue = mapping.get(value.toString();//设置转义值回字段field.set(joinPoint.getTarget(, transValue);}return result;}``````javapublic class Userprivate Integer gender;// getter and setter```5.在业务中使用转义后的字段值:```javapublic class UserService// 注入 UserMapper 或者其他数据访问层public User getUserById(String id)User user = userMapper.findById(id);System.out.println(user.getGender(); // 输出转义后的值,例如输出 "男"return user;}```这样,就实现了基于 SpringBoot、AOP 和自定义注解来转义字典值的功能。
关于Spring事务的原理,以及在事务内开启线程,连接池耗尽问题.
关于Spring事务的原理,以及在事务内开启线程,连接池耗尽问题.主要以结果为导向解释Spring 事务原理,连接池的消耗,以及事务内开启事务线程要注意的问题.Spring 事务原理这⾥不多说,⽹上⼀搜⼀⼤堆,也就是基于AOP配合ThreadLocal实现.这⾥强调⼀下Spring Aop 以及Spring 注解式注⼊在⾮Spring容器管理的类中是⽆效的.因为Spring Aop是在运⾏时实现字节码增强,字节码增强有多种实现⽅法,请⾃⾏了解,原⽣AspectJ是编译时织⼊,但是需要特定的编译器.语法并没有Spring Aop好理解.先看下Spring的事务传播⾏为类型事务传播⾏为类型说明PROPAGATION_REQUIRED如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。
这是最常见的选择。
PROPAGATION_SUPPORTS⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。
PROPAGATION_MANDATORY使⽤当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执⾏。
如果当前没有事务,则执⾏与 PROPAGATION_REQUIRED类似的操作。
打开⽇记debug模式,留意控制台输出以下测试为了可读性以及更容易理解全是基于Spring注解式事务,⽽没有配置声明式事务.测试1:可以看见只创建了⼀个SqlSession以及⼀个事务,在⽅法内所有操作都使⽤同⼀个连接,同⼀个事务@RequestMapping(value="/testThreadTx",method = RequestMethod.GET)@Transactional(propagation = Propagation.REQUIRED)public void testThreadTx(){//此⽅法没有事务(当前⽅法是 Propagation.REQUIRED)Quotation quotation = quotationService.findEntityById(new String("1"));//此⽅法没有事务(当前⽅法是 Propagation.REQUIRED)quotationService.updateEntity(quotation);}//查看控制台输出(红字关键部分,第三个查询是更新⽅法内部需要先查询⼀次再更新,可以⽆视)Creating a new SqlSessionRegistering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]ansaction(line/:54) -JDBC Connection [1068277098(com.mysql.jdbc.JDBC4Connection@5d92bace)] will be managed by SpringotationMapper.findEntityById(line/:54) -==> Preparing: SELECT * FROM table WHERE id = 1otationMapper.findEntityById(line/:54) -==> Parameters:otationMapper.findEntityById(line/:54) -<== Total: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4] from current transactionReleasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4] from current transactionotationMapper.updateEntity(line/:54) -==> Preparing: update ….. where id = 1otationMapper.updateEntity(line/:54) -==> Parameters:otationMapper.updateEntity(line/:54) -<== Updates: 1Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]erOperationLogServiceImpl(line/:41) -请求所⽤时间:207erOperationLogServiceImpl(line/:42) -请求结束*******************************************************************************Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@230376b4]测试2:不使⽤事务可以看出在⾮事务操作数据库,会使⽤多个连接,⾮常不环保,这⾥给稍微多线程插⼊埋下⼀个陷阱@RequestMapping(value="/testThreadTx",method = RequestMethod.GET)// @Transactional(propagation = Propagation.REQUIRED)public void testThreadTx(){Quotation quotation = quotationService.findEntityById(new String("1"));quotationService.updateEntity(quotation);}//查看控制台输出(红字关键部分,第三个查询是更新⽅法内部需要先查询⼀次再更新,可以⽆视)Creating a new SqlSessionSqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7f7b94f] was not registered for synchronization because synchronizationansaction(line/:54) -JDBC Connection [352410768(com.mysql.jdbc.JDBC4Connection@c63fcb6)] will not be managed by SpringotationMapper.findEntityById(line/:54) -==> Preparing: SELECT * FROM table WHERE id = 1otationMapper.findEntityById(line/:54) -==> Parameters:otationMapper.findEntityById(line/:54) -<== Total: 1Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7f7b94f]Creating a new SqlSessionSqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a41785a] was not registered for synchronization because synchronizationansaction(line/:54) -JDBC Connection [1615108970(com.mysql.jdbc.JDBC4Connection@38377d86)] will not be managed by SpringotationMapper.findEntityById(line/:54) -==> Preparing: SELECT * FROM table WHERE id = 1otationMapper.findEntityById(line/:54) -==> Parameters:otationMapper.findEntityById(line/:54) -<== Total: 1Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7a41785a]Creating a new SqlSessionSqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@181e5a22] was not registered for synchronization because synchronizationansaction(line/:54) -JDBC Connection [2096339748(com.mysql.jdbc.JDBC4Connection@5d4e9892)] will not be managed by SpringotationMapper.updateEntity(line/:54) -==> Preparing: update …. where id = 1otationMapper.updateEntity(line/:54) -==> Parameters:otationMapper.updateEntity(line/:54) -<== Updates: 1Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@181e5a22]erOperationLogServiceImpl(line/:41) -请求所⽤时间:614erOperationLogServiceImpl(line/:42) -请求结束*******************************************************************************测试3:@RequestMapping(value="/testThreadTx",method = RequestMethod.GET)@Transactional(propagation = Propagation.REQUIRED)public void testThreadTx(){final ExecutorService executorService = Executors.newFixedThreadPool(3);Quotation quotation = quotationService.findEntityById(new String("1"));quotationService.updateEntity(quotation);List<Future<Integer>> futures = new ArrayList<Future<Integer>>(3);for(int i=0;i<3;i++){Callable<Integer> task = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {Quotation quotation = quotationService.findEntityById(new String("1"));quotationService.updateEntity(quotation);return null;}};futures.add(executorService.submit(task));}executorService.shutdown();}//查看控制台输出(红字关键部分,第三个查询是更新⽅法内部需要先查询⼀次再更新,可以⽆视)为了节篇幅,这⾥不贴出控制台数据⼤概就是输出了10个Creating a new SqlSession(⼤概有些同学使⽤了多线程,把线程池耗完了也没弄明⽩原因)外层⽅法启动⼀个,内部3个线程,每个线程3个.⼀共是使⽤了10个连接.为什么?这涉及到ThreadLocal以及线程私有栈的概念.如果Spring 事务使⽤InhertableThreadLocal就可以把连接传到⼦线程,但是为什么Spring不那么⼲呢?因为这样毫⽆意义,如果把同⼀个连接传到⼦线程,那就是SQL操作会串⾏执⾏,那何必还多线程呢?有关于ThreadLocal,InhertableThreadLocal配合线程池的⼀些陷阱请看我另⼀篇⽂章:测试4:既然使⽤同⼀个事务,不能实现并发操作,那么只能折中,在每⼀个线程开启⼀个事务,减少创建更多的连接,执⾏完毕以后可以返回操作成功失败结果,反馈给⽤户@RequestMapping(value="/testThreadTx",method = RequestMethod.GET)// @Transactional(propagation = Propagation.REQUIRED)public void testThreadTx(){ExecutorService executorService = Executors.newFixedThreadPool(3);List<Future<Integer>> futures = new ArrayList<Future<Integer>>(3);for(int i=0;i<3;i++){Callable<Integer> task = new Callable<Integer>() {@Overridepublic Integer call() throws Exception {quotationService.doSomeThing();return null;}};futures.add(executorService.submit(task));}executorService.shutdown();}//封装⼀下@Override@Transactional(propagation =Propagation.REQUIRED)public void doSomeThing(){Quotation quotation = this.findEntityById(new String("1"));this.updateEntity(quotation);}//查看控制台输出,只会创建3个连接,为节省篇幅,这⾥不贴出控制台所有数据Creating a new SqlSessionCreating a new SqlSessionCreating a new SqlSession最后⼩技巧PROPAGATION_NOT_SUPPORTED(仅仅为了让Spring能获取ThreadLocal的connection),如果不使⽤事务,但是同⼀个⽅法多个对数据库操作,那么使⽤这个传播⾏为可以减少消耗数据库连接@RequestMapping(value="/testThreadTx",method = RequestMethod.GET)@Transactional(propagation = Propagation.NOT_SUPPORTED)public void testThreadTx(){Quotation quotation = quotationService.findEntityById(new String("1"));quotation.setStatus(ClassDataManager.STATE_N);quotationService.updateEntity(quotation);}//这样只会创建⼀个SqlSession。
SpringAOP的原理和应用场景
SpringAOP的原理和应用场景SpringAOP(Aspect-Oriented Programming)是Spring框架中的一个重要组成部分,它提供了一种通过预定义的方式,将横切关注点(Cross-cutting Concerns)与业务逻辑进行解耦的机制。
本文将介绍SpringAOP的原理及其在实际应用场景中的应用。
一、SpringAOP的原理SpringAOP基于代理模式(Proxy Pattern)实现。
在SpringAOP中,通过生成与原始类(被代理类)具有相同接口的代理类,将横切逻辑编织到业务逻辑中。
在运行时,当调用代理类的方法时,会在方法执行前、后或异常抛出时插入相应的横切逻辑代码。
具体而言,SpringAOP使用了以下几个核心概念:1. 切面(Aspect):切面是横切逻辑的模块化单元,它包含了一组通知(Advice)和切点(Pointcut)。
2. 通知(Advice):通知定义了实际的横切逻辑代码,并规定了何时执行该代码。
SpringAOP提供了五种类型的通知:前置通知(Before)、后置通知(After)、返回通知(After-returning)、异常通知(After-throwing)和环绕通知(Around)。
3. 切点(Pointcut):切点指定了在哪些连接点(Join Point)上执行通知。
连接点可以是方法调用、属性访问等程序执行的点。
4. 连接点(Join Point):连接点是程序执行过程中的一个特定点,如方法调用前、方法调用后等。
通知通过切点来选择连接点。
5. 织入(Weaving):织入是将切面应用到目标对象,并创建代理对象的过程。
织入可以在编译时、类加载时或运行时进行。
二、SpringAOP的应用场景SpringAOP可应用于各种场景,用于解决跨越多个模块或类的横切关注点问题。
以下是一些常见的SpringAOP应用场景:1. 日志记录:通过在关键方法的前后插入日志代码,实现对系统运行状态的监控和记录。
aop的原理应用
AOP的原理应用1. 什么是AOPAOP(Aspect-Oriented Programming)是面向切面编程的缩写,它是一种能够通过解耦的方式将横切性关注点模块化的编程范式。
传统的面向对象编程(OOP)主要是通过类和对象来划分和组织代码,但当系统变得复杂时,代码中常常散布着一些与主要业务逻辑无关的、可复用的逻辑(比如日志记录、安全控制、事务管理等),这就导致了代码的重复和耦合度的增加。
而AOP可以通过将这些横切逻辑(称为切面)与主要业务逻辑分离,从而提高代码的可维护性、可测试性和可复用性。
2. AOP的原理AOP的核心原理是在编译期、加载期或运行期利用动态代理技术来实现切面的织入。
具体来说,AOP框架会在目标对象的方法调用前后或者异常抛出时,插入横切逻辑(切面),从而实现对目标对象的增强。
其中,横切逻辑通过切面由切点和增强组成。
•切点:定义了在何处插入切面的准则,比如可以根据类名、方法名或注解等进行精确定位。
•增强:指的是横切逻辑的实现,比如可以在方法调用前后执行某些操作。
织入过程可以通过前置织入、后置织入等方式来实现。
3. AOP的应用场景AOP的特点使得它在很多场景下都能够发挥作用,以下列举了几个常见的应用场景:•日志记录:AOP可以很方便地将日志记录逻辑与主要业务逻辑分离,从而使得代码更加清晰、易于维护。
例如,可以利用AOP在方法调用前后记录方法的输入参数和返回结果。
•安全控制:通过AOP可以在方法调用前进行身份验证、权限检查等安全控制逻辑,从而确保系统的安全性。
•事务管理:AOP可以在方法调用前后添加事务管理逻辑,保证数据的一致性和完整性。
例如,可以在方法调用前开启事务,在方法调用后提交或回滚事务。
•性能监控:利用AOP可以在方法调用前后统计方法的执行时间、请求次数等,通过监控这些性能指标可以优化系统的性能。
•异常处理:AOP可以在方法抛出异常时进行异常处理逻辑,并且可以根据异常类型进行不同的处理。
spring事务原理
spring事务原理数据库系统内,事务指一系列连续的操作,这系列操作被看作一个整体,要么完全执行,要么完全不执行,不会出现执行部分的情况,这是数据库系统的基本特征之一。
在传统数据库系统中,事务的管理是由数据库系统自身提供的一种功能,然而随着数据库系统的复杂性的增加,数据库中的事务管理越来越复杂,对数据库操作有更多的要求,这样就催生了应用层事务管理技术,而当前最流行的事务管理技术是Spring事务。
Spring事务是一种基于AOP(面向切面编程)的分布式事务管理技术,它能够帮助系统更好的控制事务的处理过程,从而使系统内的数据更加有效率的共享,降低数据库事务的管理复杂度,提高数据库系统的可用性及性能。
Spring事务原理包括几个要素:事务模型、分布式事务处理框架、事务实现机制以及事务管理工具等。
一、事务模型Spring事务原理的核心是事务模型,即它把事务分为两种:提交成功事务和失败事务,在Spring提供的事务模型中,每个事务都只有两种结果,要么提交成功,要么提交失败,而不存在半提交的状态。
在Spring的事务模型中,事务的分类还要求事务的原子性,它要求一旦提交事务,事务就不会再次改变,或者改变的程度会很小。
原子性还表明事务的执行要么完全成功,要么完全失败,不会出现半成功半失败的情况。
二、分布式事务处理框架Spring提供了基于AOP技术的分布式事务处理框架,这种分布式事务处理框架能够有效地支持不同数据库之间的事务处理,它包括三个部分:事务管理器(TransactionManager)、事务拦截器(TransactionInterceptor)和事务事件监听器(TransactionListener)。
事务管理器是Spring对分布式事务的抽象,它可以处理不同类型的事务,它的实现通常会涉及到一些事务拦截器。
事务拦截器是Spring提供的一种安全机制,它能够在事务处理过程中,根据配置的规则,来拦截事务的执行,以便能够在事务处理过程中发现任何可能存在的问题,并对其进行调整,使得事务能够顺利的提交。
MyBatis-Spring-TransactionManager事务管理
</property>
</bean>
编程式事务管理
MyBatis 的 SqlSession 提供指定的方法来处理编程式的事务。 但是当使用 MyBatis-Spring 时, bean 将会使用 Spring 管理的 SqlSession 或映射器来注入。 那就是说 Spring 通常是处理 事务的。
一旦事务创建之后,MyBatis-Spring 将会透明的管理事务。在你的 DAO 类中就不需要额 外的代码了。
标准配置
要 开 启 Spring 的 事 务 处 理 , 在 Spring 的 XML 配 置 文 件 中 简 单 创 建 一 个 DataSourceTransactionManager 对象:
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
</bean>
指定的 DataSource 一般可以是你使用 Spring 的任意 JDBC DataSource。这包含了连接 池和通过 JNDI 查找获得的 DataSource。
要注意, 为事务管理器指定的 DataSource 必须和用来创建 SqlSessionFactoryBean 的 是同一个数据源,否则事务管理器就无法工作了。
transactional注解的实现原理
transactional注解的实现原理
Transaction注解的实现原理是使用AOP技术,实现对方法的增强,对加上注解的方法进行事务管理。
实现过程如下:
1. 首先在spring的配置文件中声明一个事务管理器(TransactionManager),这个管理器会在Spring容器启动时初始化。
2. 在需要进行事务管理的方法上加上@Transactional注解,这
个注解就代表这个方法需要进行事务管理。
3. Spring在扫描带有@Transactional注解的方法时,会使用AOP技术生成一个代理对象,这个代理对象增强了原始方法的功能。
4. 代理对象会在方法前后执行一些特定的操作,主要包括在方
法执行前开启事务,方法执行完成后根据方法执行结果决定是否提交
或回滚事务。
5. 如果方法执行成功,代理对象会提交事务。
如果方法执行失败,则代理对象会回滚事务。
如果出现异常,代理对象也会回滚事务。
6. 最后,代理对象调用完方法后,会被销毁,原始方法依然存在。
通过这种方式,@Transactional注解提供了简单易用的事务管理方式。
在实际应用中,我们只需要在需要事务的方法上加上注解,就
可以实现事务管理,非常方便。
使用SpringAOP和自定义注解统一API返回值格式
使⽤SpringAOP和⾃定义注解统⼀API返回值格式摘要:统⼀接⼝返回值格式后,可以提⾼项⽬组前后端的产出⽐,降低沟通成本。
因此,在借鉴前⼈处理⽅法的基础上,通过分析资料,探索建⽴了⼀套使⽤Spring AOP和⾃定义注解⽆侵⼊式地统⼀返回数据格式的⽅法。
§前⾔ 我们封装所有的Controller中接⼝返回结果,将其处理为统⼀返回数据结构后,可以提⾼前后端对接效率,降低沟通成本。
⽽使⽤Spring AOP和⾃定义注解⽆侵⼊式地统⼀返回数据格式,则可以避免在每⼀个api上都处理返回格式,从⽽使后端开发节约开发时间,更加专注于开发业务逻辑。
后端返回给前端的⾃定义返回格式如下:{"code":200,"message":"OK","data":{}}其中的三个参数的含义如下:code: 返回状态码;message: 返回信息的描述;data: 返回值。
§直接修改API返回值类型 Spring AOP和⾃定义注解的基本概念可以分别参考《》和《》。
下⾯定义返回数据格式的封装类:package com.eg.wiener.config.result;import lombok.Getter;import lombok.ToString;import java.io.Serializable;@Getter@ToStringpublic class ResultData<T> implements Serializable {private static final long serialVersionUID = 4890803011331841425L;/** 业务错误码 */private Integer code;/** 信息描述 */private String message;/** 返回参数 */private T data;private ResultData(ResultStatus resultStatus, T data) {this.code = resultStatus.getCode();this.message = resultStatus.getMessage();this.data = data;}/** 业务成功返回业务代码和描述信息 */public static ResultData<Void> success() {return new ResultData<Void>(ResultStatus.SUCCESS, null);}/** 业务成功返回业务代码,描述和返回的参数 */public static <T> ResultData<T> success(T data) {return new ResultData<T>(ResultStatus.SUCCESS, data);}/** 业务成功返回业务代码,描述和返回的参数 */public static <T> ResultData<T> success(ResultStatus resultStatus, T data) {if (resultStatus == null) {return success(data);}return new ResultData<T>(resultStatus, data);}/** 业务异常返回业务代码和描述信息 */public static <T> ResultData<T> failure() {return new ResultData<T>(ResultStatus.INTERNAL_SERVER_ERROR, null);/** 业务异常返回业务代码,描述和返回的参数 */public static <T> ResultData<T> failure(ResultStatus resultStatus) {return failure(resultStatus, null);}/** 业务异常返回业务代码,描述和返回的参数 */public static <T> ResultData<T> failure(ResultStatus resultStatus, T data) {if (resultStatus == null) {return new ResultData<T>(ResultStatus.INTERNAL_SERVER_ERROR, null);}return new ResultData<T>(resultStatus, data);}}=== 我是分割线 ===package com.eg.wiener.config.result;import lombok.Getter;import lombok.ToString;import org.springframework.http.HttpStatus;@ToString@Getterpublic enum ResultStatus {SUCCESS(HttpStatus.OK.value(), "OK"),BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "Bad Request"),INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Internal Server Error"), TOO_MANY_REQUESTS(HttpStatus.TOO_MANY_REQUESTS.value(), "请勿重复请求"),USER_NOT_FIND(-99, "请登陆");/*** 业务状态码*/private Integer code;/*** 业务信息描述*/private String message;ResultStatus(Integer code, String message) {this.code = code;this.message = message;}} 在UserController类中添加测试函数,其返回值直接使⽤上⾯定义的ResultData:/*** @author Wiener*/@RestController@RequestMapping("/user")public class UserController {private static Logger logger = LoggerFactory.getLogger(UserController.class);/*** ⽰例地址 xxx/user/getResultById?userId=1090330** @author Wiener*/@GetMapping(value ="/getResultById", produces = "application/json; charset=utf-8")public ResultData getResultById(Long userId) {User user = new User();user.setId(userId);user.setAddress("测试地址是 " + UUID.randomUUID().toString());(user.toString());return ResultData.success(user);}} 启动项⽬,在浏览器中输⼊URL,得到如下结果:{"code":200,"message":"OK","data":{"id":1090330,"userName":null,"age":null,"address":"测试地址是 f057181c-e7e2-41ec-9066-0e72619f0f86","mobilePhone":null} 说明已经成功定义返回数据格式,但是,这⾥并没有使⽤⾃定义注解和Spring AOP这两个知识点。
spring的意思
spring的意思Spring的意思Spring是一种开源的、轻量级的、全栈的Java应用开发框架。
它是基于IoC(Inversion of Control)和AOP(Aspect-Oriented Programming)的编程模型,旨在简化企业级应用程序的开发。
首先,Spring的“意思”可以从字面上理解为春天的意思。
春天象征着新生、希望与活力。
同样,Spring框架为Java应用程序注入了新的活力与创造力,使得开发人员能够更加轻松地构建高效、可靠的应用程序。
Spring框架的核心特点是IoC和AOP:1. IoC(Inversion of Control):传统的编程模型中,应用程序的各个组件之间通常直接进行耦合。
而Spring采用IoC容器,将对象的依赖关系交由容器进行管理,通过配置文件或注解将对象之间的依赖关系进行解耦。
开发者只需关注业务逻辑的实现,而无需关心对象的创建和销毁,大大简化了开发流程。
2. AOP(Aspect-Oriented Programming):AOP是一种编程范式,与IoC相辅相成。
通过AOP,开发者可以将一些与业务逻辑无关但又需要在多个对象中复用的功能(如日志记录、性能监测等)进行横向抽取,并通过切面(Aspect)的方式进行集中管理。
Spring框架提供了强大的AOP支持,能够在不修改原有代码的情况下,动态地向程序中插入额外的功能。
Spring框架的设计理念是“面向接口编程”,它鼓励开发者通过接口定义业务逻辑,借助IoC容器将不同的实现进行组装。
这种松耦合的设计方式使得应用程序更加灵活、易于维护和扩展。
除了IoC和AOP,Spring框架还提供了许多其他功能和模块,方便开发者构建各种不同类型的应用程序:1. 数据访问层:Spring提供了对各种数据访问技术的支持,包括JDBC、ORM(如Hibernate)、NoSQL数据库等。
通过Spring的事务管理,开发者可以轻松地控制数据库事务,确保数据一致性。
Spring声明式事务注解之@EnableTransactionManagement解析
Spring声明式事务注解之@EnableTransactionManagement解析Spring声明式事务注解之@EnableTransactionManagement1. 说明@EnableTransactionManagement声明在主配置类上,表⽰开启声明式事务,其原理是通过@Import导⼊TransactionManagementConfigurationSelector组件,然后⼜通过TransactionManagementConfigurationSelector导⼊组件AutoProxyRegistrar和ProxyTransactionManagementConfiguration;2. 原理分析@EnableTransactionManagement代码实现如下:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented// 通过@Import导⼊TransactionManagementConfigurationSelector组件@Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement {boolean proxyTargetClass() default false;AdviceMode mode() default AdviceMode.PROXY;int order() default Ordered.LOWEST_PRECEDENCE;}@EnableTransactionManagement通过@Import导⼊TransactionManagementConfigurationSelector;TransactionManagementConfigurationSelector的实现如下:public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {/*** {@inheritDoc}* @return {@link ProxyTransactionManagementConfiguration} or* {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and* {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively*/@Overrideprotected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:// 根据@EnableTransactionManagement的固定值PROXY,这⾥会导⼊AutoProxyRegistrar组件和ProxyTransactionManagementConfiguration组件 return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};default:return null;}}}所以TransactionManagementConfigurationSelector⼜导⼊了组件AutoProxyRegistrar和ProxyTransactionManagementConfiguration;3. AutoProxyRegistrar分析3.1 AutoProxyRegistrar继承关系InfrastructureAdvisorAutoProxyCreator--AbstractAdvisorAutoProxyCreator--AbstractAdvisorAutoProxyCreator--ProxyProcessorSupport--SmartInstantiationAwareBeanPostProcessor // 跟AOP是原理是⼀样的--InstantiationAwareBeanPostProcessor--BeanPostProcessor--BeanFactoryAware3.2 AutoProxyRegistrar的所⽤AutoProxyRegistrar的作⽤跟AOP中的AnnotationAwareAspectJAutoProxyCreator是⼀样的,利⽤后置处理器机制在对象创建以后,包装对象,返回⼀个代理对象(增强器),代理对象执⾏⽅法利⽤拦截器链进⾏调⽤;InfrastructureAdvisorAutoProxyCreator继承SmartInstantiationAwareBeanPostProcessor,跟AOP的原理是⼀样的,也是通过@Transactional作为⽅法拦截的标记,把有事务管理的类作为⽬标类,⽣成代理对象,然后增强@Transactional标记的⽅法,在使⽤⽬标⽅法的时候,从IOC容器中获取的其实是被增强的代理类,且事务⽅法会被代理,跟AOP原理⼀样的;4. ProxyTransactionManagementConfiguration分析ProxyTransactionManagementConfiguration是⼀个配置类,想IOC容器中导⼊事务增强器(BeanFactoryTransactionAttributeSourceAdvisor),事务注解@Transactional的解析器(AnnotationTransactionAttributeSource)和事务⽅法拦截器(TransactionInterceptor);package org.springframework.transaction.annotation;import org.springframework.beans.factory.config.BeanDefinition;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Role;import org.springframework.transaction.config.TransactionManagementConfigUtils;import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;import org.springframework.transaction.interceptor.TransactionAttributeSource;import org.springframework.transaction.interceptor.TransactionInterceptor;@Configurationpublic class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {/**事务增强器(Advisor),在事务类创建的时候,被AutoProxyRegistrar导⼊的组件InfrastructureAdvisorAutoProxyCreator拦截,InfrastructureAdvisorAutoProxyCreator拦截的逻就是增强事务类的事务⽅法,⽽BeanFactoryTransactionAttributeSourceAdvisor作为增强器,与需要增强的⽅法(这⾥是指被@Transactional标记的⽅法)进⾏匹配,匹配成功的增强器,最后转成拦截器(MethodInterceptor,就是下⾯的TransactionInterceptor),然后与⽬标⽅法⼀起在拦截器链中被执⾏,达到⽅法增强的效果;BeanFactoryTransactionAttributeSourceAdvisor的继承关系如下:BeanFactoryTransactionAttributeSourceAdvisor--AbstractBeanFactoryPointcutAdvisor--AbstractPointcutAdvisor--PointcutAdvisor--AdvisorAOP中AspectJPointcutAdvisor的继承关系如下,与AbstractPointcutAdvisor⼀样,都实现PointcutAdvisor--AspectJPointcutAdvisor--PointcutAdvisor--Advisor*/@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource());advisor.setAdvice(transactionInterceptor());advisor.setOrder(this.enableTx.<Integer>getNumber("order"));return advisor;}/**@Transactional注解的解析类;负责解析事务⽅法上@Transactional中的各个参数配置,解析的时机是在创建事务类之后被增强的时候,匹配事务⽅法的时候⼀起被解析了AnnotationTransactionAttributeSource的继承关系如下:AnnotationTransactionAttributeSource--AbstractFallbackTransactionAttributeSource--TransactionAttributeSource通过⽅法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(Method, Class<?>)解析出事务信息TransactionAttribute;AnnotationTransactionAttributeSource在⽅法findTransactionAttribute(Class<?>)中依赖于SpringTransactionAnnotationParser在解析事务类时,绑定事务⽅法与增强器的时候进⾏@Transactional注解解析;*/@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}/**被@Transactional标记的事务⽅法的拦截器,实际是⼀个MethodInterceptor保存了事务属性信息,事务管理器;在⽬标⽅法执⾏的时候;执⾏拦截器链;*/@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor() {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource());if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}}在SpringTransactionAnnotationParser中parseTransactionAnnotation⽅法来解析@Transactional中的各个参数,其具体代码如下:protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();Propagation propagation = attributes.getEnum("propagation");rbta.setPropagationBehavior(propagation.value());Isolation isolation = attributes.getEnum("isolation");rbta.setIsolationLevel(isolation.value());rbta.setTimeout(attributes.getNumber("timeout").intValue());rbta.setReadOnly(attributes.getBoolean("readOnly"));rbta.setQualifier(attributes.getString("value"));ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();Class<?>[] rbf = attributes.getClassArray("rollbackFor");for (Class<?> rbRule : rbf) {RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);rollBackRules.add(rule);}String[] rbfc = attributes.getStringArray("rollbackForClassName");for (String rbRule : rbfc) {RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);rollBackRules.add(rule);}Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");for (Class<?> rbRule : nrbf) {NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);rollBackRules.add(rule);}String[] nrbfc = attributes.getStringArray("noRollbackForClassName");for (String rbRule : nrbfc) {NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);rollBackRules.add(rule);}rbta.getRollbackRules().addAll(rollBackRules);return rbta;}spring 事务 @EnableTransactionManagement原理@EnableXXX原理:注解上有个XXXRegistrar,或通过XXXSelector引⼊XXXRegistrar,XXXRegistrar实现了ImportBeanDefinitionRegistrar的registerBeanDefinitions⽅法,给容器注册XXXCreator。
spring事务详解(基于注解和声明的两种实现方式)
spring事务详解(基于注解和声明的两种实现⽅式)Spring事务( Transaction )事务的概念事务是⼀些sql语句的集合,作为⼀个整体执⾏,⼀起成功或者⼀起失败。
使⽤事务的时机⼀个操作需要多天sql语句⼀起完成才能成功程序中事务在哪⾥说明加在业务类的⽅法上⾯(public⽅法上⾯),表⽰业务⽅法执⾏时,需要事务的⽀持。
不同的事务管理器不同的数据库访问技术,处理事务是不同的1. 使⽤jdbc访问数据库,事务处理public void updateAccount(){Connection con = .....;con.setAutoCommit(false);state.insert();state.update();mit();con.setAutoCommit(true);}2. MyBatis执⾏数据库,处理事务public void updateAccount(){SqlSession sqlSession = SqlSessionFactory.openSession(false);try{sqlSession.insert(...);sqlSession.update(...);mit();}catch(Exception e){sqlSession.rollback();}}spring统⼀管理事务,把不同的数据库访问技术的事务处理统⼀起来使⽤spring的事务管理器,管理不同数据库访问技术的事务处理。
开发⼈员只需要掌握spring的事务处理⼀个⽅案,就可以实现使⽤不同数据库访问技术的事务管理。
尽管事务⾯向的是spring,有spring管理事务,做事务提交和回滚。
spring事务管理器spring框架使⽤事务管理器对象,管理所有的事务。
事务管理器接⼝: PlatFormTransactionManager作⽤:定义了事务的操作,主要是commit() , rollback()事务管理器有很多的实现类:⼀种数据库访问计数有⼀个实现类。
AOP事务管理的原理与及三种实现方式
AOP事务管理的原理与及三种实现方式AOP(Aspect-Oriented Programming)即面向切面编程,是一种软件开发方法,主要用于解决分散在一个应用程序中的横切关注点(cross-cutting concerns)问题。
事务管理是AOP的一个典型应用场景,它主要用于保证一系列操作的原子性、一致性和隔离性。
本文将详细介绍AOP事务管理的原理以及三种常见的实现方式。
一、AOP事务管理原理1.拦截器执行顺序首先,AOP框架通过拦截器机制,将事务相关的拦截器按照一定的顺序进行执行。
常见的拦截器有前置拦截器(Before)、后置拦截器(After)、异常拦截器(AfterThrowing)、返回拦截器(AfterReturning)等。
2.事务传播和隔离级别在方法级别的事务管理中,每个被拦截的方法可以有不同的事务传播行为和隔离级别。
事务传播行为指的是当一个方法调用另外一个方法时,如何处理事务;隔离级别指的是事务之间的隔离程度。
3.事务切面的应用通过拦截器机制,将事务注解或者配置文件中的事务属性传递给事务管理器,然后由事务管理器根据事务属性进行事务操作。
实际应用中,可以使用Spring框架提供的AOP事务管理功能来实现对方法级别的事务控制。
根据AOP事务管理的原理,常见的AOP事务管理的实现方式有基于注解的方式、基于XML配置的方式和基于编程的方式。
1.基于注解的方式优点:(1)简单方便,只需在方法上加上注解即可进行事务管理。
(2)灵活可控,通过注解可以更细粒度地控制事务的传播行为和隔离级别。
(3)清晰明了,注解能够直观地体现出事务的特性。
缺点:(1)侵入性较强,需要在代码中添加注解。
(2)不能对第三方库中的方法进行事务管理。
2.基于XML配置的方式基于XML配置的方式是通过在配置文件中定义事务管理器、事务通知以及切点表达式等信息,来实现对方法级别的事务控制。
通过AOP框架读取配置文件,将事务相关的信息应用到需要进行事务管理的方法上。
springboot引入AOP切面@Aspect注解使用
springboot引⼊AOP切⾯@Aspect注解使⽤<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>*/@Aspect@Component@Slf4jpublic class HttpAspect {/*** ⽇志切点*/@Pointcut("execution(public * com.api.controller..*.*(..))")public void log() {}/*** 开始请求前** @param joinPoint*/@Before("log()")public void doBefore(JoinPoint joinPoint) {// 主类ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes != null){HttpServletRequest request = attributes.getRequest();// url 路径("请求={}", request.getRequestURL() + " | method=" + request.getMethod() + " | ip=" + request.getRemoteAddr());// 类⽅法("⽅法={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());// 参数("参数={}", Arrays.toString(joinPoint.getArgs()));}}/*** 返回处理** @param result*/@AfterReturning(returning = "result", pointcut = "log()")public void doAfterReturning(Object result) {("返回={}", JSON.toJSON(result));}任何的public⽅法execution(public * *(..))以set开始的⽅法execution(* set*(..))定义在cn.freemethod.business.pack.Say接⼝中的⽅法execution(* cn.freemethod.business.pack.Say.*(..))任何cn.freemethod.business包中的⽅法execution(* cn.freemethod.business.*.*(..))任何定义在com.xyz.service包或者其⼦包中的⽅法execution(* cn.freemethod.business..*.*(..))其他表达式任何在com.xyz.service包中的⽅法within(com.xyz.service.*)任何定义在com.xyz.service包或者其⼦包中的⽅法within(com.xyz.service..*)任何实现了com.xyz.service.AccountService接⼝中的⽅法this(com.xyz.service.AccountService)任何⽬标对象实现了com.xyz.service.AccountService的⽅法target(com.xyz.service.AccountService)⼀般情况下代理类(Proxy)和⽬标类(Target)都实现了相同的接⼝,所以上⾯的2个基本是等效的。
Java框架------Spring框架AOP注解(@Aspect和@Around)
Java框架------Spring框架AOP注解(@Aspect和@Around)AOP 中的声明主要有两种基于XML和基于Annotation之前的为借助xml ,现在介绍⼀下借助注解的⽅式,修改之前的⼩项⽬常见五种通知类型org.springframework.aop.MethodBeforeAdvice(前置通知)在⽅法之前⾃动执⾏的通知称为前置通知,可以应⽤于权限管理等功能。
org.springframework.aop.AfterReturningAdvice(后置通知)在⽅法之后⾃动执⾏的通知称为后置通知,可以应⽤于关闭流、上传⽂件、删除临时⽂件等功能。
org.aopalliance.intercept.MethodInterceptor(环绕通知)在⽅法前后⾃动执⾏的通知称为环绕通知,可以应⽤于⽇志、事务管理等功能。
org.springframework.aop.ThrowsAdvice(异常通知)在⽅法抛出异常时⾃动执⾏的通知称为异常通知,可以应⽤于处理异常记录⽇志等功能。
org.springframework.aop.IntroductionInterceptor(引介通知)在⽬标类中添加⼀些新的⽅法和属性,可以应⽤于修改旧版本程序(增强类)。
常见注解@Aspect:作⽤是把当前类标识为⼀个切⾯供容器读取@Around:环绕增强,相当于MethodInterceptor@AfterReturning:后置增强,相当于AfterReturningAdvice,⽅法正常退出时执⾏@Pointcut:Pointcut是植⼊Advice的触发条件。
每个Pointcut的定义包括2部分,⼀是表达式,⼆是⽅法签名。
⽅法签名必须是 public及void型。
可以将Pointcut中的⽅法看作是⼀个被Advice引⽤的助记符,因为表达式不直观,因此我们可以通过⽅法@Before:标识⼀个前置增强⽅法,相当于BeforeAdvice的功能,相似功能的还有@AfterThrowing:异常抛出增强,相当于ThrowsAdvice@After: final增强,不管是抛出异常或者正常退出都会执⾏使⽤pointcut代码@DeclareParents ⽤于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。
举例说明事务注解失效的场景
举例说明事务注解失效的场景事务注解是在Spring框架中非常常用的一种方式,用于管理数据库事务。
但是在某些场景下,事务注解可能会失效,导致事务无法正常管理。
本文将举例说明事务注解失效的场景。
一、Spring AOP代理问题Spring AOP代理是实现事务注解的重要手段之一。
但是,在某些情况下,AOP代理可能会失效,导致事务无法正常管理。
1.1 代理对象为类而不是接口当我们使用基于类的AOP代理时,如果被代理的对象没有实现任何接口,则Spring将会使用CGLIB创建一个子类来实现AOP。
这个子类并不会继承父类上的@Transactional注解,因此在使用该子类时,事务注解将会失效。
1.2 代理对象不是由Spring容器创建如果我们手动创建了一个对象,并且使用了@Transactional注解来管理它的事务,则该注解将不起作用。
因为Spring只能对由容器创建的Bean进行AOP代理。
二、多线程问题当我们在多线程环境下使用事务注解时,可能会遇到以下问题:2.1 一个线程中开启了一个新的事务,并在该线程中进行了操作;另一个线程中也开启了一个新的事务,并尝试对第一个线程所操作过的数据进行操作。
此时,第二个线程将无法获取到第一个线程所开启的事务,从而导致事务注解失效。
2.2 在多线程环境下,如果我们使用ThreadLocal来管理事务,则可能会遇到线程池重用问题。
当一个线程执行完毕后,我们需要手动清除ThreadLocal中的内容,否则当该线程被再次使用时,它仍然会持有之前的ThreadLocal内容,从而导致事务注解失效。
三、异常处理问题在使用@Transactional注解时,我们需要注意异常处理问题。
如果我们在方法中捕获了异常,并且没有将其向上抛出,则该异常将不会被Spring捕获到,并且事务将不会回滚。
四、数据库引擎问题在某些数据库引擎中,例如MyISAM,在执行DML操作时并不支持事务。
因此,在使用这些数据库引擎时,即使我们使用了@Transactional注解来管理事务,也无法实现回滚操作。
SpringBoot使用@Aspect注解实现AOP
SpringBoot使⽤@Aspect注解实现AOPAOP(Aspect Oriented Programming,⾯向切⾯编程)是通过预编译⽅式和运⾏期动态代理实现程序功能的统⼀维护的⼀种技术。
AOP是OOP的延续,是软件开发中的⼀个热点,也是Spring框架中的⼀个重要内容,是函数式编程的⼀种衍⽣范型。
利⽤AOP可以对业务逻辑的各个部分进⾏隔离,从⽽使得业务逻辑各部分之间的耦合度降低,提⾼程序的可重⽤性,同时提⾼了开发的效率。
在Spring AOP中业务逻辑仅仅只关注业务本⾝,将⽇志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,从⽽在改变这些⾏为的时候不影响业务逻辑的代码。
相关注解介绍:注解作⽤@Aspect把当前类标识为⼀个切⾯@Pointcut Pointcut是织⼊Advice的触发条件。
每个Pointcut的定义包括2部分,⼀是表达式,⼆是⽅法签名。
⽅法签名必须是public及void 型。
可以将Pointcut中的⽅法看作是⼀个被Advice引⽤的助记符,因为表达式不直观,因此我们可以通过⽅法签名的⽅式为此表达式命名。
因此Pointcut中的⽅法只需要⽅法签名,⽽不需要在⽅法体内编写实际代码。
@Around环绕增强,⽬标⽅法执⾏前后分别执⾏⼀些代码@AfterReturning返回增强,⽬标⽅法正常执⾏完毕时执⾏@Before前置增强,⽬标⽅法执⾏之前执⾏@AfterThrowing异常抛出增强,⽬标⽅法发⽣异常的时候执⾏@After后置增强,不管是抛出异常或者正常退出都会执⾏⼀、添加依赖<!--Spring AOP 切⾯模块 --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId></dependency><!-- SpringBoot 拦截器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency>⼆、编写增强类package com.example.demo.Aspect;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import ng.JoinPoint;import ng.ProceedingJoinPoint;import ng.Signature;import ng.annotation.*;import ng.reflect.SourceLocation;import ponent;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.util.Arrays;@Component@Aspect@Slf4jpublic class LogAspect {private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();@Pointcut("execution(* com.example.demo.Aspect.TestController.doNormal(..))")public void pointCut(){}@Before(value = "pointCut()")public void before(JoinPoint joinPoint){("@Before通知执⾏");//获取⽬标⽅法参数信息Object[] args = joinPoint.getArgs();Arrays.stream(args).forEach(arg->{ // ⼤⼤try {(OBJECT_MAPPER.writeValueAsString(arg));} catch (JsonProcessingException e) {(arg.toString());}});//aop代理对象Object aThis = joinPoint.getThis();(aThis.toString()); //com.xhx.springboot.controller.HelloController@69fbbcdd//被代理对象Object target = joinPoint.getTarget();(target.toString()); //com.xhx.springboot.controller.HelloController@69fbbcdd//获取连接点的⽅法签名对象Signature signature = joinPoint.getSignature();(signature.toLongString()); //public ng.String com.xhx.springboot.controller.HelloController.getName(ng.String) (signature.toShortString()); //HelloController.getName(..)(signature.toString()); //String com.xhx.springboot.controller.HelloController.getName(String)//获取⽅法名(signature.getName()); //getName//获取声明类型名(signature.getDeclaringTypeName()); //com.xhx.springboot.controller.HelloController//获取声明类型⽅法所在类的class对象(signature.getDeclaringType().toString()); //class com.xhx.springboot.controller.HelloController//和getDeclaringTypeName()⼀样(signature.getDeclaringType().getName());//com.xhx.springboot.controller.HelloController//连接点类型String kind = joinPoint.getKind();(kind);//method-execution//返回连接点⽅法所在类⽂件中的位置打印报异常SourceLocation sourceLocation = joinPoint.getSourceLocation();(sourceLocation.toString());//(sourceLocation.getFileName());//(sourceLocation.getLine()+"");//(sourceLocation.getWithinType().toString()); //class com.xhx.springboot.controller.HelloController///返回连接点静态部分JoinPoint.StaticPart staticPart = joinPoint.getStaticPart();(staticPart.toLongString()); //execution(public ng.String com.xhx.springboot.controller.HelloController.getName(ng.String))//attributes可以获取request信息 session信息等ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();(request.getRequestURL().toString()); //http://127.0.0.1:8080/hello/getName(request.getRemoteAddr()); //127.0.0.1(request.getMethod()); //GET("before通知执⾏结束");}/*** 后置返回* 如果第⼀个参数为JoinPoint,则第⼆个参数为返回值的信息* 如果第⼀个参数不为JoinPoint,则第⼀个参数为returning中对应的参数* returning:限定了只有⽬标⽅法返回值与通知⽅法参数类型匹配时才能执⾏后置返回通知,否则不执⾏,* 参数为Object类型将匹配任何⽬标返回值*/@AfterReturning(value = "pointCut()",returning = "result")public void doAfterReturningAdvice1(JoinPoint joinPoint,Object result){("第⼀个后置返回通知的返回值:"+result);}@AfterReturning(value = "pointCut()",returning = "result",argNames = "result")public void doAfterReturningAdvice2(String result){("第⼆个后置返回通知的返回值:"+result);}//第⼀个后置返回通知的返回值:姓名是⼤⼤//第⼆个后置返回通知的返回值:姓名是⼤⼤//第⼀个后置返回通知的返回值:{name=⼩⼩, id=1}/*** 后置异常通知* 定义⼀个名字,该名字⽤于匹配通知实现⽅法的⼀个参数名,当⽬标⽅法抛出异常返回后,将把⽬标⽅法抛出的异常传给通知⽅法;* throwing:限定了只有⽬标⽅法抛出的异常与通知⽅法相应参数异常类型时才能执⾏后置异常通知,否则不执⾏,* 对于throwing对应的通知⽅法参数为Throwable类型将匹配任何异常。
Spring面试,IoC和AOP的理解,@Transactional原理及使用
Spring⾯试,IoC和AOP的理解,@Transactional原理及使⽤spring 的优点?1.降低了组件之间的耦合性,实现了软件各层之间的解耦2.可以使⽤容易提供的众多服务,如事务管理,消息服务等3.容器提供单例模式⽀持4.容器提供了AOP技术,利⽤它很容易实现如权限拦截,运⾏期监控等功能5.容器提供了众多的辅助类,能加快应⽤的开发6.spring对于主流的应⽤框架提供了集成⽀持,如hibernate,JPA,Struts等7.spring属于低侵⼊式设计,代码的污染极低8.独⽴于各种应⽤服务器9.spring的DI机制降低了业务对象替换的复杂性10.Spring的⾼度开放性,并不强制应⽤完全依赖于Spring,开发者可以⾃由选择spring的部分或全部什么是DI机制?依赖注⼊(Dependecy Injection)和控制反转(Inversion of Control)是同⼀个概念,具体的讲:当某个⾓⾊需要另外⼀个⾓⾊协助的时候,在传统的程序设计过程中,通常由调⽤者来创建被调⽤者的实例。
但在spring中创建被调⽤者的⼯作不再由调⽤者来完成,因此称为控制反转。
创建被调⽤者的⼯作由spring来完成,然后注⼊调⽤者因此也称为依赖注⼊。
spring以动态灵活的⽅式来管理对象,注⼊的两种⽅式,设置注⼊和构造注⼊。
设置注⼊的优点:直观,⾃然构造注⼊的优点:可以在构造器中决定依赖关系的顺序。
什么是AOP?⾯向切⾯编程(AOP)完善spring的依赖注⼊(DI),⾯向切⾯编程在spring中主要表现为两个⽅⾯1.⾯向切⾯编程提供声明式事务管理2.spring⽀持⽤户⾃定义的切⾯⾯向切⾯编程(aop)是对⾯向对象编程(oop)的补充,⾯向对象编程将程序分解成各个层次的对象,⾯向切⾯编程将程序运⾏过程分解成各个切⾯。
AOP从程序运⾏⾓度考虑程序的结构,提取业务处理过程的切⾯,oop是静态的抽象,aop是动态的抽象,是对应⽤执⾏过程中的步骤进⾏抽象,,从⽽获得步骤之间的逻辑划分。
事务的注解的原理
事务的注解的原理
事务的注解的原理是基于AOP(面向切面编程)的思想,通
过对方法或类进行注解,从而实现对事务的控制。
在Spring框架中,通过使用@Transactional注解来对方法或类
进行事务管理。
当方法或类上标注了@Transactional注解时,Spring会在运行时动态生成一个代理对象,将该方法的执行逻
辑包装在事务管理器中。
具体原理如下:
1. 在方法或类上添加@Transactional注解后,Spring容器会扫
描并解析注解信息。
2. Spring会生成一个动态代理对象,该对象负责管理事务的边
界和具体的事务操作。
3. 在方法执行前,代理对象会先开启一个事务,调用方法的逻辑。
4. 当方法执行完成后,代理对象会根据方法的执行情况决定是提交还是回滚事务。
5. 如果方法执行过程中出现异常或抛出RuntimeException,则
代理对象会回滚事务,否则会提交事务。
6. 代理对象将事务的提交或回滚操作应用到底层的数据库连接上。
通过注解方式配置事务,相比传统的编程方式,具有简洁、灵活和可重用的特点。
同时,由于使用了动态代理机制,使得事务的边界和具体操作的分离,提高了代码的可维护性和扩展性。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
spring使用基于注解的AOP事务管理
16.6 AOP事务管理
AOP事务管理利用了Spring AOP的基础设施,在大多数情况下,Spring AOP会创建一个JDK代理以拦截方法调用。
你可以使用装载时编织以在装载期编织切面,这样就不需要代理了(如果你记不清什么是装载时编织,请参看第6章)。
你有两种方式来配置Spring AOP 事务管理,基于注解的配置以及XML配置。
16.6.1 使用基于注解的AOP事务管理
你可以借助于AOP的自动代理,通过注解将事务性行为引入到现有的bean中。
让我们以代码清单16-21开始吧,它展示了类DeclarativeTxBankService。
代码清单16-21 DeclarativeTxBankService实现
请注意@Transactional属性,为了让Spring的事务管理基础设施可以利用该属性创建恰当的切入点和通知,我们需要使用AOP的自动代理和注解驱动的事务支持。
代码清单16-22展示了与该注解相对应的XML配置。
代码清单16-22 基于注解的事务管理的配置文件
该XML配置文件展示了标准的bankService bean声明,紧跟其后的是
<tx:annotation-driven/>和<aop:aspectj-autoproxy/>标签。
<tx:annotation-driven/>标签使用@Transactional注解创建恰当的事务管理切面。
接下来由<aop:aspectj-autoproxy/>通知匹配的bean。
1.探索tx:annotation-driven标签
<tx:annotation-driven/>标签是注解驱动的事务管理支持的核心。
表16-3列出了
<tx:annotation- driven/>标签的所有属性。
表16-3 <tx:annotation-driven/>标签的属性
属性说明
transactionManager 指定到现有的PlatformTransaction Manager bean的引用,通知会使用该引用
mode 指定Spring事务管理框架创建通知bean的方式。
可用的值有proxy和aspectj。
前者是默认值,
表示通知对象是个JDK代理;后者表示
Spring AOP会使用AspectJ创建代理
order 指定创建的切面的顺序。
只要目标对象有多个通知就可以使用该属性
proxy-target-class 该属性如果为true就表示你想要代理目标类而不是bean所实现的所有接口
2.探索@Transactional注解
凭借@Transactional注解我们就可以控制通知将要创建的事务定义的方方面面。
就像使用transactionAttributes属性表达式一样,你可以指定传播、隔离级别、超时以及允许和不允许的异常。
表16-4列出了@Transactional注解的所有属性。
表16-4 @Transactional注解的属性
属性类型说明
propagation org.springframework.
annotaion.transaction.Propagation 指定事务定义中使用的传播
isolation org.springframework.
annotation.
transaction.Isolation
设定事务的隔离级别
timeout int 指定事务的超时
(单位为秒)readOnly boolean 如果为true,事务
就被标识为只读
noRollbackF or Class<? extends Throwable>[] 目标方法可抛出的
异常所构成的数组,
但通知仍会提交事务
rollbackFor Class<? extends Throwable>[] 异常所构成的数组,
如果目标方法抛出了
这些异常,通知就会回滚事务3.基于注解的事务管理小结
通过@Transactional注解,我们可以轻松地为一个方法声明事务。
其好处在于你可以很直观地看到哪些方法带有事务,因为方法上面有该注解修饰。
其缺点是你不得不为每个需要事务的方法都加上@Transactional注解。
如果你使用的是默认的事务属性,这就不算什么问题,但当你需要设置其他的事务属性时,这就变得很乏味了,因为你要不停的复制、粘贴。
另一种方式就是用@Transactional注解去修饰类。
这会将事务应用到该类中的所有方法。
这种方式的问题在于所有的方法,包括简单的读取方法和设置方法也都运行在事务中了,尽管根本不需要这么做。
XML AOP事务管理能更好地处理这种情况。
说明虽然说通过使用@Transactional注解会使所有方法运行在事务中,但我还要再多说几句:其实准确的说法应该是如果某个类被@Transactional注解所修饰,那么该类实例化的Spring bean的所有方法都是事务性的。