百木园-与人分享,
就是让自己快乐。

Spring5

 
 
# Spring概述

1、Spring是轻量级开源JavaEE框架

2、Spring可以解决企业应用开发的复杂性

3、组成核心IOC、Aop

  • IOC:控制反转,把创建对象过程交给Spring进行管理

  • Aop:面向切面,不修改源代码进行功能增强

4、Spring特点

  • 方便解耦,简化开发
  • Aop编程支持
  • 方便程序测试
  • 方便集成各种优秀框架
  • 方便进行事务管理
  • 降低java api的使用难度

*此文档版本为Spring5

IOC

什么是IOC

​ (1)控制反转,把对象的创建和对象之间调用的过程,交给Spring进行管理

​ (2) 使用IOC的目的:为了降低耦合

​ (3) 做入门案例就是IOC的实现

IOC底层原理

​ (1) xml解析、工厂模式、反射

image-20220223170558636

IOC过程 (进一步降低耦合度)

​ 第一步 xml配置文件,配置创建的对象

<bean id=\"dao\" class=\"com.atguigu.UserDao\"></bean>

​ 第二步 有service类和dao类 创建工厂类

class UserFactory{
	public static UserDao getDao(){
		String classValue = class属性值;//1 xml解析 
        Class class = Class.forName(classValue);//2 通过反射创建对象
        return (UserDao)class.newInstance();//返回对象
	}
}	

IOC接口

  1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂

  2. Spring提供IOC容器实现两种方式:(两个接口)

  • BeanFactory :IOC容器基本实现,是Spring内部的使用接口,不提供给开发人员使用
    • 加载配置文件时不会创建对象,获取\\使用对象时才会创建对象
  • ApplicationContext :BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用
    • 加载配置文件时就会把配置文件中对象创建(服务器启动时创建)

ApplicationContext接口有实现类

image-20220223185151278

IOC操作 Bean管理

什么是Bean管理

包含以下两个操作

  1. Spring创建对象
  2. Spring注入属性

Bean管理操作

1 bean创建对象

1 基于xml配置文件方式

<!--配置User对象创建-->
<bean id=\"user\" class=\"com.atguigu.spring5.User\"></bean>   

(1)在Spring配置文件中,使用bean标签,标签里添加对应属性,就可以实现对象创建
(2)在bean标签中有很多属性:

  • id属性:唯一标识(不能加特殊符号)

  • class属性:类全路径(包类路径)

  • name:类似id(可添加特殊符号)

(3)创建对象的时候,默认也是执行无参构造方法

2 基于注解方式

2 基于xml注入属性

(1) DI:依赖注入,就是注入属性(DI是IOC的一种具体实现,在创建对象的基础之上进行)

第一种注入方式:使用set方法进行注入

第一步:创建类、创建属性、创建对应的set方法

public class Book {
    //创建属性
    private String bname;
    private String bauthor;
    //创建属性对应的set方法
    public void setBname(String bname) {
        this.bname = bname;
    }

    public void getBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
}

第二步:在Spring配置文件配置对象创建,配置属性注入

<!--2 set方法注入属性-->
<bean id=\"book\" class=\"com.atguigu.spring5.Book\">
    <!--使用property完成属性注入
        name:类里面属性名称
        value:向属性注入的值
    -->
    <property name=\"bname\" value=\"张三日记\"></property>
    <property name=\"bauthor\" value=\"法外狂徒张三\"></property>
</bean>
public class Book {
    //创建属性
    private String bname;
    private String bauthor;
    //创建属性对应的set方法
    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
}
第二种注入方法:使用有参构造进行注入

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

/**
 * 使用有参构造注入
 * */

public class Orders {
    private String oname;
    private String address;

    public Orders(String oname,String address){
        this.oname = oname;
        this.address = address;
    }
}

第二步:在Spring的配置文件中进行配置

<!--3 使用有参构造注入属性-->
<bean id=\"orders\" class=\"com.atguigu.spring5.Orders\">
    <!-- constructor-arg标签用于有参构造注入属性-->
    <constructor-arg name=\"oname\" value=\"电脑\"></constructor-arg>
    <constructor-arg name=\"address\" value=\"China\"></constructor-arg>
</bean>
第三种注入方式:P名称空间注入(底层使用的还是set方法注入)

使用p名称空间注入,可以简化基于xml配置方式

  • 添加p名称空间在配置文件中

image-20220224175509505

  • 进行属性注入,在bean标签里面进行操作

    <!--4 使用p名称空间注入-->
    <bean id=\"book\" class=\"com.atguigu.spring5.Book\" p:bname=\"张三的一生\" p:bauthor=\"罗翔\">
    </bean>
    
xml注入其他类型属性

字面量:固定值

  1. null值

    <!--null值-->
        <property name=\"address\">
            <null/>
        </property>
    </bean>
    
  2. 属性包含特殊符号

    <!--注入特殊符号
        1 拔尖括号进行转义 &lt;&gt;
        2 把特殊符号内容写到CDATA
    -->
    <property name=\"address\">
        <value><![CDATA[<<南京>>]]></value>
    </property>
    
注入属性-外部bean
  1. 创建两个类service类和dao类

  2. 在service调用dao里面的方法

  3. 在Spring配置文件中进行文件配置

    <!--1 service和Dao对象创建-->
    <bean id=\"userService\" class=\"com.atguigu.spring5.service.UserService\">
        <!--注入userDao对象
            name属性值:类里面的属性名称
            ref属性:创建userDao对象bean标签id值
        -->
        <property name=\"userDao\" ref=\"userDaoImpl\"></property>
    </bean>
    <bean id=\"userDaoImpl\" class=\"com.atguigu.spring5.dao.UserDaoImpl\"></bean>
    
    public class UserService {
    
         //创建UserDao类型属性,生成set方法
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public void add(){
            System.out.println(\"service add............\");
            userDao.update();
    
            //原始方式:创建UserDao对象
    //        UserDao userDao = new UserDaoImpl();
    //        userDao.update();
        }
    }
    
注入属性-内部bean
  1. 一对多关系,部门和员工

    一个部门有多个员工,一个员工属于一个部门。 部门是一 员工是多

  2. 在实体类之间表示一对多关系

    员工表示所属部门,使用对象类型进行表示

    //部门类
    public class Dept {
        private String dname;
        public void setDname(String dname) {
            this.dname = dname;
        }
    }
    

    //员工类
    public class Emp {
        private String ename;
        private String gender;
        //员工属于某一个部门,使用对象形式表示
        private Dept dept;
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        public void setEname(String ename) {
            this.ename = ename;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    }
    
  3. 在Spring配置文件中进行配置

    <!--内部bean-->
    <bean id=\"emp\" class=\"com.atguigu.spring5.bean.Emp\">
        <!--设置两个普通属性-->
        <property name=\"ename\" value=\"lucy\"></property>
        <property name=\"gender\" value=\"女\"></property>
    
        <!--设置对象类型属性-->
        <property name=\"dept\">
            <bean id=\"dept\" class=\"com.atguigu.spring5.bean.Dept\">
                <property name=\"dname\" value=\"安保部门\"></property>
            </bean>
        </property>
    </bean>
    
注入属性-级联赋值

第一种写法

<!--级联赋值-->
<bean id=\"emp\" class=\"com.atguigu.spring5.bean.Emp\">
    <!--设置两个普通属性-->
    <property name=\"ename\" value=\"lucy\"></property>
    <property name=\"gender\" value=\"女\"></property>

    <!--级联赋值-->
    <property  name=\"dept\" ref=\"dept\"></property>
</bean>
<bean id=\"dept\" class=\"com.atguigu.spring5.bean.Dept\">
    <property name=\"dname\" value=\"财务部\"></property>
</bean>

第二种写法 类中需要写get方法

//员工类
public class Emp {
    private String ename;
    private String gender;
    //员工属于某一个部门,使用对象形式表示
    private Dept dept;
    //生成dept的get方法

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void add(){
        System.out.println(ename+\"::\"+gender+\"::\"+dept);
    }
}
<!--级联赋值-->
<bean id=\"emp\" class=\"com.atguigu.spring5.bean.Emp\">
    <!--设置两个普通属性-->
    <property name=\"ename\" value=\"lucy\"></property>
    <property name=\"gender\" value=\"女\"></property>

    <!--级联赋值-->
    <property  name=\"dept\" ref=\"dept\"></property>
    <property name=\"dept.dname\" value=\"技术部\" ></property>
</bean>
<bean id=\"dept\" class=\"com.atguigu.spring5.bean.Dept\">
    <property name=\"dname\" value=\"财务部\"></property>
</bean>
xml注入集合属性
  1. 注入数组类型属性

  2. 注入List集合属性

  3. 注入Map集合类型属性

  4. 注入set集合类型属性

    创建类,定义数组、list、map、set类型属性,生成对应set方法

    public class Stu {
        //1 数组类型属性
        private String[] courses;
    
        //2 list集合类型属性
        private List<String> list;
    
        //3 map集合类型属性
        private Map<String,String> maps;
    
        //4 set集合类型属性
        private Set<String> set;
    
        public void setSet(Set<String> set) {
            this.set = set;
        }
    
        public void setCourses(String[] courses) {
            this.courses = courses;
        }
    
        public void setList(List<String> list) {
            this.list = list;
        }
    
        public void setMaps(Map<String, String> maps) {
            this.maps = maps;
        }
    }
    

    在Spring配置文件进行配置

    <!--1 集合类型属性注入-->
    <bean id=\"stu\" class=\"com.atguigu.spring5.collectiontype.Stu\">
        <!--数组类型属性注入-->
        <property name=\"courses\" >
            <array>
                <value>java课程</value>
                <value>sql课程</value>
            </array>
        </property>
        <!--list集合属性注入-->
        <property name=\"list\">
            <list>
                <value>张三</value>
                <value>小三</value>
            </list>
        </property>
        <!--map类型属性注入-->
        <property name=\"maps\">
            <map>
                <entry key=\"JAVA\" value=\"java\"></entry>
                <entry key=\"PHP\" value=\"php\"></entry>
            </map>
        </property>
        <!--set类型属性注入-->
        <property name=\"set\">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>
    </bean>
    
  5. 在集合里设置对象类型值

    <!--注入list集合类型,值是对象-->
    <property name=\"courseList\">
        <list>
            <ref bean=\"course1\"></ref>
            <ref bean=\"course2\"></ref>
        </list>
    </property>
    
    <!--创建多个course对象-->
    <bean id=\"course1\" class=\"com.atguigu.spring5.collectiontype.Course\">
        <property name=\"cname\" value=\"Spring5框架\"></property>
    </bean>
    <bean id=\"course2\" class=\"com.atguigu.spring5.collectiontype.Course\">
    <property name=\"cname\" value=\"Mybatis框架\"></property>
    
  6. 把集合注入部分提取出来

    1. 在Spring配置文件中引入空间名称util
    <beans xmlns=\"http://www.springframework.org/schema/beans\"
          	xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
           xmlns:util=\"http://www.springframework.org/schema/util\"
           xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd\">
    </beans>
    
    1. 使用util标签完成list集合注入提取

      <!--1 提取list集合类型属性注入-->
      <util:list id=\"bookList\" >
          <!--若引入对象使用ref标签-->
          <value>张三日记</value>
          <value>张三的悔改</value>
          <value>法外狂徒</value>
      </util:list>
      
      <!--2 提取list集合类型属性注入使用-->
      <bean id=\"book\" class=\"com.atguigu.spring5.collectiontype.Book\">
          <property name=\"list\" ref=\"bookList\"></property>
      </bean>
      

FactorBean

Spring里有两种bean,一种普通的bean。另外一种是FactoryBean(Spring内置的)

  1. 普通bean

    Spring配置文件中定义bean类型即为返回类型

  2. FactoryBean

    Spring配置文件中定义bean类型可与返回类型不同

  1. 创建类,让这个类作为工厂bean,实现接口FactoryBean

  2. 实现接口里面的方法,在实现的方法中定义返回的bean类型

    public class MyBean implements FactoryBean <Course>{
        //定义返回bean
        @Override
        public Course getObject() throws Exception {
            Course course = new Course();
            course.setCname(\"abc\");
            return course;
        }
    
        @Override
        public Class<?> getObjectType() {
            return null;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    
    //测试方法
    @Test
        public void testCollection3(){
            ApplicationContext context=new ClassPathXmlApplicationContext(\"bean3.xml\");
            Course course=context.getBean(\"myBean\",Course.class);
            System.out.println(course);
        }
    

    配置文件

    <bean id=\"myBean\" class=\"com.atguigu.spring5.factorybean.MyBean\">
    </bean>
    

bean的作用域

  1. 在Spring里,默认设置下,bean是单实例对象

    @Test
    public void testCollection2(){
        ApplicationContext context=new ClassPathXmlApplicationContext(\"bean2.xml\");
        Book book1=context.getBean(\"book\", Book.class);
        Book book2=context.getBean(\"book\", Book.class);
        //book.test();
        System.out.println(book1);
        System.out.println(book2);
    }
    

输出显示地址相同为单实例对象:

image-20220303171118846

  1. 如何设置单实例或多实例

    (1)在Spring配置文件bean标签里面有用于设置的属性(scope)

    (2)scope属性值

    • 默认值:singleton,表示单实例对象
    • prototype,表示多实例对象
    <!--2 提取list集合类型属性注入使用-->
    <bean id=\"book\" class=\"com.atguigu.spring5.collectiontype.Book\" scope=\"prototype\">
        <property name=\"list\" ref=\"bookList\"></property>
    </bean>
    

    两对象地址不同:

    image-20220303171843088

  2. singleton和prototype区别

    • singleton表示单实例,prototype多实例
    • 设置scope值是singleton时,加载Spring配置文件时就会创建单实例对象
    • 设置scope值是prototype时,不是在加载Spring配置文件时创建对象,在调用getBean方法时创建多例对象

Bean生命周期

从对象的创建到生命的销毁的过程

bean生命周期:

  1. 通过构造器创建bean实例(无参数构造)

  2. 为bean的属性设置值和对其他bean的引用(调用set方法)

    把bean实例传给bean后置处理器的方法postProcessBeforeInitialization(bean的后置处理器BeanPostProcessor,bean共有7步)

  3. 调用bean初始化的方法(需要进行配置)

    把bean实例传给bean后置处理器的另外一个方法postProcessAfterInitialization(bean的后置处理器BeanPostProcessor,bean共有7步)

  4. bean可以使用了(对象获取到了)

  5. 当容器关闭时,调用bean的销毁的方法(需要进行配置销毁的方法)

    <bean id=\"orders\" class=\"com.atguigu.spring5.bean.Orders\" init-method=\"initMethod\" destroy-method=\"destoryMethod\">
        <property name=\"oname\" value=\"手机\"> </property>
    </bean>
    
    public class Orders {
        //1 无参构造
        public Orders(){
            System.out.println(\"第一步 执行无参构造方法创建bean实例\");
        }
    
        private String oname;
        public void setOname(String oname) {
            this.oname = oname;
            System.out.println(\"第二步 调用set方法设置属性值\");
        }
    
        //3 创建执行的初始化方法
        public void initMethod(){
            System.out.println(\"第三步 执行初始化方法\");
        }
        //5 创建执行的销毁方法
        public void destoryMethod(){
            System.out.println(\"第五步 执行销毁方法\");
        }
    }
    
    //测试类
        @Test
        public void testBean3(){
    //        ApplicationContext context=new ClassPathXmlApplicationContext(\"bean4.xml\");
            ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(\"bean4.xml\");
            Orders orders=context.getBean(\"orders\",Orders.class);
            System.out.println(\"第四步 获取创建bean实例对象\");
            System.out.println(orders);
    
            //手动让bean实例销毁
            context.close();
        }
    

添加后置处理器之后:

  1. 创建类,实现接口BeanPostProcessor,创建后置处理器

    public class MyBeanPost 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 id=\"myBeanPost\" class=\"com.atguigu.spring5.bean.MyBeanPost\"></bean>
    

IOC操作Bean管理(xml自动装配)

什么是自动装配?

根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行注入

演示自动装配过程:

根据属性名称自动注入

<!--实现自动装配
        bean标签属性autowire,配置自动装配
        autowire属性常用的两个值:
            byName根据属性名称,注入值bean的id和类属性名称一样
            byType根据属性类型注入
    -->
    <bean id=\"emp\" class=\"com.atguigu.spring5.autowire.Emp\" autowire=\"byName\">
<!--        <property name=\"dept\" ref=\"dept\"></property>-->
    </bean>
    <bean id=\"dept\" class=\"com.atguigu.spring5.autowire.Dept\"></bean>
</beans>

根据属性类型自动注入

<!--实现自动装配
        bean标签属性autowire,配置自动装配
        autowire属性常用的两个值:
            byName根据属性名称,注入值bean的id和类属性名称一样
            byType根据属性类型注入
    -->
    <bean id=\"emp\" class=\"com.atguigu.spring5.autowire.Emp\" autowire=\"byType\">
<!--        <property name=\"dept\" ref=\"dept\"></property>-->
    </bean>
    <bean id=\"dept\" class=\"com.atguigu.spring5.autowire.Dept\"></bean>
</beans>

IOC操作Bean管理(外部属性文件)

  1. 直接配置数据库信息

    ​ 1.配置德鲁伊连接池(Druid连接池,阿里巴巴)

    ​ 2.引入德鲁伊连接池依赖jar包

    <!--直接配置连接池-->
    <bean id=\"database\" class=\"com.alibaba.druid.pool.DruidDataSource\">
        <property name=\"DriverClassName\" value=\"com.mysql.jdbc.Driver\"></property>
        <property name=\"url\" value=\"jdbc:mysql://locahost:3306/userDb\"></property>
        <property name=\"username\" value=\"root\"></property>
        <property name=\"password\" value=\"root\"></property>
    </bean>
    
  2. 引入外部属性文件配置数据库连接池

    (1)创建外部属性文件,properties格式文件,写数据库信息

    properties文件存储key:value格式配置

    prop.driverClass=com.mysql.jdbc.Driver
    prop.url=jdbc:mysql://localhost:3306/userDb
    prop.userName=root
    prop.password=root
    

    (2)把外部properties属性文件引入到Spring配置文件中

    • 引入context名称空间

      <beans xmlns=\"http://www.springframework.org/schema/beans\"
             xmlns:context=\"http://www.springframework.org/schema/context\"
             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
                                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">
      </beans>
      
    • 在Spring配置文件标签引入外部属性文件

      <!--引入外部属性文件-->
      <context:property-placeholder location=\"classpath:jdbc.properties\"/>
      <!--配置连接池-->
          <bean id=\"database\" class=\"com.alibaba.druid.pool.DruidDataSource\">
              <property name=\"DriverClassName\" value=\"${prop.driverClass}\"></property>
              <property name=\"url\" value=\"${prop.url}\"></property>
              <property name=\"username\" value=\"${prop.userName}\"></property>
              <property name=\"password\" value=\"${prop.password}\"></property>
          </bean>
      

IOC操作Bean管理(基于注解方式)

什么是注解?

  • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值。。。)

  • 使用注解,注解作用在类、方法、属性上面

  • 使用注解的目的:简化xml配置

Spring针对Bean管理中创建对象提供注解:

  • @Component

  • @Service

  • @Controller

  • @Repository

    *四个注解功能相同,都可以用来创建bean对象

基于注解方式实现对象的创建:

  1. 引入依赖

  2. 开启组件扫描

    <!--1 开启组件扫描
            1 扫描多个包时,使用逗号隔开
            2 扫描包上层目录可扫描包下多个包
    -->
    <context:component-scan base-package=\"com.atguigu\"></context:component-scan>
    
  3. 创建类,在类上面添加创建对象注解

    //在注解里面value属性值可以不写
    //默认值是类名称,首字母小写
    //UserService.class---userService
    @Service(value = \"userService\")//<bean id=\"userService\" class=\"..\">相同
    public class UserService {
        public void add(){
            System.out.println(\"service add....\");
        }
    }
    
  4. 开启组件扫描的细节配置

    <!--示例1
        use-default-filters=\"false\"表示不使用默认filter(扫描所有子目录),自己配置filter
        context:include-filter,设置扫描哪些内容
    -->
    <context:component-scan base-package=\"com.atguigu\" use-default-filters=\"false\">
        <context:include-filter type=\"annotation\" expression=\"org.springframework.stereotype.Service\"/>
    </context:component-scan>
    
    <!--示例2
        下面示例扫描包下所有内容
        context:exclude-filter ,设置哪些不扫描
    -->
    <context:component-scan base-package=\"com.atguigu\">
        <context:exclude-filter type=\"annotation\" expression=\"org.springframework.stereotype.Service\"/>
    </context:component-scan>
    
  5. 基于注解方式实现属性注入

    • @AutoWired:根据属性类型进行自动装配

      ​ ①把service和dao对象创建,在service和dao类添加创建对象注解

      ​ ②在service注入dao对象,在service类添加dao类型属性,在属性前使用注解

      @Service(value = \"userService\")//<bean id=\"userService\" class=\"..\">相同
      public class UserService {
      
          //定义dao类型属性
          //不需要添加set方法(spring已经封装了这一步)
          //添加注入属性的注解
          @Autowired
          private UserDao userDao;
          public void add(){
              System.out.println(\"service add....\");
              userDao.add();
          }
      }
      
    • @Qualifier:根据属性名称进行注入

      此注解的使用需要与@Autowired一起使用

      @Repository(value = \"userDaoImpl1\")
      public class UserDaoImpl implements UserDao{
          @Override
          public void add() {
              System.out.println(\"dao add...\");
          }
      }
      
      @Service(value = \"userService\")//<bean id=\"userService\" class=\"..\">相同
      public class UserService {
      
          //定义dao类型属性
          //不需要添加set方法(spring已经封装了这一步)
          //添加注入属性的注解
          @Autowired  //根据类型进行注入
          @Qualifier(value = \"userDaoImpl1\")
          private UserDao userDao;
          public void add(){
              System.out.println(\"service add....\");
              userDao.add();
          }
      }
      
    • @Resource:(javax中的注解,jdk11之后移除)可以根据类型注入,可以根据名称注入

    //    @Resource//默认根据类型注入
        @Resource(name = \"userDaoImpl1\")
        private UserDao userDao;
    
    • @Value:注入普通类型属性

      @Value(value = \"abc\")
      private String name;
      
  6. 完全注解开发

    (1)创建配置类,替代xml配置文件

    @Configuration//作为配置类,替代xml配置文件
    @ComponentScan(basePackages = {\"com.atguigu\"})
    public class SpringConfig {
    }
    

    (2)编写测试类

    @Test
    public void testService2(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean(\"userService\",UserService.class);
        System.out.println(userService);
        userService.add();
    }
    

AOP

什么是AOP?

​ 面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。

通俗描述:可不修改源代码,在主干功能里添加新的功能

例子:在原登录基础上添加权限判断

image-20220308163433475

AOP底层原理

AOP底层使用动态代理

有两种情况的动态代理

  1. 有接口的情况 ,使用JDK动态代理

    创建接口实现类代理对象,增强类的方法

    image-20220308164729412

  2. 没有接口的情况 ,使用CGLIB动态代理

    创建子类的代理对象,增强类的方法

    image-20220308165207366

AOP底层原理(JDK动态代理)

使用JDK动态代理,使用Proxy类里面的方法创建代理对象

image-20220308170122797

调用newProxyInstans方法

image-20220308170308516方法有三个参数:

  • 类加载器
  • 增强方法所在的类,这个类实现的接口,支持多个接口
  • 实现这个接口InvocationHandler,创建代理对象,写增强方法

编写JDK动态代理代码:

  1. 创建接口,定义方法

    public interface UserDao {
        public int add(int a,int b);
        public String update(String id);
    }
    
  2. 创建接口实现类,实现方法(原功能)

    public class UserDaoImpl implements UserDao{
    
        @Override
        public int add(int a, int b) {
            return a+b;
        }
    
        @Override
        public String update(String id) {
            return id;
        }
    }
    
  3. 使用Proxy类创建接口代理对象(加新功能)

    public class JDKProxy {
        public static void main(String[] args){
    //        //创建接口实现类代理对象
            Class[] interfaces = {UserDao.class};
    //        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
    //            @Override
    //            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //                return null;
    //            }
    //        });
            UserDaoImpl userDao = new UserDaoImpl();
            UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            int result = dao.add(1,2);
            System.out.println(\"result:\"+result);
        }
    }
    
    //创建代理对象代码
    class UserDaoProxy implements InvocationHandler{
        //1 把创建的是谁的代理对象,把谁传递进来
        //有参数的构造
        private Object obj;
        public UserDaoProxy(Object obj){
            this.obj = obj;
        }
    
        //增强的逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            //方法之前
            System.out.println(\"方法之前执行。。。。\"+method.getName()+\":传递的参数。。。\"+ Arrays.toString(args));
    
            //被增强的方法执行
            Object  res = method.invoke(obj,args);
    
            //方法之后
            System.out.println(\"方法之后执行。。。。\"+obj);
    
            return res;
        }
    }
    

AOP(术语)

  1. 连接点:类里面可以被增强的方法

  2. 切入点:类里面实际被增强的方法

  3. 通知(增强):实际增强的逻辑部分(新加的部分)

    *假如add()方法被增强

    • 前置通知:add()之前执行的增强
    • 后置通知:add()之后执行的增强
    • 环绕通知:add()之前之后都执行的增强
    • 异常通知:add()异常时执行的增强
    • 最终通知:return之后执行的增强,后置通知之后,有异常时不执行
  4. 切面(动作)

    把通知应用到切入点的过程

AOP操作(准备)

1、Spring框架中一般基于AspectJ实现AOP操作

AspectJ:AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

2、基于AspectJ实现AOP操作有两种方式:

  1. 基于xml配置文件使用
  2. 基于注解方式实现(使用)

3、在项目工程里引入AOP相关依赖

image-20220309102111127

4、切入点表达式

  1. 切入点表达式的作用:知道对哪个类里面哪个方法进行增强

  2. 语法结构:

    execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))

    例1:对com.atguigu.dao.BookDao类里面的add方法进行增强

    execution(public void com.atguigu.dao.BookDao.add(int a,int b))

    权限修饰符可省略,默认public

    返回类型可以用*号表示全类型

    execution(* com.atguigu.dao.BookDao.add(int a,int b))

    例2:对com.atguigu.dao.BookDao类里面的所有方法进行增强

    execution(* com.atguigu.dao.BookDao.*(..))

    例3:对com.atguigu.dao包里的所有类,类里的所有方法进行增强

    execution(* com.atguigu.dao..(..))

AOP(AspectJ注解)

演示:

  1. 创建类,在类里定义方法

    public class User {
        public void add(){
            System.out.println(\"add...\");
        }
    }
    
  2. 创建增强类

    1. 在增强类里面,创建方法,让不同方法代表不同通知类型

      //增强的类
      public class UserProxy {
      
          //前置通知
          public void before(){
              System.out.println(\"before...\");
          }
      }
      
  3. 进行通知的配置

    1. 在Spring配置文件中,开启注解的扫描

      <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\"
             xmlns:aop=\"http://www.springframework.org/schema/aop\"
             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
                                 http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd\">
      
              <!--开启注解扫描-->
              <context:component-scan base-package=\"com.atguigu.spring5.aopanno\"></context:component-scan>
      </beans>
      
    2. 使用注解创建User和UserProxy对象

    3. 在增强类上面添加注解@Aspect

      //增强的类
      @Component
      @Aspect //生产代理对象
      public class UserProxy {
      
          //前置通知
          public void before(){
              System.out.println(\"before...\");
          }
      }
      
    4. 在Spring配置文件中开启生成代理对象

      <!--开启Aspect生成代理对象-->
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
    5. 配置不同类型通知

      • 在增强类的里面,在通知方法上面添加通知类型的注解,使用切入点表达式配置

      • @Before

      • @After

      • @AfterReturning

      • @AfterThrowing

      • @Around

      //增强的类
      @Component
      @Aspect //生产代理对象
      public class UserProxy {
      
          //前置通知
          //@Before注解表示前置通知
          @Before(value = \"execution(* com.atguigu.spring5.aopanno.User.add(..))\")
          public void before(){
              System.out.println(\"before...\");
          }
      
          @After(value = \"execution(* com.atguigu.spring5.aopanno.User.add(..))\")
          public void after(){
              System.out.println(\"after...\");
          }
      
          @AfterReturning(value = \"execution(* com.atguigu.spring5.aopanno.User.add(..))\")
          public void afterReturning(){
              System.out.println(\"afterReturning...\");
          }
      
          @AfterThrowing(value = \"execution(* com.atguigu.spring5.aopanno.User.add(..))\")
          public void afterThrowing(){
              System.out.println(\"afterThrowing...异常\");
          }
      
          @Around(value = \"execution(* com.atguigu.spring5.aopanno.User.add(..))\")
          public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
              System.out.println(\"around...之前\");
      
              //被增强方法
              proceedingJoinPoint.proceed();
      
              System.out.println(\"around...之前后\");
          }
      }
      
    6. 公共切入点

      //相同切入点抽取
      @Pointcut(value = \"execution(* com.atguigu.spring5.aopanno.User.add(..))\")   //切入点注解
      public void pointdemo(){
      }
      
      //前置通知
      //@Before注解表示前置通知
      @Before(value = \"pointdemo()\")
      public void before(){
          System.out.println(\"before...\");
      }
      
    7. 多个增强类对同一个切入点增强时,可设置优先级

      在增强类上面加一个注释@Order(数字类型值),数字类型值越小它的优先级越高(值从0开始)

    8. 完全使用注解开发

      创建配置类(config),不需要创建xml配置文件

      @Configuration
      @ComponentScan(basePackages = \"com.atguigu\")    //开注解扫描
      @EnableAspectJAutoProxy(proxyTargetClass = true)    //开启Aspect生成代理对象
      public class ConfigAop {
      }
      

AOP(AspectJxml配置文件)

  1. 创建两个类:增强类和被增强类,创建方法

  2. 在Spring配置文件中创建两个类的对象

  3. 在Spring配置文件中配置切入点

    <!-- 创建两个类的对象-->
    <bean id=\"book\" class=\"com.atguigu.spring5.aopxml.Book\"></bean>
    <bean id=\"bookProxy\" class=\"com.atguigu.spring5.aopxml.BookProxy\"></bean>
    
    <!-- 配置切入点-->
    <aop:config>
        <!-- 切入点-->
        <aop:pointcut id=\"buy\" expression=\"execution(* com.atguigu.spring5.aopxml.Book.buy()) \"/>
    
        <!-- 配置切面(把增强应用到切入点的过程)-->
        <aop:aspect ref=\"bookProxy\">
            <!-- 增强作用在具体方法上-->
            <aop:before method=\"before\" pointcut-ref=\"buy\"></aop:before>
        </aop:aspect>
    </aop:config>
    

JdbcTemplate

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

JdbcTemplate使用准备工作

  1. 引入相关jar包

    image-20220310175133948

  2. 在Spring配置文件中配置数据库连接池

    <!--数据库连接池-->
    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">
        <property name=\"name\" value=\"jdbc:mysql:///user_db\"/>
        <property name=\"username\" value=\"root\"/>
        <property name=\"password\" value=\"root\"/>
        <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\"/>
    </bean>
    
  3. 配置JdbcTemplate对象,注入Datasource

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

    1. <!--1 开启组件扫描-->
      <context:component-scan base-package=\"com.atguigu\"></context:component-scan>
      
    2. @Service
      public class BookService {
          //注入Dao
          @Autowired
          private BookDao bookDao;
      }
      
    3. @Repository
      public class BookDaoImpl implements BookDao{
      
          //注入JdbcTemplate
          @Autowired
          private JdbcTemplate jdbcTemplate;
      }
      

JdbcTemplate操作数据库(添加)

  1. 对应数据库创建

  2. 编写service和dao

    1. 在dao进行数据库添加操作

      jdbcTemplate.update();
      
    2. 调用JdbcTemplate中的update()实现添加操作

      有两个参数:

      1. sql语句
      2. 可变参数设置sql语句中的值
      
      @Repository
      public class BookDaoImpl implements BookDao{
      
          //注入JdbcTemplate
          @Autowired
          private JdbcTemplate jdbcTemplate;
      
      
          //添加方法
          @Override
          public void add(Book book) {
              //1 创建sql语句
              String sql=\"insert into t_book value(?,?,?)\";
              //2 调用方法实现
              Object[] args = {book.getUser_id(),book.getUsername(),book.getUstatus()};
              int update = jdbcTemplate.update(sql,args);
              System.out.println(update);
          }
      }
      
    3. 测试类

      public class TestBook {
          @Test
          public void testJdbcTemplate(){
              ApplicationContext context=
                      new ClassPathXmlApplicationContext(\"bean1.xml\");
              BookService bookServcie = context.getBean(\"bookService\", BookService.class);
              Book book = new Book();
              book.setUser_id(1);
              book.setUsername(\"张三\");
              book.setUstatus(\"a\");
              bookServcie.addBook(book);
          }
      }
      

JdbcTemplate操作数据库(修改和删除)

  1. 方法的实现
//修改的方法
    @Override
    public void updateBook(Book book) {
        //1 创建sql语句
        String sql=\"update t_book set username=?,ustatus=? where user_id=?\";
        //2 调用方法实现
        Object[] args = {book.getUsername(),book.getUstatus(),book.getUser_id()};
        int update = jdbcTemplate.update(sql,args);
        System.out.println(update);
    }

    //删除的方法
    @Override
    public void deleteBook(String id) {
        //1 创建sql语句
        String sql=\"delete from t_book where user_id=?\";
        //2 调用方法实现
        int update = jdbcTemplate.update(sql,id);
        System.out.println(update);
    }
  1. 测试

    public class TestBook {
        @Test
        public void testJdbcTemplate(){
            ApplicationContext context=
                    new ClassPathXmlApplicationContext(\"bean1.xml\");
            BookService bookServcie = context.getBean(\"bookService\", BookService.class);
    //        //添加
    //        Book book = new Book();
    //        book.setUser_id(1);
    //        book.setUsername(\"张三\");
    //        book.setUstatus(\"a\");
    //        bookServcie.addBook(book);
            //修改
            Book book = new Book();
            book.setUser_id(1);
            book.setUsername(\"javaupup\");
            book.setUstatus(\"atguigu\");
            bookServcie.updateBook(book);
    //        //删除
    //        bookServcie.deleteBook(\"1\");
        }
    

JdbcTemplate操作数据库(查询)

查询返回某个值

  1. 场景:查询表里有多少条记录,返回是某个值

  2. 使用JdbcTemplate实现查询返回某个值

    jdbcTemplate.queryForObject(sql,Integer.class);
    

    有两个参数:

    1. sql语句
    2. 返回类型Class
    //查询表中的记录数
    @Override
    public int selectCount() {
        String sql=\"SELECT COUNT(*) FROM t_book\";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        return count;
    }
    

查询返回对象

  1. 场景:查询图书详情

  2. JdbcTemplate实现查询返回对象

    jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Book.class), id);

    三个参数:

    1. sql语句

    2. RowMapper,是接口,返回不同类型的数据,使用这个接口里面的实现类完成数据封装

    3. 传递sql语句中?(占位符)的值

      @Override
      public Book findBookInfo(int id) {
          String sql=\"SELECT * FROM t_book where user_id=?\";
          //调用方法
          Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
      
          return book;
      }
      

查询返回集合

  1. 场景:查询图书列表分页

  2. 调用JdbcTemplate实现查询返回集合

    jdbcTemplate.query(sql, new BeanPropertyRowMapper(Book.class));

    三个参数:

    1. sql语句

    2. RowMapper,是接口,返回不同类型的数据,使用这个接口里面的实现类完成数据封装

    3. 传递sql语句中?(占位符)的值

      *第三个参数也可不写

      @Override
      public List<Book> findAllBook() {
          String sql = \"select * from t_book\";
          List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
          return bookList;
      }
      

JdbcTemplate操作数据库(批量)

  1. 批量添加

    image-20220311202913560

    两个参数:

    1. sql语句

    2. List集合,添加多条记录数据

      //批量添加
      @Override
      public void batchAddBook(List<Object[]> batchArgs) {
          String sql = \"insert into t_book value(?,?,?)\";
          int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
          System.out.println(Arrays.toString(ints));
      }
      
  2. 批量修改

    @Override
    public void batchUpdateBook(List<Object[]> batchArgs) {
        String sql = \"update t_book set username=?,ustatus=? where user_id=?\";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
    

    测试

    //批量修改
    List<Object[]> batchArgs = new ArrayList<>();
    Object[] objects1 = {\"cc00\",\"ccc00\",\"3\"};
    Object[] objects2 = {\"dd00\",\"ddd00\",\"4\"};
    Object[] objects3 = {\"ee00\",\"eee00\",\"5\"};
    batchArgs.add(objects1);
    batchArgs.add(objects2);
    batchArgs.add(objects3);
    bookServcie.batchUpdate(batchArgs);
    
  3. 批量删除

    @Override
    public void batchDeleteBook(List<Object[]> batchArgs) {
        String sql=\"delete from t_book where user_id=?\";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
    

    测试

    List<Object[]> batchArgs = new ArrayList<>();
    Object[] objects1 = {\"3\"};
    Object[] objects2 = {\"4\"};
    Object[] objects3 = {\"5\"};
    batchArgs.add(objects1);
    batchArgs.add(objects2);
    batchArgs.add(objects3);
    bookServcie.batchDelete(batchArgs);
    

事务操作

1、事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败则全失败

典型场景:银行转账:

  • lucy转账100元给mary
  • lucy少100,mary多100

2、事务的四个特性(ACID):

(1)原子性(atomicity):成功都成功,失败都失败

(2)一致性(consistency):操作之前和操作之后总量不变

(3)隔离性(isolation):多事务操作时,之间不会产生影响

(4)持久性(durability):提交之后表中数据就会发生变化

事务操作(搭建事务操作环境)

典型场景:银行转账:

转账环境:image-20220311214628302

  1. 创建数据库,添加记录

image-20220311215159992

  1. 创建service,搭建dao,完成对象创建和注入关系

    1. service注入dao,在dao注入JdbcTemplate,在JdbcTemplate注入DateSource

    2. @Service
      public class UserService {
          //注入Dao
          @Autowired
          private UserDao userDao;
      
      }
      
    3. @Repository
      public class UserDaoImpl implements UserDao{
          @Autowired
          private JdbcTemplate jdbcTemplate;
      }
      
    4. <!--1 开启组件扫描-->
      <context:component-scan base-package=\"com.atguigu\"></context:component-scan>
      
      <!--数据库连接池-->
      <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">
          <property name=\"url\" value=\"jdbc:mysql:///user_db\"/>
          <property name=\"username\" value=\"root\"/>
          <property name=\"password\" value=\"root\"/>
          <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\"/>
      </bean>
      
      <!--JdbcTemplate对象-->
      <bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">
          <!--注入DataSource-->
          <property name=\"dataSource\" ref=\"dataSource\"></property>
      </bean>
      
  2. 在dao创建两个方:多钱和少钱,在service创建转账方法

  3. 以上代码如果正常执行是没有问题的,但是如果以上代码出现异常,有问题,则应符合原子性和一致性,账户数据都不变

事务管理(Spring事务管理介绍)

  1. 事务一般添加到JavaEE三层结构里的service层(业务逻辑层)
  2. 在Spring进行事务管理操作有两种方式
    1. 编程式事务管理
    2. 声明式事务管理(常用)
  3. 声明式事务管理
    1. 基于注解方式实现(常用)
    2. 基于xml配置文件方式
  4. 在Spring进行声明式事务管理,底层使用AOP原理
  5. Spring事务管理API
    1. 提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

image-20220312110914933

事务操作(注解声明式事务管理)

  1. 在Spring配置文件配置事务管理器

    <!-- 创建事务管理器-->
    <bean id=\"dataSourceTransactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">
        <!-- 注入数据源-->
        <property name=\"dataSource\" ref=\"dataSource\"></property>
    </bean>
    
  2. 在Spring配置文件中开启事务注解

    1. 在Spring配置文件中引入名称空间tx

      xmlns:tx=\"http://www.springframework.org/schema/tx\"
      
    2. 开启事务注解

      <!-- 开启事务注解-->
      <tx:annotation-driven transaction-manager=\"dataSourceTransactionManager\"></tx:annotation-driven>
      
  3. 在service类上面添加事务注解

    @Transactional
    
    1. 如果添加到类上面,则类中所有方法都添加事务
    2. 如果添加到方法上面,则只给此方法添加事务

事务操作(声明式事务管理参数配置)

  1. 在service类上面添加@Transactional,在这个注解里可以配置事务相关的参数

    image-20220312113822417

    1. propagation:事务传播行为

      *多事务方法直接进行调用,这个过程中事务是如何进行管理的

      image-20220312114612365image-20220312114741323

    2. isolation:事务隔离级别

      默认值:@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)

      *事务有特性称为隔离性,多事务操作之间不会产生影响,不考虑隔离性会产生很多问题

      *有三个读的问题:脏读、不可重复读、虚(幻)读

      • 脏读:一个提交事务读取到了另一个未提交事务的数据
      • 不可重复度:一个未提交事务读取到另一提交事务修改数据
      • 虚读:一个未提交事务读取到另一提交事务添加****数据

      解决:通过设置事务隔离级别就能解决读问题

      image-20220312145603002

    3. timeout:超时时间

      • 事务需要在一定时间内提交,如果不提交就会进行回滚
      • 默认值:-1(不超时)
      • 设置以秒为单位
    4. readOlay:是否只读

      • 读:查询操作;写:添加修改删除操作
      • 默认值:false(表示可以读也可以写)
      • 设置成true时只能读不能写
    5. rollbackFor:回滚

      • 设置出现哪些异常进行事务回滚
    6. noRollbackFor:不回滚

      • 设置出现哪些异常不进行事务回滚

事务操作(xml声明式事务管理)

  1. 在Spring管理文件中进行配置

    1. 配置事务管理器

    2. 配置通知

    3. 配置切入点和切面

      <!--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=\"accountMoney\" propagation=\"REQUIRES_NEW\" isolation=\"REPEATABLE_READ\" read-only=\"false\"/>
      <!--            <tx:method name=\"account*\"/>-->
              </tx:attributes>
          </tx:advice>
          <!--3 配置切入点和切面-->
          <aop:config>
      <!--        切入点-->
              <aop:pointcut id=\"pt\" expression=\"execution(* com.atguigu.spring5.service.UserService.*(..))\"/>
      <!--        切面-->
              <aop:advisor advice-ref=\"txadvice\" pointcut-ref=\"pt\"/>
          </aop:config>
      

事务操作(完全注解声明式注解管理)

创建配置类,使用配置类代替xml配置文件

@Configuration  //配置类
@ComponentScan(basePackages = \"com.atguigu\")    //组件扫描
@EnableTransactionManagement    //开启事务
public class TxConfig {
    //1. 创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");
        druidDataSource.setUrl(\"jdbc:mysql:///user_db\");
        druidDataSource.setUsername(\"root\");
        druidDataSource.setPassword(\"root\");
        return druidDataSource;
    }
    //2. 创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        //到IOC容器中根据类型找到DateSource
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //注入DateSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //3. 创建事务管理器对象
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

Spring5框架新功能

整个Spring5框架基于java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除

Spiring5框架自带了通用的日志框架

  • Spring5已经移除了Log4jConfigListener,官方建议使用Log4j2
  • Spring5框架整合Log4j2

Log4j2使用:

1. 引入jar包

image-20220312160311370

  1. 创建Log4j2.xml配置文件

    <?xml version=\"1.0\" encoding=\"UTF-8\"?>
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
    <?import org.apache.logging.log4j.core.layout.PatternLayout?>
    <configuration status=\"INFO\">
        <!--先定义所有的appender-->
        <appenders>
            <!--输出日志信息到控制台-->
            <console name=\"Console\" target=\"SYSTEM_OUT\">
                <!--控制日志输出的格式-->
                <PatternLayout pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n\"/>
            </console>
        </appenders>
        <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
        <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
        <loggers>
            <root level=\"info\">
                <appender-ref ref=\"Console\"/>
            </root>
        </loggers>
    </configuration>
    

Spring5框架核心容器支持@Nullable注解

@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空

Spring5核心容器支持函数风格GenericApplicationContext(lambda表达式)

public void testGenericApplicationContext(){
        //创建GenericApplicationContext对象
        GenericApplicationContext context = new GenericApplicationContext();
        //调用context方法注册对象
        context.refresh();
        context.registerBean(\"user1\",User.class,()-> new User());
        //获取Spring注册的对象
//        User user = (User) context.getBean(\"com.atguigu.spring5.test.User\");
        User user = (User) context.getBean(\"user1\");
        System.out.println(user);
    }

Spring5支持整合JUnit5

  1. 整合JUnit4

    1. 引入Spring测试相关的依赖

      image-20220312171459491

    2. @RunWith(SpringJUnit4ClassRunner.class) //指定单元测试框架的版本
      @ContextConfiguration(\"classpath:bean1.xml\")    //加载配置文件
      public class JTest4 {
          @Autowired
          private UserService userService;
      
          @Test
          public void test1(){
              userService.accountMoney();
          }
      }
      
  2. 整合JUnit5

    1. 引入JUnit5的jar包

    image-20220312180019155

    1. 创建测试类,使用注解完成

      package com.atguigu.spring5.test;
      
      import com.atguigu.spring5.service.UserService;
      
      import org.junit.jupiter.api.Test;
      import org.junit.jupiter.api.extension.ExtendWith;
      import org.junit.runner.RunWith;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit.jupiter.SpringExtension;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      @ExtendWith(SpringExtension.class)
      @ContextConfiguration(\"classpath:bean1.xml\")    //加载配置文件
      public class JTest5 {
          @Autowired
          private UserService userService;
      
          @Test
          public void test1(){
              userService.accountMoney();
          }
      }
      

复合注解@SpringJUnitConfig(locations = \"classpath:bean1.xml\")

//@ExtendWith(SpringExtension.class)
//@ContextConfiguration(\"classpath:bean1.xml\")    //加载配置文件
@SpringJUnitConfig(locations = \"classpath:bean1.xml\")
public class JTest5 {
    @Autowired
    private UserService userService;

    @Test
    public void test1(){
        userService.accountMoney();
    }
}

SpringWebFlux

image-20220312181857297

webflux介绍

  1. 基本概念

    • Spring5添加的新的模块,用于web开发的,功能与SpringMVC相似,webflux使用一种响应式编程出现的框架

    • 使用传统的web框架,比如SpringMVC,这些基于Servlet容器,webflux是一种异步非阻塞的框架,异步非阻塞的框架在servlet3.1之后才支持,核心是基于Reactor的相关API实现的

  2. 响应式编程

  3. webflux执行流程和核心API

  4. Springwebflux(基于注解编程模型)

  5. Springwebflux(基于函数式编程模型)


来源:https://www.cnblogs.com/hanyk/p/16202135.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » Spring5

相关推荐

  • 暂无文章