少女祈祷中...

1.IoC控制反转

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

  • Spring技术对IoC思想进行了实现

  • Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部”。

  • IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

2.DI依赖注入

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

错误异常:

  • 获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException
  • 无参构造方法如果不存在,将抛出异常BeanCreationException

3.bean生命周期

3.1初始化容器

  1. 创建对象(内存分配)
  2. 执行构造方法
  3. 执行属性注入(set操作)
  4. 执行bean初始化方法

3.2使用bean

执行业务操作

3.3关闭、销毁容器

执行bean销毁方法

1.容器关闭前触发bean的销毁

2.关闭容器方式:

  • 手工关闭容器

    ConfigurableApplicationContext接口close()操作

  • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机

    ConfigurableApplicationContext接口registerShutdownHook()操作

    1
    2
    3
    4
    5
    6
    7
    public class AppForLifeCycle{
    public static void main(String[] args) {

    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ctx.close();
    }
    }

4.bean生命周期控制

配置

  • init-method
  • destroy-method

接口

  • InitializingBean
  • DisposableBean

4.依赖注入

4.1setter注入

4.1.1引用类型

  • 在bean中定义引用类型属性并提供可访问的set方法

    1
    2
    3
    4
    5
    6
    public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
    this.bookDao = bookDao;
    }
    }
  • 配置中使用property标签ref属性注入引用类型对象

1
2
3
4
<bean id = "bookService" class="com.itheima.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

4.1.2简单类型

  • 在bean中定义引用类型属性并提供可访问的set方法

    1
    2
    3
    4
    5
    6
    public class BookDaoImpl implements BookDao{
    private int connectionNumber;
    public void setconnectionNumber(int connectionNumber) {
    this.connectionNumber = connectionNumber;
    }
    }
  • 配置中使用property标签value属性注入简单类型对象

    1
    2
    3
    <bean id = "bookServiceDao" class="com.itheima.service.impl.BookDaoImpl">
    <property name="bookDaoconnectionNumber" value="10"/>
    </bean>

4.2构造器注入

4.2.1引用类型

  • 在bean中定义引用类型属性并提供可访问的构造方法

    1
    2
    3
    4
    5
    6
    public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    public BookServiceImpl(BookDao bookDao) {
    this.bookDao = bookDao;
    }
    }
  • 配置中使用 constructor-arg标签ref属性注入引用类型对象

1
2
3
4
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
</bean>
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"></bean>

4.2.2简单类型

  • 在bean中定义引用类型属性并提供可访问的set方法

    1
    2
    3
    4
    5
    6
    public class BookDaoImpl implements BookDao{
    private int connectionNumber;
    public void setconnectionNumber(int connectionNumber) {
    this.connectionNumber = connectionNumber;
    }
    }
  • 配置中使用property标签value属性注入简单类型对象

    1
    2
    3
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <constructor-arg name="connectionNumber" value="10"></constructor-arg>
    </bean>

4.2.3参数适配

配置中使用 constructor-arg 标签 type 属性设置按参数类型注入

1
2
3
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<construct-arg type="int" value="10"></construct-arg>
</bean>

配置中使用 constructor-arg 标签 index 属性设置按形参位置注入

1
2
3
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<constructor-arg index="0" value="10"></constructor-arg>
</bean>

4.3依赖注入选择方式

1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现

2.可选依赖使用setter注入进行,灵活性强

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

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

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

6.自己开发的模块使用setter注入

4.4自动装配

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

自动装配方式

  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启动自动装配

依赖自动装配特征:

  1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  2. 使用按类型装配时(byType)必须保障容器中相同类型的 bean 唯一,推荐使用
  3. 使用按名称装配时(byType)必须保障容器中具有指定名称的 bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于 setter 注入与构造器注入,同时出现时自动装配配置失效

4.5集合注入

4.5.1注入数组对象

1
2
3
4
5
6
7
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>

4.5.2注入List对象

1
2
3
4
5
6
7
<property name="list">
<list>
<value>baozi</value>
<value>baobao</value>
<value>xiaobaozi</value>
</list>
</property>

4.5.3注入Set对象

1
2
3
4
5
6
7
<property name="set">
<set>
<value>baozi</value>
<value>baobao</value>
<value>xiaobaozi</value>
</set>
</property>

4.5.4注入Map对象

1
2
3
4
5
6
7
<property name="map">
<map>
<entry key="1" value="baozi"/>
<entry key="2" value="xiaobaozi"/>
<entry key="3" value="baobao"/>
</map>
</property>

4.5.5注入Properties对象

1
2
3
4
5
6
7
<property name="properties">
<props>
<prop key="1">baozi</prop>
<prop key="2">xiaobaozi</prop>
<prop key="3">baobao</prop>
</props>
</property>

4.6数据源对象管理bean

1
2
3
4
5
6
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/student"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>

4.7加载properties文件

4.7.1开启context命名空间

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:property-placeholder location="jdbc.properties" />
</beans>

4.7.2使用context命令空间,加载指定 properties 文件

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:property-placeholder location="jdbc.properties" />
</beans>

4.7.3使用 ${} 读取加载的属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:property-placeholder location="jdbc.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>

5.容器

5.1创建容器

5.1.1类路径加载配置文件

1
2
3
4
5
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}

5.1.2文件路径加载配置文件

1
2
3
4
5
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
}
}

5.1.3加载多个配置文件

1
2
3
4
5
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml", "applicationContext2.xml");
}
}

5.2获取bean

5.2.1使用bean名称获取

1
2
3
4
5
6
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
}
}

5.2.2使用bean名称获取指定类型

1
2
3
4
5
6
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
}
}

5.2.3使用bean类型获取

1
2
3
4
5
6
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = ctx.getBean(BookDao.class);
}
}

5.3容器类层次结构

image-20231009191547912

5.4BeanFactory初始化

所有容器类的顶层接口

  • 类路径加载配置文件

    1
    2
    3
    4
    Resoure resources = new ClassPathResource("applicationContext.xml");
    BeanFactory bf = new XmlBeanFactory(resource);
    BookDao bookDao =bf.getBean("bookDao",BookDao.class)
    bookDao.save();
  • BeanDactory创建完毕后,所有的bean均为延迟加载

5.5核心容器总结

5.5.1容器相关

  1. BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载

  2. ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载

  3. ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能

  4. ApplicationContext接口常用初始化类

    ​ ClassPathXmlApplicationContext

    ​ FileSystemXmlApplicationContext

5.5.2bean相关

1
2
3
4
5
6
7
<bean 
id="bookDao" //bean的Id
name="dao bookDaoImpl daoImpl" //bean别名
class="com.itheima.dao.impl.BookDaoImpl" //bean类型静态工厂类FactoryBean类
scope="singleton" //控制bean的实例数量
autowide="byType" //自动装配类型
/>

6.注解开发

6.1注解开发定义bean

6.1.1使用@Component定义bean

1
2
3
@Component("bookDao")
public class BookDaoImpl implements BookDao {
}
1
2
3
@Component
public class BookServiceImpl implements BookService {
}

6.1.2 核心配置文件中通过组件扫描加载 bean

1
<context:component-scan base-package="com.itheima"/>

6.1.3Spring提供@Component注解的三个衍生注解

  1. @Controller:用于表现层bean定义

  2. @Service:用于业务层bean定义

  3. @Repository:用于数据层bean定义

    1
    2
    3
    @Repository("bookDao")
    public class BookDaoImpl implements BookDao {
    }
    1
    2
    3
    @Service
    public class BookServiceImpl implements BookService {
    }

6.2纯注解开发

  1. Spring3.0 开启了纯注解开发模式,使用 Java 类替代配置文件,开启了 Spring 快速开发赛道
  2. Java 类代替 Spring 核心配置文件(代替 xml 配置文件)
  3. @Configuration 注解用于设定当前类为配置类
  4. @ComponentSacn 注解用于扫描路径,此注解只能添加一次,多个数据可以使用数组形式

6.3bean管理

6.3.1bean作用范围

  1. 使用 @Scope 定义 bean 作用范围

    1
    2
    3
    4
    @Repository
    @Scope("singleton")
    public class BookDaoImpl implements BookDao{
    }
  2. bean 的生命周期

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Reponsitory
    @Scope("singleton") // 单例:singleton 多例:prototype
    public class BookServiceImpl implements BookDao {
    public BookDaoImpl() {
    System.out.println("book dao constructor ...");
    }
    @PostConstruct
    public void init() {
    System.out.println("book init...");
    }
    @PreDestroy
    public void destory() {
    System.out.println("book Destory...");
    }
    }

6.4依赖注入

6.4.1自动装配

@Autowired解决引用注入

@Qualifier指定注入的bean的id或名称

@Value注入简单类型或值类型

6.4.2读取properties文件

@PropertySource加载外部配置文件(不支持通配*)

6.5第三方bean管理

使用@bean配置第三方bean

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class SpringConfig {
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/sstudent");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

使用独立的配置类管理第三方 bean

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/student");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

将独立配置类加入核心配置

方式一:使用 @Import 注解手动加入配置类到核心配置,此注解只能添加一次,多个数据采用数组格式

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/student");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
1
2
3
4
@Configuration
@Import(JdbcConfig.class)
public class SpringConfig {
}

方式二:使用 @ComponentScan 注解扫描配置所在的包,加载对应的配置类信息

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class JdbcConfig {
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/student");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
1
2
3
4
@Configuration
@ComponentScan("com.baozi.config")
public class SpringConfig {
}

6.6第三方bean依赖注入

简单类型注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/student")
private String url;
@Value("root")
private String username;
@Value("root")
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;
}
}

引用类型注入

引用类型注入只需要为 bean 定义方法设置形参即可,容器会根据类型自动装配对象

1
2
3
4
5
6
7
8
9
10
11
12
public class JdbcConfig {
@Bean
public DataSource dataSource(BookService bookService) {
System.out.println(bookService);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/student");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

6.7 XML 配置与注解配置

功能 XML配置 注解
定义bean bean标签:id属性,class属性 @component @controller @service @Repository @ComponentScan
设置依赖注入 setter注入,构造器注入 @Autowried Qualifier Value
配置第三方bean bean标签,静态工厂,实例工厂,FactoryBean @Bean
作用范围 scope属性 @Scope
生命周期 标准接口:init-method destory-method @PostController @PreDestory

7.AOP

7.1AOP简介

  1. AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何阻止程序结构
  2. 作用:在不惊动原始设计的基础上对其进行增强
  3. Spring 理念:无入侵式 / 无侵入式

7.2AOP核心概念

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

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

  2. 切入点:匹配连接点的式子

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

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

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

  3. 通知:在切入点执行的操作,也就是共性功能

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

  4. 通知类:定义通知的类

  5. 切面:描述通知与切入点的对应关系

7.3AOP入门案例

7.3.1 导入 aop 相关坐标

1
2
3
4
5
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

7.3.2定义 dao 接口与实现类

1
2
3
4
public interface BookDao {
public void save();
public void update();
}
1
2
3
4
5
6
7
8
9
10
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save ...");
}
public void update() {
System.out.println("book dao update ...");
}
}

7.3.3定义通知类,制作通知

1
2
3
4
5
public class Advice {
public void before {
System.out.println(System.currentTimeMillis());
}
}

7.3.4定义切点

1
2
3
4
public class Advice {
@Pointcut("excution(void com.baozi.dao.BookDao.update())")
private void pt(){}
}

7.3.5帮抵挡切入点与通知关系

1
2
3
4
5
6
7
8
public class MyAdvice {
@Pointcut("excution(void com.baozi.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void before() {
System.out.println(System.currentTimeMillis());
}
}

7.3.6定义通知类接受 Spring 容器管理

1
2
3
4
5
6
7
8
9
10
@Compoent
@Aspect
public class MyAdvice {
@Pointcut("excution(void com.baozi.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void before() {
System.out.println(System.currentTimeMillis());
}
}

7.3.7开启 Spring 对 AOP 注解驱动支持

1
2
3
4
5
@Congiguration
@CompoentScan("com.baozi")
@EnableAspectJAutoProxy
public class SpringConfig {
}

7.4AOP工作流程

  1. Spring容器启动

  2. 读取所有切面配置中的切入点

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

    ·匹配失败,创建对象

    ·匹配成功,创建原始对象(目标对象)的代理对象

  4. 获取bean执行方法

    ·获取bean,调用方法并执行,完成操作

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

核心概念

  1. 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
  2. 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

7.5AOP切入点表达式

7.5.1表达式格式

切入点表达式标准格式:动作关键词(访问修饰符 返回值 包名。类名 / 接口名。方法名(参数)异常名)

1
execution (public User com.baozi.service.UserService.findById(int))
  1. 动作关键字:描述切入点的行为动作
  2. 访问修饰符:public private 等
  3. 返回值
  4. 包名
  5. 类 / 接口名
  6. 方法名
  7. 参数
  8. 异常名:方法定义中抛出指定异常

7.5.2通配符

  1. *:单个独立的任意符号,可以独立出现,也可以作为前缀或后缀的匹配符出现
  2. …:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
  3. +:专用于匹配子类类型

7.6AOP通知类型

7.6.1前置通知

  1. 名称: @Before
  2. 类型:方法注解
  3. 位置:通知方法定义上方
  4. 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行
  5. 相关属性:value(默认):切入点方法名,格式为类名。方法名 ()
1
2
3
4
@Before("pt()")
public void before() {
System.out.println("before advice ...");
}

7.6.2后置通知

  1. 名称: @After
  2. 类型:方法注解
  3. 位置:通知方法定义上方
  4. 作用:设置当前通知方法与切入点之间的绑定关系,,当前通知方法在原始切入点方法后运行
  5. 相关属性:value(默认):切入点方法名,格式为类名。方法名 ()
1
2
3
4
@After("pt()")
public void after() {
System.out.println("after advice ...");
}

7.6.3环绕通知

  1. 名称: @Around
  2. 类型:方法注解
  3. 位置:通知方法定义上方
  4. 作用:设置当前通知方法与切入点之间的绑定关系,,当前通知方法在原始切入点方法前后运行
1
2
3
4
5
6
7
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice ...");
Object ret = pjp.proceed();
System.out.println("around after advice ...");
return ret;
}

7.6.4返回值通知

  1. 名称: @AfterReturning
  2. 类型:方法注解
  3. 位置:通知方法定义上方
  4. 作用:设置当前通知方法与切入点之间的绑定关系,,当前通知方法在原始切入点方法正常执行完毕后运行
  5. 相关属性:value(默认):切入点方法名,格式为类名。方法名 ()
1
2
3
4
@AfterReturning("pt()")
public void afterReturning() {
System.out.println("afterReturning advice ...");
}

7.6.5抛出异常后通知

  1. 名称: @AfterThrowing
  2. 类型:方法注解
  3. 位置:通知方法定义上方
  4. 作用:设置当前通知方法与切入点之间的绑定关系,,当前通知方法在原始切入点方法运行抛出异常后执行
  5. 相关属性:value(默认):切入点方法名,格式为类名。方法名 ()
1
2
3
4
@AfterThrowing("pt()")
public void afterThrowing() {
System.out.println("afterThrowing advice ...");
}

7.7AOP通知获取数据

7.7.1方法

  1. 获取切入点方法的参数

  2. JoinPoint:适用于前置、后置、返回后、抛出异常后通

  3. ProceedJoinPoint:适用于环绕通知

  4. 获取切入点方法返回值

    返回后通知

    环绕通知

  5. 获取切入点方法运行异常信息

    抛出异常后通知

    环绕通知

7.7.2实现

JoinPoint 对象描述了连接点方法的运行状态,可以获取到原始方法的适用参数

1
2
3
4
5
@Before("pt()")
public void before(JoinPoint jp) {
Object[] args = jp.getArgs();
System.out.println(Arrays.toString(args));
}

ProceedJointPoint 是 JoinPoint 的子类

1
2
3
4
5
6
7
@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;
}

抛出异常后通知可以获取切入点方法中出现的异常信息,适用形参可以接收对应的异常对象

1
2
3
4
@AfterReturning(value = "pt()", returning = "ret")
public void afterReturning(String ret) {
System.out.println("afterReturning advice ..." + ret);
}

环绕通知中可以手工书写对原始方法的调用,得到结果为原始方法的返回值

1
2
3
4
5
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
return ret;
}

8.Spring事务

8.1Spring事务简介

  1. 事物作用:在数据层保障一系列的数据库操作同成功同失败
  2. Spring 事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败

8.1.1早业务层接口上添加 Spring 事务管理

1
2
3
4
public class AccountService {
@Transactional
public void transfer(String out, String in, Double money);
}

8.1.2设置平台事务管理器

1
2
3
4
5
6
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager ptm = new DataSourceTransactionManager();
ptm.setDataSource(dataSource);
return ptm;
}

8.1.3 开启注解式事物驱动

1
2
3
4
5
6
7
@Configuration
@ComponentScan("com.baozi")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MyBatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}

8.2Spring事务角色

  1. 事务管理员:发起事务方,在 Spring 中通常指代业务层开启事务的方法
  2. 事务协调员:加入事务方,在 Spring 中通常指代数据层方法,也可以是业务层方法

8.3Spring事务属性

8.3.1设置事务基本属性

属性 作用 示例
readOnly 设置是否只读事务 readOnly=true 只读事务
timeout 设置事务超时时间 timeout=-1 永不超时
rollbackFor 设置事务回滚异常(class) rollbackFor={NullPointException.calss}
rollbackForClassName 设置事务回滚异常(String) 同上为字符串格式
noRollbackFor 设置事务不回滚异常(class) noRollbackFor={NullPointException.class}
noRollbackForClassName 设置事务不回滚异常(String) 同上格式为字符串
propagation 设置事务传播行为

8.3.2事务的传播行为

事务协调员对事物管理员所携带事务处理的态度