详解Spring,学习spring这一篇就够了。快速掌握-------知识总结

spring官网 http://spring.io/

目录

1.Spring核心概念

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

      1.2.Bean:被管理的对象称为Bean

      1.3.DI 依赖注入: 在容器中建立bean与bean之间的依赖关系的整个过程

      1.4.目标:充分解耦

2.IoC入门案例

3.DI入门案例

4.bean的基础配置 

       4.1.给bean起别名

       4.2.scope作用域

       4.3 开启懒加载 

5.bean的实例化

        5.1.构造方法实现

        5.2.静态工厂实现

        5.3.实例工厂初始化(了解)

        5.4.FactoryBean(掌握)

6.bean的生命周期

        6.1配置方式

                6.1.1 close()方法:

                6.1.2 设置关闭钩子

        6.2 实现接口 

7.依赖注入方式

        7.1 setter注入--简单类型

        7.2 setter注入--引用类型

        7.3 构造注入器--引用类型

        7.4 构造器注入--简单类型

8. 依赖自动装配

        8.1按类型装配(主要用)

        8.2 按名称装配 

 9. 集合等类型注入

10. 第三方工具注入举例

        10.1 加载properties文件

 11. 注解开发

         11.1 注解方式管理第三方资源

12 AOP 面向切面编程

        12.1 概念介绍

        12.2 AOP入门案例

        12.3 AOP工作流程

        12.4 AOP切入点表达式

        12.5 AOP通知类型

        12.6 AOP获取数据

13. 事务管理

        13.1 事务简介

        13.2 事务角色

        13.3 事务属性


1.Spring核心概念

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

                1.spring提供了一个容器,成为IoC容器,用来充当IoC思想中的外部

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

      1.2.Bean:被管理的对象称为Bean

      1.3.DI 依赖注入: 在容器中建立bean与bean之间的依赖关系的整个过程

      1.4.目标:充分解耦

                1.使用IoC容器管理bean

                2.在IoC容器内将有依赖关系的bean进行关系绑定

2.IoC入门案例

        maven模块结构(此时的serviceImpl对象中,new了daoImpl对象

        可用此方法加载文件的绝对路径(了解)

   ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml"); 

        另外两种获取bean的方式(了解)

       BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
       BookDao bookDao = ctx.getBean(BookDao.class);

        导入坐标到pom.xml文件

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

    <!-- 测试jar包 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

        applicationContext.xml配置文件(注:id不能重复,具有唯一性)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   

  
    <!--bean标签标示配置bean
    id属性标示给bean起名字
    class属性表示给bean定义类型-->
    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.jinruidai.service.impl.BookServiceImpl"/>
      

</beans>

3.DI入门案例

        3.1.基于IoC管理bean

        3.2.不能保留new形式创建的dao对象

        3.3.提供方法让dao对象进入到service中

        3.4.配置实现

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->

    <!--2.配置bean-->
    <!--bean标签标示配置bean
    id属性标示给bean起名字
    class属性表示给bean定义类型-->
    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl"/>

    <!-- 变化在这里 -->

    <bean id="bookService" class="com.jinruidai.service.impl.BookServiceImpl">
        <!--7.配置server与dao的关系-->
        <!--property标签表示配置当前bean的属性
        name属性表示配置哪一个具体的属性,是对象中的属性名
        ref属性表示参照哪一个bean-->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

4.bean的基础配置 

      4.1.给bean起别名

                     异常NoSuchBeanDefinitionException: 要么是getBean("") 方法中名字写错,要么是配置文件中找不到“service44”该名字

 Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'service44' available

      4.2.scope作用域

在bean标签中加  scope属性

 修改后进行测试,发现两个对象的地址值不一致,表明不再是单例模式

        问题.为什么bean默认单例?        防止类过多,不负责管理类的数量

        4.3 开启懒加载 

           配置属性 lazy-init="true"

5.bean的实例化

        5.1.构造方法实现

                配置文件以及测试代码和"3.IoC注入”方式一致

            异常BeanCreationException:表示无参构造方法不存在

Exception in thread "main" org.springframework.beans.factory.BeanCreationException:

        5.2.静态工厂实现

         xml配置如下,要把静态工厂方法名写在factory-method属性中

   <!--方式二:使用静态工厂实例化bean-->
    <bean id="orderDao" class="com.jinruidai.factory.OrderDaoFactory" factory-method="getOrderDao"/>

        5.3.实例工厂初始化(了解)

                 属性配置如图

         5.4.FactoryBean(掌握)

                可选方法的内容

                 xml配置

 <!--方式四:使用FactoryBean实例化bean-->
    <bean id="userDao" class="com.jinruidai.factory.UserDaoFactoryBean"/>

6.bean的生命周期

  • 创建对象(内存分配)        
  • 执行构造方法
  • 执行属性注入(set操作)
  • 执行bean初始化方法
  • 使用bean
  • 销毁bean

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

}

               xml配置 

    <!--init-method:设置bean初始化生命周期回调函数-->
    <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象-->
    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

        getBean()后发现,destory()方法并没执行。因为程序运行完,虚拟机直接退出了,没有给bean销毁的会,有以下两种方式解决:

                6.1.1 close()方法:

        用ClassPathXmlApplicationContext 接口里的close()方法,销毁bean。再次运行发现,destory()方法执行

public class AppForLifeCycle {
    public static void main( String[] args ) {
        
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //关闭容器
        ctx.close();
    }
}

                6.1.2 设置关闭钩子

        程序中设置一个标志,告诉虚拟机退出前记得关闭容器

public class AppForLifeCycle {
    public static void main( String[] args ) {

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

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
        ctx.registerShutdownHook();
        //关闭容器
        //ctx.close();
    }
}

        6.2 实现接口 

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {

    //销毁前执行方法
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }
    //属性注入完之后执行
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}

         实现接口后 IoC容器中正常配置该对象即可

7.依赖注入方式

  •         向一个类中传递数据的方式有2中
  •                 普通方法(setter)
  •                 构造方法

  •         setter注入(适合可选依赖注入,会出现null对象的情况,导致报错。自己开发的模块推荐使用)
  •                 简单类型
  •                 引用类型
  •         构造器注入(倡导使用)
  •                 简单类型
  •                 引用类型

        7.1 setter注入--简单类型

public class BookDaoImpl implements BookDao {

    private String databaseName;
    private int connectionNum;
    //setter注入需要提供要注入对象的set方法
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }
    //setter注入需要提供要注入对象的set方法
    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}

                xml配置

   <!--注入简单类型-->
    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--value属性:设置注入简单类型数据值-->
        <property name="connectionNum" value="100"/>
        <property name="databaseName" value="mysql"/>
    </bean>

        7.2 setter注入--引用类型


public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    private UserDao userDao;
    //setter注入需要提供要注入对象的set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    //setter注入需要提供要注入对象的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
}

                xml配置 

 <!--注入简单类型-->
    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl"/>

    <bean id="userDao" class="com.jinruidai.dao.impl.UserDaoImpl"/>

    <!--注入引用类型-->
    <bean id="bookService" class="com.jinruidai.service.impl.BookServiceImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--ref属性:设置注入引用类型bean的id或name-->
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>

        7.3 构造注入器--引用类型

public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    private UserDao userDao;

    public BookServiceImpl(BookDao bookDao, UserDao userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
}

                xml配置

    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl"/>

    <bean id="userDao" class="com.jinruidai.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.jinruidai.service.impl.BookServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

        7.4 构造器注入--简单类型

public class BookDaoImpl implements BookDao {
    private String databaseName;
    private int connectionNum;

    public BookDaoImpl(String databaseName, int connectionNum) {
        this.databaseName = databaseName;
        this.connectionNum = connectionNum;
    }

    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}

                xml配置

    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl">
        根据构造方法参数名称注入
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="mysql"/>
    </bean>

        第二种方式,根据参数类型来赋值,解耦(形参变名,不影响配置文件)

    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl">
        根据构造方法参数类型注入
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="mysql"/>
    </bean>

        第三种方式,解决参数类型重复问题,使用位置解决参数匹配

    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl">
        <!--根据构造方法参数位置注入-->
        <constructor-arg index="0" value="mysql"/>
        <constructor-arg index="1" value="100"/>
    </bean>

8. 依赖自动装配

        IoC容器根据bean所依赖的资源在容器中自动查找并注入bean的过程;

        自动装配只用于引用类型;自动装配优先级低于setter注入与构造器注入,同时出现自动装配配置失效

  •         按类型
  •         按名称
  •         按构造方法(不推荐使用)

         8.1按类型装配(主要用)

        实体类如下,需提供setter方法

        使用 autowire="byType" 属性。类型匹配必须唯一匹配,例class =com.jinruidai.dao.impl.BookDaoImpl 是唯一的一个bean

    <bean class="com.jinruidai.dao.impl.BookDaoImpl"/>
    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.jinruidai.service.impl.BookServiceImpl" autowire="byType"/>

        异常 

NoUniqueBeanDefinitionException  -- 类型不唯一

        8.2 按名称装配 

        xml配置,设置属性 autowire="byName"。        id="bookDao"  id需唯一

    <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl"/>

    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.jinruidai.service.impl.BookServiceImpl" autowire="byName"/>

NullPointerException  -- id不唯一,报空指针异常

 9. 集合等类型注入

            实体类

package com.jinruidai.dao.impl;

import com.jinruidai.dao.BookDao;

import java.util.*;

public class BookDaoImpl implements BookDao {

    private int[] array;

    private List<String> list;

    private Set<String> set;

    private Map<String,String> map;

    private Properties properties;


    public void setArray(int[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }


    public void save() {
        System.out.println("book dao save ...");

        System.out.println("遍历数组:" + Arrays.toString(array));

        System.out.println("遍历List" + list);

        System.out.println("遍历Set" + set);

        System.out.println("遍历Map" + map);

        System.out.println("遍历Properties" + properties);
    }
}

         xml配置

 <bean id="bookDao" class="com.jinruidai.dao.impl.BookDaoImpl">
        <!--数组注入-->
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
        <!--list集合注入-->
        <property name="list">
            <list>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>chuanzhihui</value>
            </list>
        </property>
        <!--set集合注入-->
        <property name="set">
            <set>
                <value>itcast</value>
                <value>itheima</value>
                <value>boxuegu</value>
                <value>boxuegu</value>
            </set>
        </property>
        <!--map集合注入-->
        <property name="map">
            <map>
                <entry key="country" value="china"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="kaifeng"/>
            </map>
        </property>
        <!--Properties注入-->
        <property name="properties">
            <props>
                <prop key="country">china</prop>
                <prop key="province">henan</prop>
                <prop key="city">kaifeng</prop>
            </props>
        </property>
    </bean>

10. 第三方工具注入举例

        此处用c3p0连接池举例;先导入对应的依赖

     <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <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.47</version>
        </dependency>
    </dependencies>

        xml中进行配置,导入第三方工具方式都大同小异,至于需要注入哪个类,设置类里的什么属性,需要自行查询文档

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
        <property name="maxPoolSize" value="1000"/>
    </bean>

        测试类

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    
    }
}

        10.1 加载properties文件

        创建properties文件,写入以下内容 

        spring需要开启新的命名空间,在xml头部分内容中加入方框内的内容

 xmlns:context="http://www.springframework.org/schema/context"

 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context.xsd

         在配置文件中添加新配置;location 属性识别源码以及resource文件夹下的文件;

system-properties-mode="NEVER" 属性,防止(若properties key和系统重名,则会优先读取系统的值)读取系统自带的值

<!--    1.开启context命名空间-->
<!--    2.使用context空间加载properties文件-->
<!-- classpath*:*.properties  :  设置加载当前工程类路径和当前工程所依赖的所有jar包中的所有properties文件 -->
 <context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

         使用${}方式取properties里的值

         此种读取方式也适用于类的属性

 11. 注解开发

        2.5版本的spring注解已比较完善。3.0时推出纯注解开发。配置文件中配置如下--开启扫描包

        以下列出常用注解

 <context:component-scan base-package="com.jinruidai"/>
注解用途
@Component定义bean;可加括号,里面写上bean的名字
@Controller @Component的衍生类,功能一样,为了代码具有可读性。用在控制层
@Service@Component的衍生类,功能一样,为了代码具有可读性。用在服务层
@Repository@Component的衍生类,功能一样,为了代码具有可读性。用在持久层
@Configuration声明当前类为Spring配置类
@ComponentScan({"com.jinruidai.service", "com.jinruidai.dao"})设置bean扫描路径,多个路径书写为字符串数组格式
@Scope(" ")设置bean的作用范围 singleton和prototype
@PostConstruct加在方法上 设置bean的初始化方法
@PreDestroy加在方法上 设置bean的销毁方法
@Bean加在方法上  表示当前方法的返回值是一个bean,当前方法的形参根据类型自动装配
@Autowired加在属性上(不需要set方法) 注入引用类型,自动装配模式,默认按类型装配
@Qualifier自动装配bean时按bean名称装配,必须依赖@Autowired
@Value("")注入简单类型(无需提供set方法) 可取properties文件值
@PropertySource({"jdbc.properties"})加在配置类上 加载properties配置文件,可加多个
@Import({JdbcConfig.class})在配置类中 导入配置信息

        AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器

 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

         11.1 注解方式管理第三方资源

        此处用druid连接池举例

@Configuration
public class JdbcConfig {
    //1.定义一个方法获得要管理的对象
    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private String url;
    @Value("root")
    private String userName;
    @Value("root")
    private String password;
    //2.添加@Bean,表示当前方法的返回值是一个bean
    //@Bean修饰的方法,形参根据类型自动装配
    @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;
    }
}

12 AOP 面向切面编程

一种编程范式,指导开发者如何组织程序结构。在不惊动原始设计的基础上为其进行功能增强

        12.1 概念介绍

        当前有一个类里有save()方法

         当我在测试类里调用不同的方法,改变save()方法里的内容,但不影响程序

         分析以及概念

         12.2 AOP入门案例

  •                 可以用xml或者注解实现,这里采用注解方法
  •                 业务:在接口执行前输出当前系统时间
  •                 思路:导入坐标,制作连接点方法,制作共性功能,制定切入点,绑定关系(切面)

       执行update()方法时,也要输出系统时间

        pom.xml导入依赖 

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>
  </dependencies>

         编写切面类

可以直接这样写:

@Before("execution(* com.example.spring04_aop.service.UserService.insert(..))")

         配置类

         测试类

         12.3 AOP工作流程

  •                 spring容器启动
  •                 读取所有切面配置中的切入点        
  •                 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
  •                                 匹配失败,创建对象
  •                                 匹配成功,创建原始对象(目标对象)的代理对象
  •                 获取bean执行方法
  •                                 获取bean,调用方法并执行,完成操作
  •                                 获取的bean时代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

        12.4 AOP切入点表达式

标准格式:动作关键字(访问修饰符   返回值   包名.类/接口名.方法名(参数)异常名)

  •         动作关键字:如execution
  •         访问修饰符:public等,可省略
  •         异常名:可省略
//单个方法
@Pointcut("execution(void com.jinruidai.dao.BookDao.update())")
@Pointcut("execution(void com.jinruidai.dao.impl.BookDaoImpl.update())")

//表示方法要带有任意 一个 参数,返回值是任意类型
@Pointcut("execution(* com.jinruidai.dao.impl.BookDaoImpl.update(*))")    

//*代表任意一个
@Pointcut("execution(void com.*.*.*.update())")

//..代表多个 任意包下的有任意参数的方法  即匹配所有
@Pointcut("execution(* *..*(..))")

//方法名是e结尾的
@Pointcut("execution(* *..*e(..))")

@Pointcut("execution(void com..*())")
@Pointcut("execution(* com.jinruidai.*.*Service.find*(..))")

        12.5 AOP通知类型

           前置通知,后置通知,环绕通知(重点),返回后通知(了解),抛出异常后通知(了解)

  •         前置通知 @Before ,后置 @After
  •         环绕通知@Around 如下:

         注意事项:

  1.                              必须依赖形参,未使用形参将直接跳过原始方法
  2.                             原始方法返回值为void AOP类里的方法返回值可写void,但建议写成Object
  3.                             环绕通知方法必须抛出异常
@Component
@Aspect
public class MyAdvice {
    @Pointcut("execution(void com.jinruidai.dao.BookDao.update())")
    private void pt(){}

    @Pointcut("execution(int com.jinruidai.dao.BookDao.select())")
    private void pt2(){}

    //写上形参ProceedingJoinPoint pjp
    @Around("pt2()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //扩展方法
        //获取执行的签名对象
        Signature signature = pjp.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();
        

        System.out.println("around before advice ...");
        //表示对原始操作的调用
        Object ret = pjp.proceed();
        System.out.println("around after advice ...");
        return ret;  //原方法有返回值需返回
    }
}
  •                  返回后通知(了解)@AfterReturning----当方法正常结束时才会触发
  •                  抛出异常后通知(了解)@AfterThrowing

        12.6 AOP获取数据

  •                 获取切入点方法的参数
  •                         JointPoint:适用于前置,后置,返回后,抛出异常后
  •                         ProceedJointPoint:适用于环绕通知
  •                 获取切入点方法的返回值
  •                         返回后通知
  •                         环绕通知
  •                 获取切入点方法运行异常信息
  •                         抛出异常后通知
  •                         环绕通知
    //获取参数
//    如果是环绕通知获取就用ProceedingJoinPoint类型
   
 //JoinPoint:用于描述切入点的对象,必须配置成通知方法中的第一个参数,可用于获取原始方法调用的参数
    @Before("pt()")
    public void before(JoinPoint jp) {
        Object[] args = jp.getArgs();    //获取原方法的参数
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ..." );
    }

    //获取返回值
//环绕可以直接获取返回值
    
    //设置返回后通知获取原始方法的返回值,要求returning属性值必须与方法形参名相同
    @AfterReturning(value = "pt()",returning = "ret")
    public void afterReturning(JoinPoint jp,String ret) { //第一个参数必须时JoinPoint
        System.out.println("afterReturning advice ..."+ret);
    }

//    获取异常  
//在环绕通知里直接 try-catch就能获取到异常

//返回异常后执行 获取异常如下
//设置抛出异常后通知获取原始方法运行时抛出的异常对象,要求throwing属性值必须与方法形参名相同
    @AfterThrowing(value = "pt()",throwing = "t")
    public void afterThrowing(Throwable t) {
        System.out.println("afterThrowing advice ..."+t);
    }

13. 事务管理

           13.1 事务简介

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

                 举例

        实现:在接口(方法)上配置注解 @Transactional(也可在实现类上写,不建议)

         在相应的配置类中写transactionManager方法

        注:事务的DataSource和mybatis的DataSource要是同一个,否则不能开启事务

         在总配置类中开启注解 @EnableTransactionManagement

           13.2 事务角色

原先的服务层中,加钱和减钱是两个独立的事务。转钱方法开启事务(事务管理员)后,总共是三个事务。不过加钱和减钱的两个事务(加入事务方)会自动被转钱方法(在它的控制范围内)管理,所以最后是一个事务

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

           13.3 事务属性

         error错误,运行时异常,事务会自动回滚。其余异常不会,所以需要设置@Transactional(rollbackFor = IOException.class)

        事务传播行为:事务协调员对事务管理员所携带事务的处理态度

        说简单点就是控制 “加入事务方”到底加不加入 “事务管理员”方        

         在相应的方法上开启@Transactional(propagation = Propagation.REQUIRES_NEW),表示不属于加入事务方,另外开启一个

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值