Spring5 简述

IOC 容器

IOC 底层原理

IOC : 控制反转,对象创建和对象之间的调用过程,交给Spring进行管理,达到降低耦合度的目的。

底层原理xml 解析+工厂模式+反射(本质就是对象工厂)

IOC 过程 :

  1. 配置 xml 文件,配置创建的对象

    <bean id = "自定义名称" class = "类路径"></bean>
    
  2. 有 A 类和 B 类,现需要在 B 中调用 A 中的方法,需创建工厂类

    class XxxFactory{
    	public static A getA(){
    		String classValue = 获取-class属性值; //xml解析(获取类路径)
    		Class clazz = Class.forName(className);//通过反射创建对象
    		return (A)clazz.newInstance();
    	}
    }
    
IOC-BeanFactory 接口

​ **Spring 提供的 IOC 容器两种实现方式 : **

  1. BeanFactory : IOC 容器的基本实现方式,是 Spring 内部使用接口,不提供给开发人员使用。加载配置文件时不会创建对象,在获取或使用对象时才去创建

  2. ApplicationContext : BeanFactory 的子接口,提供更多的功能,面向开发人员使用,加载配置文件时会对配置文件中的对象进行创建

    ApplicationContext 的两个主要实现类

    1.ClassPathXmlApplicationContext
    
    2.FileSystemXmlApplicationContext
    
IOC Bean 的管理

Bean 管理的两个操作 : (1) Spring 创建对象 (2) Spring 注入属性

xml 方式
创建对象
  • Spring 配置文件中,使用 bean 标签,然后添加对应属性,就可实现对象的创建
  • bean 标签-常用属性
属性
id唯一标识
class包类路径
  • 创建对象时,默认执行无参构造方法完成对象的创建
注入属性

DI : 依赖注入,(就是注入属性)

  1. 使用 set 方法进行注入

    创建类,定义属性,创建对应的 set 方法

    //name:属性名,value:注入的值
    <bean id="user" class="com.lte.User">
        <property name="username" value="admin"></property>
        <property name="password" value="123"></property>
    </bean>
    
  2. 使用有参构造器进行注入

    创建类,定义属性,创建对应有参构造方法

    <bean id="user" class="com.lte.User">
        <constructor-arg name="username" value="liu"></constructor-arg>
        <constructor-arg name="password" value="666"></constructor-arg>
    
        //或者
        <!-- <constructor-arg index="0" value="liu"></constructor-arg>-->
    </bean>
    
  3. p 名称空间注入(略过…,,只是 set 方式的简化写法)

  4. xml 注入其它类型属性

    字面量

    null

    <property name="username">
        <null/>
    </property>
    

    属性值包含特殊符号

    1.<!--对特殊符号进行转义(&lt,&gt 等)-->
    
    2.<!--把特殊符号内容写在 CDATA 中-->
    <property name="username">
        <value><![CDATA[<<特殊符号>>……^!]]></value>
    </property>
    

    注入属性-外部 Bean

    (1) 两个类 service 类和 dao 类 (2)在 service 调用 dao 里面的方法 (3) spring配置文件中进行配置

    <!--配置文件 -->
    <!-- service 和 dao 对象的创建-->
    <bean id="userService" class="com.lte.Service.impl.UserServiceImpl">
        <!-- 
    		注入 UserDAOImpl 对象 
    		ref 属性 : 创建的 UserDAOImpl 对象的 bean 标签的 id 值
    		(注意 : UserServiceImpl 类中 要有对应的 set 方法)
    			public void setUserDAO(UserDAOImpl userDAO) {
            		this.userDAO = userDAO;
        		}
    	-->
    	<property name="userDAO" ref = "userDAOImpl"></property>
    </bean>
    <bean id="userDAOImpl" class="com.lte.DAO.Impl.UserDAOImpl"></bean>
    

    -注入属性-内部 Bean 和级联赋值

    创建了 Employee 类 和 Employee 类,Employee 类的其中一个属性为 Department 类型

    <!-- 1. 可以使用外部Bean的方式-->
    
    <!-- 2. -->
    <bean id="emp" class="com.lte.domain.Employee">
        <property name="name" value="admin"></property>
        <property name="age" value="123"></property>
        <!-- 设置对象类型属性 -->
        <property name="dep">
            <bean id="dep" class="com.lte.domain.Department">
                <property name="dname" value="财务部"></property>
            </bean>
        </property>
    </bean>
    

    级联赋值

    <!-- 1. 外部Bean的方式可以看成级联赋值的一种-->
    
    <!-- 2.在外部Bean的基础上-->
    <bean id="emp" class="com.lte.domain.Employee">
        <property name="name" value="admin"></property>
        <property name="age" value="123"></property>
        <property name="dep" ref="dep"></property>
        <!-- (注意 : 需要定义 dep 属性的 get 方法才能使用此种方式)-->
        <property name="dep.dname" value="技术部"></property>
    </bean>
    <bean id="dep" class="com.lte.domain.Department">
        <property name="dname" value=""></property>
    </bean>
    

    数组 ,List ,Map ,Set 集合类型的注入

    <!-- 数组 -->
    <property name="courses">
        <array>
            <value></value>
            <value></value>
        </array>
    </property>
    <!-- List 集合-->
    <property name="lists">
        <list>
            <value></value>
            <value></value>
        </list>
    </property>
    <!-- map集合 -->
    <property name="maps">
        <map>
            <entry key="" value=""></entry>
            <entry key="" value=""></entry>
        </map>
    </property>
    <!-- set -->
    <property name="sets">
        <set>
            <value></value>
            <value></value>
        </set>
    </property>
    

    集合类型为对象

    <bean id="" class="">
        <property name="ObjectList">
            <list>
                <ref bean="object1"></ref>
                <ref bean="object2"></ref>
            </list>
        </property>
    </bean>
    <bean id="object1" class="xxx.xx">
        <property name="" value=""></property>
    </bean>
    <bean id="object2" class="yyy.yy">
        <property name="" value=""></property>
    </bean>
    

    提取公共的集合注入部分( list 为例)

    spring 配置文件中引入名称空间(在 beans 标签里设置)
    xmlns:util="http://www.springframework.org/schema/util"
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
    
    util标签完成集合的注入提取
    <util:list id="lists">
        <value>aaaa</value>
        <value>bbbb</value>
    </util:list>
    
    注入使用
    <property name="list" ref="lists"></property>
    
FactoryBean

Spring 的两种类型 bean : (1) 普通 bean ,(2)工厂bean(FactoryBean)

​ 普通 bean :在配置文件中定义的 bean 类型,返回值为相同类型

​ 工厂 bean :配置文件中定义的 bean 类型可以和返回类型不一样

	//自定义的类实现 FactoryBean 接口 ,重写里面的方法
	//配置文件,创建对象
	public class FactoryBeanImpl implements FactoryBean 
Bean 的作用域

​ 创建的 Bean 实例 : (1)单实例(默认) ,(2)多实例

<!-- 
singleton : 单实例,默认,加载配置文件时创建
prototype : 多实例,调用 getBean方法时创建
 -->

<!-- 设置为多实例 -->
<bean id="user" class="com.lte.User" scope="prototype"> 
</bean>
Bean 的生命周期
  1. 创建 bean 实例

  2. 注入属性(设置属性值)

  3. 调用 bean 的初始化方法

    init-method="初始化需要执行的方法名(不需要括号)"
    
  4. 使用 bean (获取对象)

  5. 销毁 bean (容器关闭时,调用 bean 的销毁方法)

    destroy-method="销毁 bean 之后需要执行的方法名(不需要括号)"
    

在 bean 的后置处理器的情况下,生命周期有七步

​ 在 3.调用 bean 的初始化方法 之前,bean 的实例传递给 bean 后置处理器的 postProcessBeforeInitialization 方法

​ 在 3.调用 bean 的初始化方法 之后,bean 的实例传递给 bean 后置处理器的 postProcessAfterInitialization 方法

//实现 BeanPostProcessor 接口,重写两个方法
public class MyBean implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化前需要执行的方式");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后需要执行的方法");
        return bean;
    }
}

//配置后置处理器
//会对所在配置文件中的所有 bean 添加后置的处理
<bean id="myBean" class="com.lte.MyBean"></bean>
自动装配

根据指定的装配规则,自动将匹配的属性值进行注入

<!-- 根据属性和名称自动注入 或者其它方式 -->
<!-- 根据属性名称自动注入 -->

<bean id="emp" class="com.lte.domain.Employee" autowire="byName">
    <property name="name" value="admin"></property>
    <property name="age" value="123"></property>
    <property name="list" ref="lists"></property>
</bean>
<!--  注入值的 bean id 值要和类属性名称一致 -->
<bean id="dep" class="com.lte.domain.Department">
    <property name="dname" value="财务部"></property>
</bean>
引入外部属性文件
//引入 druid 数据库连接池的配置文件为例

spring 配置文件中引入名称空间(在 beans 标签里设置)
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

//引入外部属性文件的标签
<context:property-placeholder location="classpath:配置文件全名.后缀"/>
<bean id="" class="com.alibaba.druid.pool.DruidDataSource"> 
	//${} : spring 中的表达式,填写内容为数据库配置文件中等号左边的属性名称
	   <property name="driverClass" value="${driverClass}"></property>
	   <property name="url" value="${url}"></property>
	   ......
</bean>
注解方式

​ spring 中针对 Bean 管理中创建对象提供的四种注解,都可以用来创建 bean 实例

  • @Component
  • @Service
  • @Controller
  • @Repository
创建对象
  1. 引入相关依赖 (aop-jar)

  2. 开启组件扫描

    引入名称空间
    xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    
    开启组件扫描 
    如果要扫描多个包,包之间用逗号隔开 或 直接扫描上层目录
    <context:component-scan base-package="com.lte.domain"/>
    

    关于组件扫描的两个常见示例

    示例一

    <!--  
    	use-default-filters="false" : 表示不使用默认的 filter,而是自己配置 filter
    	context:include-filter : 扫描的内容
     -->
    <context:component-scan base-package="com.lte.domain" use-default-filters="false">
       	 	<!-- 
    			只扫描含有 org.springframework.stereotype.Component 注解所在的类
    		-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>
    
    

    示例二

    <!-- 
    	排除指定的内容
    -->
    <context:component-scan base-package="com.lte.domain">
        	<!--  
    			org.springframework.stereotype.Component 注解所在的类不扫描
    		-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>
    
    
  3. 在创建的类上添加注解(注解的 value 如果没有赋值,默认为该类的名称并且首字母小写)

属性注入
  1. @Autowired : 根据属性类型

     //在属性上边使用注解
      @Autowired
      private UserService service;
    
  2. @Qualifier : 根据属性名称

     //需要配合  @Autowired 使用
      @Autowired
      //value : 对应类的注解的 value 值
      //并且不需要设置 set 方法
      @Qualifier(value = "userServiceImpl")
      private UserService service;
    
  3. @Resource : 根据属性类型 或 名称

      @Resource : 根据类型
      @Resource(name = "xx") : 根据名称
      (Resource 是 import javax.annotation.Resource 下的,不属于 spring)
    
  4. @Value : 注入普通类型(以上三种主要用于对象类型)

    @Value(value="admin")
    private String name;
    

完全注解开发 —>(springboot)

AOP 面向切面编程

面向切面编程降低业务逻辑的各个部分之间的耦合度

AOP 底层原理

AOP 底层使用动态代理,其中包含两种情况的动态代理 :

​ 1. 有接口情况 :使用 JDK 中的动态代理 (创建接口实现类的代理对象)

​ 2. 无接口情况 : 使用 CGLIB 动态代理 (创建子类的代理对象)

JDK 提供的动态代理

java.lang.reflect.Proxy 下提供的 newProxyInstance 方法 可以返回指定接口的代理类的实例

newProxyInstance 方法提供的三个参数 :

​ 1.类加载器

​ 2.被代理类所实现的接口,传入的参数为 Class 类型的数组

​ 3. 实现 InvocationHandler 接口,创建代理对象,添加增强的方法

演示

1.创建 UserService 接口,UserServiceImpl 为该接口实现类(被代理)

2.实现 InvocationHandler 接口

//代理类
class UserServiceProxy implements InvocationHandler{

    private Object obj; //被代理的对象
    public UserServiceProxy(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法增强
        System.out.println(method.getName() + "方法执行前...");
        Object invoke = method.invoke(obj, args);
        System.out.println(method.getName() + "方法执行后...");
        return invoke;
    }
}

3.调用 newProxyInstance 方法实现代理

//所在的类为 DynamicProxy
Class[] interfaces = {UserService.class};
UserServiceImpl userService = new UserServiceImpl();
UserService userService1 = (UserService) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), interfaces, new UserServiceProxy(userService));
AOP 常见操作术语
  1. 连接点

    ​ 类中的哪些方法可以被增强,这些方法称为连接点

  2. 切入点

    ​ 实际被增强的方法,称为切入点

  3. 通知(或增强)

    ​ 实际增加的逻辑部分称为通知 或者 增强

    类型 :前置 ,后置 ,环绕 , 异常 , 最终通知

  4. 切面

    把通知应用到切入点的过程,可以看成一个动作

AOP 操作

spring 框架一般基于 AspectJ 实现 AOP 操作,AspectJ 不是 spring 的组成部分,一般和spring 框架一起使用。

基于 AspectJ 实现 AOP 操作 :(1) xml 配置文件实现 (2) 注解实现

切入点表达式 :明确对某个类中的某个方法进行增强

语法结构execution( [权限修饰符 ( * :任意修饰符) ] [返回类型 (无返回类型可以省略) ] [类全路径 (* :包下的所有类) ] [方法名称(* :该类下的所有方法) ] [ 参数列表 (用两个点表示参数) ] )

AspectJ 注解
  1. 创建 User(被增强类) 类和 UserProxy 类(增强类)

  2. 使用注解创建 User 和 UserProxy 对象

    @Component
    public class User { ... }
    
    @Component
    public class UserProxy{ ... }
    
  3. 在增强类上面添加注解 @Aspect

    @Component
    @Aspect
    public class UserProxy{ ... }
    
  4. spring 配置文件中开启组件扫描 和 开启生成代理对象

    <!-- 引入名称空间 -->
    xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    <!-- 开启自动扫描-->
     <context:component-scan base-package="com.lte"></context:component-scan>
    
    <!-- 引入名称空间 -->
    xmlns:aop="http://www.springframework.org/schema/aop"
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
    <!-- 开启Aspectj生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
  5. 配置不同的通知

    @Component
    @Aspect
    public class UserProxy {
    
        // User 类中的 show() 方法作为切入点
        //前置通知(因为在方法前执行,所有无论有没有异常都会执行)
        @Before(value = "execution(* com.lte.aopanno.User.show(..))")
        public void before(){
            System.out.println("before...");
        }
        
        //最终通知(无论有没有异常都执行)
        @After(value = "execution(* com.lte.aopanno.User.show(..))")
        public void after(){
            System.out.println("after...");
        }
        
        //后置通知(不出现异常,并且在方法返回结果之后执行)
        @AfterReturning(value = "execution(* com.lte.aopanno.User.show(..))")
        public void afterReturning(){
            System.out.println("afterReturning...");
        }
        
        //异常通知(出现异常时执行)
        @AfterThrowing(value = "execution(* com.lte.aopanno.User.show(..))")
        public void afterThrowing(){
            System.out.println("afterThrowing...");
        }
        
        //环绕通知(出现异常时不执行)
        @Around(value = "execution(* com.lte.aopanno.User.show(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕之前...");
            //表示被增强的方法执行
            proceedingJoinPoint.proceed();
            System.out.println("环绕之后");
        }
    }
    

    抽取公共切入点

    //使用 @Pointcut 对相同切入点进行抽取
    @Pointcut(value = "execution(* com.lte.aopanno.User.show(..))")
    public void publicpiont(){}
    //将方法名赋给value
    @Before(value = "publicpiont()")
    public void before(){System.out.println("before...");}
    

    优先级 :

    多个不同的增强类,对同一个方法进行增强,设置增强类优先级

    //通过注解 @Order 设置优先级 ,值越小优先级越高
    @Order(3)
    public class UserProxy{ ... }
    

使用 JdbcTemplate 操作数据库

Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 实现对数据库的操作

操作示例
  1. 导入相关依赖 和 druid 连接池的配置文件

    #druid 部分配置文件
    jdbc.driverClassName=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/android?rewriteBatchedStatements = true&serverTimezone=UTC
    jdbc.username=root
    jdbc.password=123123
    
  2. 在 spring 配置文件中 对数据库连接池进行配置

    <!-- 引入相关的名称空间-->
    
    <!-- 配置数据库连接池 -->
    <!-- 读取druid配置文件-->
    <context:property-placeholder location="classpath:druid.properties"/>
    
    <!-- mysql8 以下-->
    <!-- <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">  -->
    <!-- mysql8 以上(如果使用8以下的方法,会出现 严重 的警告)-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!-- 开启组件扫描-->
    <context:component-scan base-package="com.lte"></context:component-scan>
    
  3. 配置 JdbcTemplate对象,注入DataSource

    <!-- 配置 jdbcTemplate 对象,注入 DataSource-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    
        <!-- 注入 dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  4. 创建 service 类和 dao 类,在 dao 类中注入 JdbcTemplate 对象

    //UserDAO 的实现类
    @Repository(value = "UserDAOImpl")
    public class UserDAOImpl implements UserDAO {
    
        //注入JDBCTemplate
        @Autowired
        private JdbcTemplate jdbcTemplate;
    }
    
    
    //UserService 的实现类
    @Service(value = "UserServiceImpl")
    public class UserServiceImpl implements UserService {
    
        //注入DAO
        @Qualifier(value = "UserDAOImpl")
        private UserDAO userDAO;
    }
    
    
  5. 操作数据库

    插入数据

    //传入的两个参数 sql语句 和 可变形参
    @Override
    public void add(User user) {
        String sql = "insert into users values(?,?,?)";
        Object[] obj = {user.getId(),user.getUsername(),user.getPassword()};
        int row = jdbcTemplate.update(sql, obj);
        System.out.println(row);
    }
    
    

    删除 和 修改操作也是通过调用 update 方法进行操作

    查询数据

    @Override
    public int findCount() {
        String sql = "select count(*) from users";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        return count;
    }
    
    @Override
    public User findOne(String id) {
        String sql = "select * from users where id =?";
        return jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),id);
    }
    
    @Override
    public List<User> findAll() {
        String sql = "select * from users";
        return jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class));
    }
    
获取连接时出现的异常

异常 :org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Access denied for user ‘86152’@‘localhost’ (using password: YES)

Caused by: java.sql.SQLException: Access denied for user ‘86152’@‘localhost’ (using password: YES)

原因 :properties 文件 username 被系统环境变量替代了,导致无法连接成功(不是 86152’@‘localhost 而应该是 root’@'localhost)

解决方法:

  1. 修改 username 为 user 或其他名称 (例如 :username 修改为 jdbc.username )

  2. spring导入properties 文件的标签中添加属性:system-properties-mode=“FALLBACK” 不加时属性值默认为 NVIRONMENT

    // 练习时用到的配置标签

    <context:property-placeholder location=“classpath:druid.properties” system-properties-mode=“FALLBACK”/>

批量操作
@Override
public int[] batchAddUser(List<Object[]> lists) {
    /*   String sql = "update users set username = ?,password = ? where id = ?";*/
    String sql = "insert into users values(?,?,?)";
    //batchUpdate : 可以进行批量 插入,修改,删除
    int[] ints = jdbcTemplate.batchUpdate(sql,lists);
    return ints;
}

事务

数据库操作的最基本单元,逻辑上的一组操作,有一个失败,整个操作都会失败

事务的四个特性(ACID) : (1)原子性 (2)一致性 (3)隔离性 (4)持久性

利用 spring 进行事务管理
编程式事务声明

​ (一般不用,略…)

声明式事务管理(注解方式)

spring 中进行声明式事务管理,底层使用 AOP 原理

使用事务-示例

  1. 引入 tx 名称空间

  2. 创建事务管理器

    <!-- 创建事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  3. 开启事务注解

    <!-- 开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
  4. 添加事务注解

    @Transactional
    添加到类上,类中的所有方法都会添加注解
    添加到方法上,只为当前方法添加事务
    

@Transactional 常用参数

属性名表示
propagation事务传播行为
isolation事务隔离级别
timeout超时时间
readOnly是否只读
rollbackFor回滚
noRollbackFor不回滚

事务传播行为( propagation ) :多事务方法直接进行调用,这个过程中事务是如何进行管理的

@Transactional(propagation = Propagation.REQUIRED)

事务方法 :增 删 改等对数据库表数据进行变化的操作

事务传播行为 :

事务隔离级别( isolation ) : **解决 脏读,不可重复读,幻读 这三个问题 **

	1. **脏读 :当一个事务读取另一个事务尚未提交的修改时,产生脏读**
	2. **不可重复读 :同一查询在同一事务中多次进行,由其它提交事务所做的修改或删除,每次返回不同的结果集,此时发生不可重复读**
	3. **幻读 : 同一查询在同一事务中多次进行,由于其他提交事务所作的**插入**操作,每次返回不同的结果集,此时发生幻读。**
//一共存在四种隔离级别
//Isolation.REPEATABLE_READ : 可重复读,不加锁 ,一般为 mysql 默认级别
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)

超时时间( timeout ) : 事务需要在一定时间内进行提交,超出时间还未提交则进行回滚

​ 默认值 :-1 (表示不超时) , 设置时间以 秒 为单位

timeout = -1 //不超时
timeout = 10 //超时时间10秒

是否只读 ( readOnly ):设置成 true 后,只能进行查询(读) ,不能进行增删改(写)

readOnly = true //默认 false

**回滚 ( rollbackFor ) : 设置出现哪些异常进行事务回滚 **

rollbackFor = NullPointerException.class

不回滚 ( noRollbackFor ) : 设置出现的哪些属性不进行回滚

noRollbackFor = NullPointerException.class
声明式事务管理(xml 方式)
  1. 配置事务管理器

    <!-- 创建事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  2. 配置通知

    <!-- 配置通知-->
    <tx:advice id = "txadvice">
        <tx:attributes>
            <!-- 指定在那种规则上面添加通知-->
            <tx:method name="transfer" propagation="REQUIRED"/>
            <!--
                方法名以 transfer 开头的添加事务
                <tx:method name="transfer*"/>
             -->
        </tx:attributes>
    </tx:advice>
    
  3. 配置切入点和切面

    <!-- 设置切入点和切面-->
    <aop:config>
        <!-- 设置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.lte.service.AccountService.*(..))"/>
        <!-- 设置切面(将事务 txadvice 的通知设置到切入点 pt 上)-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>
    
声明式事务管理(完全注解)

(省略------,尚硅谷 spring p-49)

其它一些特性

@Nullable 注解

可以使用在 类 \方法\属性\参数\上面,表示方法\属性值\参数值\返回可以为空

WebFlux

**Spring WebFlux :功能和 SpringMVC 类似,但使用的是响应式编程框架,相对于传统框架(例如 SpringMVC), WebFlux 是一种 异步非阻塞框架(该种框架在 Servlet 3.1 以后才支持的),核心是基于 Reactor 相关 API 实现的。 **

特点 :非阻塞式 ,在有限资源下,提高系统吞吐量和伸缩性,使用函数式编程实现路由请求。默认使用容器是 Netty,Netty 为高性能 NIO 异步非阻塞框架
请添加图片描述
*WebFlux 其它知识学习中~~~~*

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值