根据黑马程序员的课程资料整理所得,仅用于学习使用,如有侵权,请联系删除
目录
Spring Framework(以下简称Spring)
Spring的系统架构
Spring_核心概念及入门案例
1.IOC实现案例:
2.DI入门案例:(项目创建在下文中不再讲解)
Spring_bean配置,实例化及生命周期
1.bean配置
2.bean实例化:
3.bean生命周期
Spring_注入问题
1.setter引用类型注入(在实现类中提供setter方法
2.setter简单类型注入(在实现类中提供setter方法
3.构造器注入引用类型(在实现类中提供构造方法
4.构造器注入简单类型(在实现类中提供构造方法
5.依赖自动装配(提供setter方法
6.集合注入
Spring_容器
Spring_IOC/DI注解开发
1.注解开发定义bean
2.纯注解开发模式,使用Java类替代配置文件
3.注解开发bean作用范围与生命周期管理
4.注解开发依赖注入
5.注解开发管理第三方bean,以下以druid连接池为例
6.注解开发实现为第三方bean注入资源,接着上例
Spring_Spring整合mybatis以及junit
1.整合mybatis
2.整合junit
Spring_AOP简介
1.AOP概念:
2.入门案例:
3.AOP工作流程
4.AOP切入点表达式
5.AOP通知类型
6.AOP通知获取数据
spring_事务管理
1.spring事务简介
2.spring事务配置
Spring Framework是spring家族中的底层框架及设计框架
介绍路线如标号所示.
1. IOC(Inversion of Control)控制反转
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到 外部,此思想称为控制反转。
spring与ioc的关系:Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部".
ioc容器中存放的是一个个数据层和业务层的bean对象
2.DI(Dependency Injection)依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
1.创建项目:
2.pom.xml添加Spring的依赖jar包
org.springframework
spring-context
5.2.10.RELEASE
3.创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
4.resources下添加spring配置文件,并完成bean的配置
5.使用Spring提供的接口完成IOC容器的创建并加载配置文件
public static void main(String[] args) {
//获取IOC容器
//1.加载类路径下的配置文件,默认为立即加载
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
//2.从文件系统下加载配置文件
//ApplicationContext ctx = new FileSystemXmlApplicationContext("绝对路径");
//3.已过时,延迟加载
// Resource resources = new ClassPathResource("applicationContext.xml");
//BeanFactory bf = new XmlBeanFactory(resources);
}
6.从容器中获取对象进行方法调用(获取bean)
在主方法下接着上文:
//法一:
//BookService bookService = (BookService) ctx.getBean("bookService");
//法二:
//BookService bookService = ctx.getBean("bookService",bookDao.class);
//法三:
BookService bookService = ctx.getBean(bookDao.class);
bookService.save();
1.删除业务层中使用new的方式创建的dao对象
2.在业务层提供BookDao的setter方法
3.在配置文件中添加依赖注入的配置
4.运行程序调用方法
1.bean的别名
//用name标签给bean起别名并在main方法中修改,如下
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("service");
bookService.save();
}
2.bean的作用范围
<-- 添加标签scope限制作用范围,singleton为单例,prototype为非单例-->
3.适合交给spring管理的bean对象:表现层对象 业务层对象 数据层对象 工具对象
方法1.用无参构造方法来实例化对象
//用无参构造方法来实例化对象
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
方法2.使用静态工厂实例化对象
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");
return new OrderDaoImpl();
}
}
方法3.使用实例工厂实例化bean
//创建实例工厂对象(main方法中)
UserDaoFactory userDaoFactory = new UserDaoFactory();
//通过实例工厂对象创建对象
UserDao userDao = userDaoFactory.getUserDao();
userDao.save();
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
//工厂类
方法4.使用FactoryBean实例化bean
(1)创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法
public class UserDaoFactoryBean implements FactoryBean {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//返回所创建类的Class对象
public Class> getObjectType() {
return UserDao.class;
}
}
(2)在Spring的配置文件中进行配置
(3)FactoryBean接口其实会有三个方法
T getObject() throws Exception;
Class> getObjectType();
default boolean isSingleton() {
return true;
}
方法一:
步骤1:添加初始化和销毁方法
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
步骤2:配置生命周期
步骤3: (法1)close关闭容器
ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
//调用ctx的close方法
ctx.close();
(法2)4 注册钩子关闭容器
ctx.registerShutdownHook();
方法二:修改BookServiceImpl类,添加两个接口InitializingBean, DisposableBean并实现接口中的 两个方法afterPropertiesSet和destroy
public class BookServiceImpl implements BookService, InitializingBean,
DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
[1]. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现,强制依赖指对象在创建的过程中必须要注入指定的参数
[2]. 可选依赖使用setter注入进行,灵活性强,可选依赖指对象在创建过程中注入的参数可有可无
[3]. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相 对严谨
[4]. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选 依赖的注入
[5]. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注 入
[6]. 自己开发的模块推荐使用setter注入
(1.按类型,类型匹配唯一
(2.按名称,具有指定名称的bean
(1.array注入
...
(2.list注入
...
(3.set注入
...
(4.Map注入
(5.properties注入
...
容器类结构层次
(1.在需要添加注解的表现层、业务层或是数据层的类上添加注解
@Component("...")
public class ...impl implements ...
/**
*@Component
*在表现层上可以添加 *@Controller
*在业务层上可以添加 *@Service
*在数据层上可以添加 *@Repository
*/
(2:配置Spring的注解包扫描
(3.从IOC容器中获取对应的bean对象
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
//按类型获取bean,例如
BookService bookService = ctx.getBean(BookService.class);
}
(1.将配置文件applicationContext.xml删除掉
(2.创建一个配置类SpringConfig,标识该类为配置类,并用注解替换包扫描配置
@Configuration
@ComponentScan("包名")//此注解只能添加一次,多个数据请用数组格式
public class SpringConfig {
}
(3.运行
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new
AnnotationConfigApplicationContext(SpringConfig.class);
//调用,例如
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
}
}
(1.管理是否单例
@Repository
//@Scope设置bean的作用范围
@Scope("prototype")
public class ...Impl implements ... {
}
}
(2.生命周期
@Repository
public class ...impl implements ...{
@PostConstruct //在构造方法之后执行,替换 init-method
public void init() {
System.out.println("init ...");
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println("destroy ...");
}
}
注意:@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包
javax.annotation
javax.annotation-api
1.3.2
(1.注解实现按照类型注入
//在相应实现方法上添加@Autowired注解,例如
@Service
public class BookServiceImpl implements BookService {
@Autowired//不需要setter方法
private BookDao bookDao;
}
}
(2.注解实现按照名称注入
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao1")
//@Qualifier来指定注入哪个名称的bean对象,@Qualifier不能独立使用,必须和@Autowired一起使用
private BookDao bookDao;
}
(3.简单数据类型注入
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("...")
private String name;
}
(4.注解读取properties配置文件
在配置类上添加@PropertySource注解
@Configuration
@ComponentScan("包名")
@PropertySource("配置文件.properties")
public class SpringConfig {
}
使用@Value读取配置文件中的内容
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${...}")
private String name;
}
//如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个
// @PropertySource({"jdbc.properties","xxx.properties"})
//@PropertySource注解属性中不支持使用通配符*,运行会报错
(1.现在pom文件中导入druid坐标
(2.对于数据源的bean,我们新建一个JdbcConfig配置类,并把数据源配置到该类下。
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
(3.将该配置类引入到spring配置类中
方法一:使用包扫描引入(不推荐使用)
*在Spring的配置类上添加包扫描
@Configuration
@ComponentScan("config")
public class SpringConfig {
}
*在JdbcConfig上添加配置注
@Configuration
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
方法二:使用@Import引入
*在spring配置类中引入
@Configuration
//@ComponentScan("config")
@Import({JdbcConfig.class})//@Import参数需要的是一个数组,可以引入多个配置类。
public class SpringConfig {
}
(1注入简单类型数据
在JdbcConfig配置类中进行修改
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("password")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
(2.注入引用类型
*:在SpringConfig中扫描BookDao
@Configuration
@ComponentScan("dao")
@Import({JdbcConfig.class})
public class SpringConfig {
}
*在JdbcConfig类的方法上添加参数
@Bean
public DataSource dataSource(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
注解总结:XML配置和注解的区别
(1.在pom文件中导入以下依赖
spring-context druid mybatis mysql-connector-java spring-jdbc
mybatis-spring
(2.创建Spring的主配置类
//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("...")
public class SpringConfig {
}
(3.创建数据源的配置类
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
(4.主配置类中读properties并引入数据源配置类
@Configuration
@ComponentScan("...")
@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfig {
}
(5.创建Mybatis配置类并配置SqlSessionFactory
public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
//设置模型类的别名扫描
ssfb.setTypeAliasesPackage("domain");
//设置数据源
ssfb.setDataSource(dataSource);
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao");
return msc;
}
}
(6.主配置类中引入Mybatis配置类
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
(7.从ioc中获取对象并运行
(1.引入依赖junit spring-test
(2.编写测试类
//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置Spring环境对应的配置类
@ContextConfiguration(classes = {SpringConfiguration.class}) //加载配置类
//@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载
配置文件
public class AccountServiceTest {
//支持自动装配注入bean
@Autowired
private AccountService accountService;
@Test
public void testFindById(){
System.out.println(accountService.findById(1));
}
@Test
public void testFindAll(){
System.out.println(accountService.findAll());
}
}
*AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程 序结构。
AOP作用:在不惊动原始设计的基础上为其进行功能增强,前面咱们有技术就可以实现这样的功能即代 理模式
*连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
*在SpringAOP中,理解为方法的执行
*切入点(Pointcut):匹配连接点的式子
*在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
*一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方 法
*法 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意 方法,所有带有一个参数的方法
*连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一 定要被增强,所以可能不是切入点。
*通知(Advice):在切入点处执行的操作,也就是共性功能
*在SpringAOP中,功能最终以方法的形式呈现
*通知类:定义通知的类
*切面(Aspect):描述通知与切入点的对应关系。
(1.pom.xml添加Spring依赖spring-context aspectjweaver
(2.定义接口和实现类
(3.定义通知类和通知,定义切入点,制作切面,并将通知类配给容器并标识其为切面类
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
(4.开启注解格式AOP功能
@Configuration
@ComponentScan("")
@EnableAspectJAutoProxy//加上该注解
public class SpringConfig {
}
(5.运行
流程1:Spring容器启动
*需要被增强的类,如:BookServiceImpl
*通知类,如:MyAdvice
*注意此时bean对象还没有创建成功
流程2:读取所有切面配置中的切入点
流程3:初始化bean, 判定bean对应的类中的方法是否匹配到任意切入点
*注意第1步在容器启动的时候,bean对象还没有被创建成功。
* 要被实例化bean对象的类中的方法和切入点进行匹配
*匹配失败,创建原始对象,如UserDao
*匹配失败说明不需要增强,直接调用原始对象的方法即可。
*匹配成功,创建原始对象(目标对象)的代理对象,如: BookDao
*匹配成功说明需要对其进行增强 对哪个类做增强,这个类对应的对象就叫做目标对象
*因为要对目标对象进行功能增强,而采用的技术是动态代理,所以会为其创建一个代理对象 *最终运行的是代理对象的方法,在该方法中会对原始方法进行功能增强
流程4:获取bean执行方法
* 获取的bean是原始对象时,调用方法并执行,完成操作
*获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
验证容器中是否为代理对象
*为了验证IOC容器中创建的对象和我们刚才所说的结论是否一致,首先先把结论理出来:
*如果目标对象中的方法会被增强,那么容器中将存入的是目标对象的代理对象
*如果目标对象中的方法不被增强,那么容器中将存入的是目标对象本身。
*验证思路
1.要执行的方法,不被定义的切入点包含,即不要增强,打印当前类的getClass()方法
2.要执行的方法,被定义的切入点包含,即要增强,打印出当前类的getClass()方法
3.观察两次打印的结果
(1.两种描述方法
//描述方式一:执行dao包下的BookDao接口中的无参数update方法
execution(void dao.BookDao.update())
描述方式二:执行dao.impl包下的BookDaoImpl类中的无参数update方法
execution(void dao.impl.BookDaoImpl.update()
(2.切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常 名)
execution(public User service.UserService.findById(int))
(3.通配符
// * 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
execution(public * com.itheima.*.UserService.find*(*))
// .. 多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
execution(public User com..UserService.findById(..))
// + 专用于匹配子类类型
execution(* *..*Service+.*(..))
(4.书写技巧
*所有代码按照标准规范开发,否则以下技巧全部失效
*描述切入点通常描述接口,而不描述实现类,如果描述到实现类,就出现紧耦合了
*访问控制修饰符针对接口开发均采用public描述(可省略访问控制修饰符描述)
*返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述
*包名书写尽量不使用..匹配,效率过低,常用*做单个包描述匹配,或精准匹配
*接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务 层接口名
*方法名书写以动词进行精准匹配,名词采用匹配,例如getById书写成getBy,selectAll书写成 selectAll
*参数规则较为复杂,根据业务方法灵活调整
*通常不使用异常作为匹配规则
(1.前置通知
` 修改MyAdvice,在before方法上添加@Before注解
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void dao.BookDao.update())")
private void pt(){}
@Before("pt()")
//此处也可以写成 @Before("MyAdvice.pt()"),不建议
public void before() {
System.out.println("before advice ...");
}
}
(2.后置通知
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void before() {
System.out.println("before advice ...");
}
@After("pt()")
public void after() {
System.out.println("after advice ...");
}
}
(3.环绕通知
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void dao.BookDao.update())")
private void pt(){}
@Pointcut("execution(dao.BookDao.select())")
private void pt2(){}
@Around("pt2()")
public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice ...");
//表示对原始操作的调用
Object ret = pjp.proceed();
System.out.println("around after advice ...");
return ret;
}
}
(4.返回后通知
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void dao.BookDao.update())")
private void pt(){}
@Pointcut("execution(int dao.BookDao.select())")
private void pt2(){}
@AfterReturning("pt2()")
public void afterReturning() {
System.out.println("afterReturning advice ...");
}
}
(5.异常后通知
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}
@Pointcut("execution(int com.itheima.dao.BookDao.select())")
private void pt2(){}
@AfterReturning("pt2()")
public void afterThrowing() {
System.out.println("afterThrowing advice ...");
}
}
从获取参数、获取返回值和获取异常三个方面来研究切入点的相关信息:
*获取切入点方法的参数,所有的通知类型都可以获取参数
*JoinPoint:适用于前置、后置、返回后、抛出异常后通知
* ProceedingJoinPoint:适用于环绕通知
*获取切入点方法返回值,前置和抛出异常后通知是没有返回值,后置通知可有可无,所以不做研究
*返回后通知
*环绕通知
*获取切入点方法运行异常信息,前置和返回后通知是不会有,后置通知可有可无,所以不做研究 *抛出异常后通知
*环绕通知
(1.非环绕通知获取方式
//在方法上添加JoinPoint,通过JoinPoint来获取参数
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* dao.BookDao.findName(..))")
private void pt(){}
@Before("pt()")
public void before(JoinPoint jp)
Object[] args = jp.getArgs();
System.out.println(Arrays.toString(args));
System.out.println("before advice ..." );
}
//...其他的略
}
//使用JoinPoint的方式获取参数适用于前置、后置、返回后、抛出异常后通知。剩下的大家自行去验
//证。
(2.环绕通知获取方式
//环绕通知使用的是ProceedingJoinPoint,因为ProceedingJoinPoint是JoinPoint类的子
//类,所以对于ProceedingJoinPoint类中应该也会有对应的getArgs()方法,我们去验证下
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* dao.BookDao.findName(..))")
private void pt(){}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp)throws Throwable {
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
Object ret = pjp.proceed();
return ret;
}
//其他的略
}
//pjp.proceed()方法是有两个构造方法,当需要修改原始方法的参数时,只能采用带有参数的方法,例如
//修改上面代码
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
args[0] = 666;
Object ret = pjp.proceed(args);
return ret;
}
(3.环绕通知获取返回值
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* dao.BookDao.findName(..))")
private void pt(){}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
args[0] = 666;
Object ret = pjp.proceed(args);
return ret;
}
//其他的略
}
(4.返回后通知获取返回值
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* dao.BookDao.findName(..))")
private void pt(){}
@AfterReturning(value = "pt()",returning = "ret")
public void afterReturning(Object ret) {
System.out.println("afterReturning advice ..."+ret);
}
//其他的略
}
(5.环绕通知获取异常
*只需要将异常捕获,就可以获取到原始方法的异常信息了
(6.抛出异常后通知获取异常
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(* dao.BookDao.findName(..))")
private void pt(){}
@AfterThrowing(value = "pt()",throwing = "t")
public void afterThrowing(Throwable t) {
System.out.println("afterThrowing advice ..."+t);
}
//其他的略
}
(1.在业务层接口上添加spring事务管理
public interface AccountService {
//配置当前接口方法具有事务
@Transactional
public void transfer(String out,String in ,Double money) ;
}
(2.设置事务管理器
//配置事务管理器,mybatis使用的是jdbc事务
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
(3.开启注解式事务驱动
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
上面这些属性都可以在@Transactional注解的参数上进行设置。
* readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true。
* timeout:设置超时时间单位秒,在多长时间之内事务没有提交成功就自动回滚,-1表示不设置超 时时间。
*rollbackFor:当出现指定异常进行事务回滚 noRollbackFor:当出现指定异常不进行事务回滚
* rollbackForClassName等同于rollbackFor,只不过属性为异常的类全名字符串 *noRollbackForClassName等同于noRollbackFor,只不过属性为异常的类全名字符串 *isolation设置事务的隔离级别
*DEFAULT :默认隔离级别, 会采用数据库的隔离级别
*READ_UNCOMMITTED : 读未提交
*READ_COMMITTED : 读已提交
*REPEATABLE_READ : 重复读取 SERIALIZABLE: 串行化
*propagation事务传播行为:
* 事务传播行为:事务协调员对事务管理员所携带事务的处理态度。 具体如何解决,就需要用到之前我们没有说的propagation属性。