Spring注解开发系列Ⅵ --- AOP&事务
注解开发 --- AOP
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,横向重复,纵向抽取。详细的AOP介绍请看这里,本篇主要是讨论AOP在spring注解开发中的运用。
AOP的使用
1.导入aop模块(spring-aspects)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
2.定义一个业务逻辑类(com.wang.aop.MathCalculator),在业务逻辑运行时将日志进行打印(方法之前,方法结束,方法异常都会打印)。
public class MathCalculator {
public int div(int x,int y){
return x/y;
}
}
3.定义一个日志切面类(com.wang.aop.LogAspects),切面类的方法需要动态感知MathCalculator的div方法运行到哪里,然后执行通知方法。
通知方法:
1).前置通知(@Before):logStart(),在目标方法运行之前运行
2).后置通知(@After):logEnd(),在目标方法运行之后运行(无论方法正常结束或异常结束都会调用)
3).返回通知(@AfterReturning):logRet(),在目标方法正常返回之后执行
4).异常通知(@AfterThrowing):logException(),在目标方法运行异常之后运行
5).环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
4.给切面类的方法标注通知注解
/**
* 切面类
*/
@Aspect
public class LogAspects {
//抽取公共表达式
//本类引用:pointCut()
//其他切面类引用:com.wang.aop.LogAspects.pointCut()
//@Pointcut("execution(public int com.wang.aop.MathCalculator.div(int ,int ))")
@Pointcut("execution(public int com.wang.aop.MathCalculator.*(..))") public void pointCut(){ }
//在目标方法之前切人,切入点表达式
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法开始运行...@Before,参数列表是"+Arrays.asList(joinPoint.getArgs()));
}
@After("pointCut()")
public void logEnd(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法结束...@After,参数列表是"+Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "pointCut()",returning = "result")
public void logRet(JoinPoint joinPoint,Object result){ //joinPoint必须放在参数第一位,否则则会报错
System.out.println(joinPoint.getSignature().getName()+"方法结果打印...@AfterReturning,运行结果"+result);
}
@AfterThrowing(value = "pointCut()",throwing = "exception")
public void logException(Exception exception){
System.out.println("方法异常...@AfterThrowing,异常结果"+exception);
}
}
5.将切面类和业务逻辑类(目标方法所在类)都加入到容器中
@Configuration
@EnableAspectJAutoProxy //开启spring的aop注解功能
public class AOPConfig {
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
6.必须告诉spring哪个类是切面类(给切面类加上注解@Aspect)(@Aspect)
7.给配置类中添加@EnableAspectJAutoProxy,开启基于注解的AOP模式
注意:
1.使用aop的对象不能自己new创建,需要去spring容器中获取,否则AOP方法不会执行
2.JoinPoint必须放在参数第一位,否则会报错
注解开发 --- 事务
Spring事务其实就是Spring AOP,底层创建动态代理对象,在代码的开头结尾封装了开启事务和事务回滚操作,关于事务的基本使用。
声明式事务
1.环境搭建:导入相关依赖:数据源,数据库驱动
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
2.配置数据源,spring-jdbc模块(jdbctmplate,也可以导入mybatis以及hibernate,jpa)
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("123456");
comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return comboPooledDataSource;
}
3.给方法标注:@Transactional 表示当前方法是一个事务方法
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "INSERT INTO `tb_user`(username,age) VALUES(?,?)";
String substring = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql,substring,11);
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser(){
userDao.insert();
int i = 1/0;
System.out.println("插入成功");
}
}
4.配置类上加上@EnableTransactionManagement开启基于注解的事务管理
@ComponentScan({"com.wang.tx","com.wang.service","com.wang.dao"})
@Configuration
@EnableTransactionManagement
public class TxConfig {
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setUser("root");
comboPooledDataSource.setPassword("123456");
comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
return comboPooledDataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
//spring对Configuration类有特殊处理,给容器中加组件的方法,多次调用都会从容器中找组件
JdbcTemplate template = new JdbcTemplate(dataSource);
return template;
}
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
5.在配置类配置事务管理器控制事务
测试结果:查看数据库,若抛出异常没有数据插入到数据库说明事务注解生效了
public class TxTest {
@Test
public void txTest(){
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userservice = annotationConfigApplicationContext.getBean(UserService.class);
userservice.insertUser();
annotationConfigApplicationContext.close();
}
}
Spring注解开发系列Ⅵ --- AOP&事务的更多相关文章
- Spring注解开发系列专栏
这个系列主要是讲Spring注解的使用,可以为后面SpringBoot的学习带来一定的帮助.我觉得从Spring直接过度到SpringBoot还是有点快,还是得需要一个演变的过程.从Spring开发, ...
- Spring注解开发系列VIII --- SpringMVC
SpringMVC是三层架构中的控制层部分,有过JavaWEB开发经验的同学一定很熟悉它的使用了.这边有我之前整理的SpringMVC相关的链接: 1.SpringMVC入门 2.SpringMVC进 ...
- spring注解开发-声明式事务(源码)
1. 环境搭建与测试 1)导入相关依赖 数据源.数据库驱动.Spring-jdbc模块 <dependency> <groupId>org.springframework< ...
- Spring注解开发系列Ⅰ--- 组件注册(上)
传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点:1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文件 ...
- Spring注解开发系列Ⅴ --- 自动装配&Profile
自动装配: spring利用依赖注入和DI完成对IOC容器中各个组件的依赖关系赋值.自动装配的优点有: 自动装配可以大大地减少属性和构造器参数的指派. 自动装配也可以在解析对象时更新配置. 自动装配的 ...
- Spring注解开发系列VII --- Servlet3.0
Servlet3.0简介 Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布.该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用 ...
- Spring注解开发系列Ⅱ --- 组件注册(下)
1.@Import注册组件 @Import主要功能是通过导入的方式实现把实例加入springIOC容器中, /** * 给容器注册组件 * 1.包扫描+组件标注注解(@Controller,@Serv ...
- Spring注解开发系列Ⅲ --- 生命周期
Bean的生命周期 Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,掌握这些可以加深对 Spring 的理解. 首先看下生命周期图: 再谈生命周期之前有一点需要先明确: S ...
- Spring注解开发系列Ⅳ --- 属性赋值
在Spring框架中,属性的注入我们有多种方式,我们可以通过构造方法注入,可以通过set方法注入,也可以通过p名称空间注入,方式多种多样,对于复杂的数据类型比如对象.数组.List集合.map集合.P ...
随机推荐
- 《带你装B,带你飞》pytest修炼之路1- 简介和环境准备
1. pytest简介 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高.根据pytest的官方网站介 ...
- QT信号和槽函数学习笔记
//connect 函数有4个参数 分别是 发送者 信号.接受者 ,槽 //connect(sender,signal,receiver,slot) /* * 信号和槽 * 信号 就是一个普通的函数 ...
- 洛谷$P$2286 宠物收养场 $[HNOI2004]$ $splay$
正解:$splay$ 解题报告: 传送门! $splay$板子,,,? 先考虑这题要实现些什么东西嘛$QwQ$ 其实只要实现一个东西?就查询数列中与给定数字相差最小的数,显然用$splay$查询前驱后 ...
- JAVA8学习——从源码角度深入Stream流(学习过程)
从源代码深入Stream / 学习的时候,官方文档是最重要的. 及其重要的内容我们不仅要知道stream用,要知道为什么这么用,还要知道底层是怎么去实现的. --个人注释:从此看出,虽然新的jdk版本 ...
- Logger日志打印规范
首先来看一下比较常用的Logger日志级别(部分未列出): error - 运行期错误日志记录,应该有专门的error日志文件.: warn - 警告信息,如程序调用了一个即将作废的接口,接口的不当使 ...
- JAVA封装、继承、多态
封装 1.概念: 将类的某些信息隐藏在类的内部,不允许外部程序访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: a.只能通过规定的方法访问数据 b.隐藏类的实例细节,方便修改和实 ...
- Serverless 微服务实践-移动应用包分发服务
背景 阿里云函数计算是事件驱动的全托管计算服务.通过函数计算,您无需管理服务器等基础设施,只需编写代码并上传.函数计算会为您准备好计算资源,以弹性.可靠的方式运行您的代码,并提供日志查询.性能监控.报 ...
- JS中如何比较两个数组,取得数组二相对于数组一新增和去除的元素
//数组二相对于数组一所新增的数据 function add_msg(a,b){ return a.filter(function(i){ return b.indexOf(i) === -1 }) ...
- Unity_Dungeonize 随机生成迷宫
本文对随机生成迷宫的实现思路进行记录,其作用在于为游戏过程提供随机性以及节省开发周期,下面是Dungeonize的结构 随机迷宫的生成主要包括几个阶段 1.生成房间体结构,为墙体,自定义房间,自定义物 ...
- 【LC_Overview1_5】---学会总结回顾
刷LeetCode题目一周,主要采用C++和Python编程手段,截至目前做了5道简单的leetcode题目,做下阶段性的小结: 小结主要通过手撕代码,复习加回顾,尽量避免自己眼高手低的情况发生,对于 ...