黑马程序员SSM_Spring笔记(自用)

根据黑马程序员的课程资料整理所得,仅用于学习使用,如有侵权,请联系删除

目录

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)

Spring Framework是spring家族中的底层框架及设计框架

Spring的系统架构

黑马程序员SSM_Spring笔记(自用)_第1张图片

介绍路线如标号所示. 

Spring_核心概念及入门案例

1. IOC(Inversion of Control)控制反转

        使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到 外部,此思想称为控制反转。

        spring与ioc的关系:Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部".

        ioc容器中存放的是一个个数据层和业务层的bean对象

2.DI(Dependency Injection)依赖注入

        在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

        黑马程序员SSM_Spring笔记(自用)_第2张图片

1.IOC实现案例:

1.创建项目:

黑马程序员SSM_Spring笔记(自用)_第3张图片

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的配置

黑马程序员SSM_Spring笔记(自用)_第4张图片


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();

2.DI入门案例:(项目创建在下文中不再讲解)

1.删除业务层中使用new的方式创建的dao对象

2.在业务层提供BookDao的setter方法

3.在配置文件中添加依赖注入的配置



    
    
    

4.运行程序调用方法

Spring_bean配置,实例化及生命周期

1.bean配置

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对象:表现层对象 业务层对象 数据层对象 工具对象

2.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;
}

3.bean生命周期

方法一:

步骤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");
}
}

Spring_注入问题

[1]. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现,强制依赖指对象在创建的过程中必须要注入指定的参数

[2]. 可选依赖使用setter注入进行,灵活性强,可选依赖指对象在创建过程中注入的参数可有可无

[3]. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相 对严谨

[4]. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选 依赖的注入

[5]. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注 入

[6]. 自己开发的模块推荐使用setter注入

1.setter引用类型注入(在实现类中提供setter方法



 2.setter简单类型注入(在实现类中提供setter方法



3.构造器注入引用类型(在实现类中提供构造方法



4.构造器注入简单类型(在实现类中提供构造方法



5.依赖自动装配(提供setter方法

(1.按类型,类型匹配唯一



(2.按名称,具有指定名称的bean



6.集合注入

(1.array注入




...


(2.list注入




...


(3.set注入




...


(4.Map注入







(5.properties注入




...


Spring_容器

容器类结构层次

黑马程序员SSM_Spring笔记(自用)_第5张图片

Spring_IOC/DI注解开发

1.注解开发定义bean

(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);
}

2.纯注解开发模式,使用Java类替代配置文件

(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");
}
}

3.注解开发bean作用范围与生命周期管理

(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

4.注解开发依赖注入

(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注解属性中不支持使用通配符*,运行会报错

5.注解开发管理第三方bean,以下以druid连接池为例

(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 {
}

6.注解开发实现为第三方bean注入资源,接着上例

(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配置和注解的区别

黑马程序员SSM_Spring笔记(自用)_第6张图片

Spring_Spring整合mybatis以及junit

1.整合mybatis

(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中获取对象并运行

2.整合junit

(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());
}
}

Spring_AOP简介

1.AOP概念:

        *AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程 序结构。

AOP作用:在不惊动原始设计的基础上为其进行功能增强,前面咱们有技术就可以实现这样的功能即代 理模式

*连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等

        *在SpringAOP中,理解为方法的执行

*切入点(Pointcut):匹配连接点的式子

        *在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法

                *一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方 法

                *法 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意 方法,所有带有一个参数的方法

        *连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一 定要被增强,所以可能不是切入点。

*通知(Advice):在切入点处执行的操作,也就是共性功能

        *在SpringAOP中,功能最终以方法的形式呈现

*通知类:定义通知的类

*切面(Aspect):描述通知与切入点的对应关系。

黑马程序员SSM_Spring笔记(自用)_第7张图片

2.入门案例:

(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.运行

3.AOP工作流程

流程1:Spring容器启动

          *需要被增强的类,如:BookServiceImpl

          *通知类,如:MyAdvice

          *注意此时bean对象还没有创建成功

流程2:读取所有切面配置中的切入点

流程3:初始化bean, 判定bean对应的类中的方法是否匹配到任意切入点

        *注意第1步在容器启动的时候,bean对象还没有被创建成功。

        * 要被实例化bean对象的类中的方法和切入点进行匹配

        *匹配失败,创建原始对象,如UserDao

                *匹配失败说明不需要增强,直接调用原始对象的方法即可。

        *匹配成功,创建原始对象(目标对象)的代理对象,如: BookDao

        *匹配成功说明需要对其进行增强 对哪个类做增强,这个类对应的对象就叫做目标对象

        *因为要对目标对象进行功能增强,而采用的技术是动态代理,所以会为其创建一个代理对象          *最终运行的是代理对象的方法,在该方法中会对原始方法进行功能增强

流程4:获取bean执行方法

        * 获取的bean是原始对象时,调用方法并执行,完成操作

        *获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

验证容器中是否为代理对象

        *为了验证IOC容器中创建的对象和我们刚才所说的结论是否一致,首先先把结论理出来:

                *如果目标对象中的方法会被增强,那么容器中将存入的是目标对象的代理对象

                *如果目标对象中的方法不被增强,那么容器中将存入的是目标对象本身。 

         *验证思路

                1.要执行的方法,不被定义的切入点包含,即不要增强,打印当前类的getClass()方法

                2.要执行的方法,被定义的切入点包含,即要增强,打印出当前类的getClass()方法

                3.观察两次打印的结果

4.AOP切入点表达式

(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

        *参数规则较为复杂,根据业务方法灵活调整

        *通常不使用异常作为匹配规则

5.AOP通知类型

(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 ...");
}
}

6.AOP通知获取数据

从获取参数、获取返回值和获取异常三个方面来研究切入点的相关信息:

*获取切入点方法的参数,所有的通知类型都可以获取参数

        *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);
}
//其他的略
}

spring_事务管理

1.spring事务简介

(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 {
}

2.spring事务配置

黑马程序员SSM_Spring笔记(自用)_第8张图片

上面这些属性都可以在@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属性。

黑马程序员SSM_Spring笔记(自用)_第9张图片

你可能感兴趣的:(java,spring)