首页 > 其他分享 >spring完整笔记

spring完整笔记

时间:2023-07-16 09:56:32浏览次数:39  
标签:事务 对象 spring bean 笔记 完整 Spring 方法 public

第一章 初识Spring

1.1 Spring简介

  • Spring是一个为简化企业级开发而生的开源框架

  • Spring是一个IOC(DI)AOP容器框架。

    • IOC全称:Inversion Of Control【控制反转】
      • 将对象控制权由程序员自己反转交个Spring
    • DI全称:Dependency Injection【依赖注入】
      • Spring管理对象与对象之间依赖关系
    • AOP全称:Aspect-Oriented Programming【面向切面编程】
  • 官网:https://spring.io

  • Spring简图

    image-20230716093454034

1.2 搭建Spring框架

  • 导入jar包

    <!--导入spring-context-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.1</version>
    </dependency>
    <!--导入junit4.12-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    
  • 创建POJO

  • 编写核心配置文件

    • 配置文件名称:applicationContext.xml【beans.xml或spring.xml】

    • 配置文件位置:src/main/resources

    • 示例代码

      <bean id="empCui" class="com.atguigu.pojo.Employee">
          <property name="id" value="1001"></property>
          <property name="lastName" value="cuicui"></property>
          <property name="email" value="[email protected]"></property>
          <property name="salary" value="100.5"></property>
      </bean>
      
  • 使用核心类库【容器对象】

    • ApplicationContext

      @Test
      public void testSpringHw(){
          //创建Spring容器对象
          ApplicationContext ioc =
                  new ClassPathXmlApplicationContext("applicationContext.xml");
      
          //通过容器对象,获取需要对象
          Employee empCui = (Employee) ioc.getBean("empCui");
          System.out.println("empCui = " + empCui);
      
      }
      

1.3 Spring特性

  • 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API。
  • 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。
  • 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
  • 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的JDBCTemplate)。

1.4 Spring中getBean()三种方式

  • getBean(String beanId):通过beanId获取对象

    • 不足:返回值是Object,使用不灵活
  • getBean(Class clazz):通过Class获取对象

    • 不足: 当容器中存在多个同类型的bean时,会报如下错误:

      available: expected single matching bean but found 2: empCui,empTao

  • getBean(String beanId,Class clazz):通过beanId&Class获取对象

    • 推荐使用

1.5 bean标签详解

  • 属性

    • id:唯一标识【任意定义,不可重复】
    • class:装配对象全类名
  • 子标签property

    • name属性:设置对象中属性名称
    • value属性:设置对象中属性数值
  • 示例代码

    <bean id="empCui" class="com.atguigu.pojo.Employee">
        <property name="id" value="1001"></property>
        <property name="lastName" value="cuicui"></property>
        <property name="email" value="[email protected]"></property>
        <property name="salary" value="100.5"></property>
    </bean>
    

第二章 SpringIOC底层实现

2.1 BeanFactory与ApplicationContext

  • BeanFactory:IOC容器的基本实现,是Spring内部的使用接口,是面向Spring本身的,不是提供给开发人员使用的。
  • ApplicationContext: BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是底层的BeanFactory。

2.2 IOC底层实现简图

  • BeanFactory【底层实现】

    • ...

      • ApplicationContext【开发者实现】

        • ConfigurableApplicationContext

          是ApplicationContext的子接口,包含一些扩展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力。

          • ...
            • ClassPathXmlApplicationContext【基于类路径检索xml】
            • FileSystemXmlApplicationContext【基于系统路径检索xml】
            • AnnotationConfigApplicationContext【基于完全注解研发】

image-20230716093536875

第三章 Spring依赖注入数值问题

3.1 字面量数值

  • 数据类型:基本数据类型及其包装类型、String等类型
  • 语法结构:value属性或value标签可注入数值

3.2 CDATA区

  • 语法:<![CDATA[]]>

  • 作用:解决xml【支持各种xml】中特殊符号问题

  • 示例代码

    <bean id="empTao" class="com.atguigu.pojo.Employee">
        <property name="id" value="1001"></property>
        <property name="lastName">
            <value><![CDATA[<taotao>]]></value>
        </property>
        <property name="email" value="[email protected]"></property>
        <property name="salary">
            <value>100.5</value>
        </property>
    </bean>
    
    <select id="selectDeptAndEmpByDeptIdStep" resultMap="deptAndEmpRmStep">
        <![CDATA[
            select
                dept_id,
                dept_name
            from
                tbl_dept
            where
                dept_id < #{deptId}
         ]]>
    </select>
    

day06

3.3 外部已声明bean及级联属性赋值

  • 级联属性赋值时,更改级联属性数值,也会同时更改外部bean的属性值
    • 因为:引用类型赋值时,赋值的是引用
<!--    测试外部bean-->
<bean id="dept1" class="com.atguigu.pojo.Dept">
    <property name="deptId" value="101"></property>
    <property name="deptName" value="研发部门"></property>
</bean>

<bean id="empXin" class="com.atguigu.pojo.Employee">
    <property name="id" value="1002"></property>
    <property name="lastName" value="xinxin"></property>
    <property name="email" value="[email protected]"></property>
    <property name="salary" value="200.5"></property>
    <!-- 装配【注入】外部bean-->
    <property name="dept" ref="dept1"></property>
    <!-- 级联属性赋值-->
    <property name="dept.deptName" value="教学部门"></property>
</bean>

3.4 内部bean

  • 内部bean不会直接装配到ioc容器中,所以一般不会设置id属性值
<!--    测试内部bean-->
<bean id="empNan" class="com.atguigu.pojo.Employee">
    <property name="id" value="1003"></property>
    <property name="lastName" value="nannan"></property>
    <property name="email" value="[email protected]"></property>
    <property name="salary" value="200.5"></property>
    <property name="dept">
        <bean class="com.atguigu.pojo.Dept">
            <property name="deptId" value="102"></property>
            <property name="deptName" value="教务部门"></property>
        </bean>
    </property>
</bean>

3.5 装配List

  • 如需使用<util:list>标签,需要引入其名称空间及相关约束,快捷键如下:

    image-20230716093553996

<!--    测试List-->
    <bean id="dept2" class="com.atguigu.pojo.Dept">
        <property name="deptId" value="102"></property>
        <property name="deptName" value="教学部门"></property>
        <property name="empList">
            <list>
                <ref bean="empXin"></ref>
                <ref bean="empTao"></ref>
<!--                <bean class="com.atguigu.pojo.Employee"></bean>-->
            </list>
        </property>
    </bean>

    <!--  定义list集合-->
    <util:list id="empList">
        <ref bean="empTao"></ref>
        <ref bean="empXin"></ref>
    </util:list>
    <bean id="dept3" class="com.atguigu.pojo.Dept">
        <property name="deptId" value="103"></property>
        <property name="deptName" value="教学部门3"></property>
        <!-- 引入外部已声明List-->
        <property name="empList" ref="empList"></property>
    </bean>

3.6 装配Map

<!--    测试Map-->
<bean id="dept4" class="com.atguigu.pojo.Dept">
    <property name="deptId" value="104"></property>
    <property name="deptName" value="教学部门4"></property>
    <property name="empMap">
        <map>
            <entry>
                <key>
                    <value>1001</value>
                </key>
                <ref bean="empTao"/>
            </entry>
            <entry>
                <key>
                    <value>1002</value>
                </key>
                <ref bean="empXin"></ref>
            </entry>
        </map>
    </property>
</bean>
<util:map id="empMap">
    <entry>
        <key>
            <value>1001</value>
        </key>
        <ref bean="empTao"></ref>
    </entry>
    <entry>
        <key>
            <value>1002</value>
        </key>
        <ref bean="empXin"></ref>
    </entry>
</util:map>
<bean id="dept5" class="com.atguigu.pojo.Dept">
    <property name="deptId" value="105"></property>
    <property name="deptName" value="教学部门5"></property>
    <property name="empMap" ref="empMap"></property>
</bean>

第四章 Spring依赖注入方式

4.1 回顾为属性赋值几种方式

  • setXxx()方式
  • 构造器方式
  • 反射方式

4.2 Spring中三种依赖注入方式

  • set注入

    • 语法:<property name="" value="">标签

    • 属性

      • name:设置属性名称
      • value:设置属性数值【字面量数值】
      • ref:设置属性数值【非字面量数值】
    • 示例代码

      <!--    测试setter注入-->
      <bean id="dept1" class="com.atguigu.pojo.Dept">
          <property name="deptId" value="101"></property>
          <property name="deptName" value="研发部门"></property>
      </bean>
      
  • 构造器注入

    • 语法:<constructor-arg name="deptId" value="102"></constructor-arg>

    • 属性

      • name:设置属性名称
      • value:设置属性数值【字面量数值】
      • ref:设置属性数值【非字面量数值】
    • 注意:使用构造器注入方式,必须提供相应构造方法

    • 示例代码

      <!--    测试构造器注入-->
      <bean id="dept2" class="com.atguigu.pojo.Dept">
          <constructor-arg name="deptId" value="102"></constructor-arg>
          <constructor-arg name="deptName" value="教学部门"></constructor-arg>
      </bean>
      
  • p名称空间注入

    • 语法

      <?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:p="http://www.springframework.org/schema/p"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--    测试p名称空间注入-->
          <bean id="dept3"
                class="com.atguigu.pojo.Dept"
                p:deptId="103"
                p:deptName="教务部门">
          </bean>
      </beans>
      
    • 注意:p名称空间注入,本质是set注入。

第五章 Spring管理第三方bean【DruidDataSource】

5.1 Spring管理第三方bean步骤

  • 导入相关jar包
  • 装配bean
  • 获取bean

5.2 示例代码

<!--导入druid的jar包-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>
<!--导入mysql的jar包-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <!--<version>8.0.26</version>-->
    <version>5.1.37</version>
</dependency>
<?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 
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 加载外部属性文件-->
    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>

    <!-- 装配DruidDataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${db.driverClassName}"></property>
        <property name="url" value="${db.url}"></property>
        <property name="username" value="${db.username}"></property>
        <property name="password" value="${db.password}"></property>
    </bean>

</beans>
@Test
public void testDruidDataSource() throws Exception{

    ApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext_DruidDataSource.xml");

    DruidDataSource dataSource = context.getBean("dataSource", DruidDataSource.class);
    System.out.println("dataSource = " + dataSource);
    //测试,通过dataSource获取Connection对象
    DruidPooledConnection connection = dataSource.getConnection();
    System.out.println("connection = " + connection);

}

第六章 Spring中FactoryBean

6.1 FactoryBean概述

  • Spring提供两种Bean
    • 一种普通Bean
    • 另一种工厂Bean【FactoryBean】
  • FactoryBean作用:参与Bean的创建时,使用FactoryBean

6.2 使用FactoryBean

  • 实现FactoryBean接口

  • 重写FactoryBean中三个方法

  • 装配FactoryBean

  • 测试

    package com.atguigu.factorybean;
    
    import com.atguigu.pojo.Dept;
    import org.springframework.beans.factory.FactoryBean;
    
    /**
     * @author Chunsheng Zhang 尚硅谷
     * @create 2022/4/20 14:08
     */
    public class MyFactoryBean implements FactoryBean<Dept> {
    
        /**
         * 参与bean的创建,并返回
         * @return
         * @throws Exception
         */
        @Override
        public Dept getObject() throws Exception {
            Dept dept = new Dept(101,"研发部门");
            return dept;
        }
    
        /**
         * 返回bean的class即可
         * @return
         */
        @Override
        public Class<?> getObjectType() {
            return Dept.class;
        }
    
        public boolean isSingleton() {
            return true;
        }
    
    }
    
    <?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">
        <!--    装配factoryBean-->
        <bean id="dept" class="com.atguigu.factorybean.MyFactoryBean"></bean>
    
    </beans>
    
    @Test
    public void testFacoryBean(){
        //创建容器对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext_factoryBean.xml");
    
        Dept dept = context.getBean("dept", Dept.class);
        System.out.println("dept = " + dept);
    
    }
    

6.3 注意

  • 通过工厂bean【FactoryBean】获取对象,不是工厂bean本身,而是getObject()方法返回的对象

第七章 Spring中bean的作用域

7.1 语法

  • 在bean标签中添加scope属性即可

7.2 四种作用域

使用框架帮助我们创建对象时,使用无参构造器【所以必须提供无参构造器】

  • singleton【默认值】:单例【当前容器中,只有一个对象】
    • 创建容器对象时,创建装配对象
  • prototype:多例【当前容器中,存在多个对象】
    • 每次调用getBean()方法时,创建装配对象
  • request:请求域
    • 当前请求有效,离开当前请求失效
    • 当前请求:当前URL【地址栏】未改变即为当前请求,如URL改变则不在当前请求。
  • session:会话域
    • 当前会话有效,离开当前会话失效
    • 当前会话:默认情况,浏览器未关闭且未更换则在当前会话,如重启浏览器或更换浏览器则不在当前会话。

第八章 Spring中bean的生命周期

8.1 Spring生命周期

① 通过构造器或工厂方法创建bean实例【创建对象】

② 为bean的属性设置值和对其他bean的引用【为对象中属性赋值】

③ 调用bean的初始化方法【初始化】

④ bean可以使用了【使用】

当容器关闭时,调用bean的销毁方法【销毁对象】

  • 示例代码

    /**
     * 初始化Dept
     */
    public void initDept(){
        System.out.println("3. 初始化Dept操作!");
    }
    
    /**
     * 销毁Dept
     */
    public void destroyDept(){
        System.out.println("5. 销毁Dept操作!");
    }
    
    <bean id="dept"
          class="com.atguigu.pojo.Dept"
          init-method="initDept"
          destroy-method="destroyDept">
    
        <property name="deptId" value="101"></property>
        <property name="deptName" value="研发部门"></property>
    </bean>
    
    @Test
    public void testLifeCycle(){
        //创建容器对象
        ConfigurableApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext_lifeCycle.xml");
    
        Dept dept = context.getBean("dept", Dept.class);
        System.out.println("4. 使用dept = " + dept);
    
        //关闭容器对象
        context.close();
    
    }
    

8.2 Spring后置处理器

  • 作用:在bean的初始化方法的前&后再继续添加方法的支持

  • 实现

    • 实现BeanPostProcessor接口
    • 重写接口中的两个方法
      • postProcessBeforeInitialization():在初始化方法之前执行
      • postProcessAfterInitialization():在初始化方法之后执行
    • 装配后置处理器【所有bean装配,不能为局部bean装配】
  • 示例代码

    package com.atguigu.mybeanprocess;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.lang.Nullable;
    
    /**
     * @author Chunsheng Zhang 尚硅谷
     * @create 2022/4/20 15:18
     */
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        /**
         * 在初始化方法之前执行
         * @param bean
         * @param beanName
         * @return
         * @throws BeansException
         */
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("==>初始化方法【之前】执行!");
            return bean;
        }
    
    
        /**
         * 在初始化方法之后执行
         * @param bean
         * @param beanName
         * @return
         * @throws BeansException
         */
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("==>初始化方法【之后】执行!");
            return bean;
        }
    }
    
    <!--    为所有bean装配后置处理器-->
    <bean class="com.atguigu.mybeanprocess.MyBeanPostProcessor"></bean>
    
  • 添加后置处理器后的生命周期

    ① 通过构造器或工厂方法创建bean实例【创建对象】

    ② 为bean的属性设置值和对其他bean的引用【为对象中属性赋值】

    执行处理器的postProcessBeforeInitialization()方法

    ③ 调用bean的初始化方法【初始化】

    执行处理器的postProcessAfterInitialization()方法

    ④ bean可以使用了【使用】

    当容器关闭时,调用bean的销毁方法【销毁对象】

day07

第九章 Spring 自动装配

Spring提供两种装配风格

  • 手动装配
    • set注入
    • 构造器注入
    • p名称空间注入
  • 自动装配:无需使用上述标签或名称空间,就可以自动为对象中属性注入数值。

9.1 自动装配【xml】

  • 语法:在bean标签中,添加属性:autowire

    • byType:对象中属性类型与容器中class数值匹配。

      • 如果唯一匹配,则匹配成功

      • 如果匹配0个,则装配默认值null

      • 如果匹配多个,则报如下错误

        available: expected single matching bean but found 2: deptDao,deptDao2

    • byName:对象中属性名称与容器中id数值匹配

      • 如果数值一致,则匹配成功

      • 如果数值不一致,则装配默认值null

        成员变量与属性关系:封装后的成员变量称之为属性

    • 注意:

      • 基于xml方式自动装配,底层使用set注入。
      • 自动装配不能装配字面量数值
  • 示例代码

    <bean id="deptDao" class="com.atguigu.dao.impl.DeptDaoImpl"></bean>
    <bean id="deptMapper" class="com.atguigu.dao.impl.DeptMapper"></bean>
    <bean id="deptService"
              class="com.atguigu.service.impl.DeptServiceImpl"
                autowire="byName"></bean>
    
  • 总结:最终不推荐使用byType&byName,推荐使用注解方式

第十章 Spring中注解【非常重要】

10.1 使用注解装配对象

  • @Component:标识普通组件

  • @Repository:标识持久化层组件

  • @Service:标识业务逻辑层组件

  • @Controller:标识【表述层、表示层、控制层】组件

  • 注意:

    • Spring框架本身不区分四个注解【在业务逻辑层使用@Repository也不会报错】,使用四个注解的优势:增强代码可读性。
    • 注解位置:class上面
    • 注解默认会将类名首字母小写作为beanId,也可以是value属性设置bean的Id【如只使用value属性时,value关键字可省略】
    • 使用步骤
      • 导入jar包【aop的jar包已经导入】
      • 开启组件扫描【扫描注解标识组件】
      • 可以直接使用注解标识组件

10.2 使用注解装配对象中属性【自动装配】

  • @Autowired注解

    • 装配原理:反射机制【set注入&构造注入】

    • 装配方式【byType&byName】

      • 先按照byType进行匹配

        • 匹配一个,则匹配成功

        • 匹配0个

          • required=true,报如下错误

            available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:

          • required=false,会装配默认值【null】,不会报【装配】错

        • 匹配多个,再按照byName进行唯一筛选

          • 筛选成功【对象属性与bean的Id一致】,则自动装配成功
          • 筛选失败【对象属性与bean的Id不一致】,则按照byType风格报错
    • @Autowired注解属性:required属性

      • required=true:表示当前被标识的属性,必须装配数值,如未装配数值,会报错
      • required=false:表示当前被标识的属性,不必须装配数值,如未装配数值,不会报【装配】错,会将默认值【null】装配。
    • 示例代码

      //    @Autowired(required = false)
          private DeptDao deptDao;
      
      
          @Override
          public void saveDept(Dept dept) {
              deptDao.insertDept(dept);
          }
      
          @Autowired
          public void setDeptDao(DeptDao deptDao) {
              this.deptDao = deptDao;
          }
      
  • 设置自动装配名称的注解:@Qualifier

    @Autowired(required = false)
    @Qualifier("deptDaoMybatis")
    private DeptDao deptDao;
    
  • 设置自动装配字面量数值@Value

    @Value("101")
    private Integer deptId;
    @Value("研发部门")
    private String deptName;
    

第十一章 Spring组件扫描

<!-- base-package:设置扫描的当前包及其子包-->
<context:component-scan base-package="com.atguigu.annotation"></context:component-scan>

11.1 Spring开启组件扫描-排除扫描

<context:component-scan base-package="com.atguigu.annotation">
        <!-- 排除扫描[Controller] -->
<!--        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
        <context:exclude-filter type="assignable" expression="com.atguigu.annotation.controller.DetpController"/>
    </context:component-scan>
  • type:设置排除扫描类型
    • annotation:设置排除扫描注解全类名
    • assignable:设置排除扫描对象全类名

11.2 Spring开启组件扫描-包含扫描

<!--    假设当前项目中,共有100个包【其中:包含Controller(只扫描Controller)】-->
<context:component-scan base-package="com.atguigu.annotation" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
  • type:设置排除扫描类型
    • annotation:设置排除扫描注解全类名
    • assignable:设置排除扫描对象全类名
  • 注意:使用包含扫描时,需要关闭默认组件扫描

第十二章 Spring完全注解开发

  • 完全注解开发【0xml】

  • 示例代码

    @ComponentScan(basePackages = "com.atguigu.annotation")
    @Configuration  //标识当前类是一个配置类,代替xml配置文件
    public class SpringConfig {
    }
    
    ApplicationContext context =
            new AnnotationConfigApplicationContext(SpringConfig.class);
    
    Dept dept = context.getBean("dept", Dept.class);
    System.out.println("dept = " + dept);
    

第十三章 Spring继承Junit4

13.1 Spring整合Junit4步骤

  • 导入jar包

    • spring-test-5.3.1.jar
  • 在测试类上面添加两个注解

    @ContextConfiguration(locations = "classpath:application_annotation.xml")
    @RunWith(SpringJUnit4ClassRunner.class)    //标识当前Junit版本【Junit4】
    public class TestAnnotation {
        
        @Autowired
        private DeptService deptService;
        
         /**
         * 测试使用Spring装配对象中属性
         */
        @Test
        public void testAnnotationProperties() {
           deptService.saveDept(new Dept());
        }
        
    }
    

第十四章 工厂模式

  • 工厂模式:

    • 生活中工厂:
      • 服装厂:生产服装
      • 笔记本电脑厂:生产电脑
  • 程序中工厂:创建对象【管理对象】

  • 示例代码

    //获取连接
    public static Connection getConnection() {
       Connection connection = threadLocal.get();
       try {
          if(connection == null){
             connection = dataSource.getConnection();
             //将connection设置threadLocal
             threadLocal.set(connection);
          }
       } catch (SQLException e) {
          e.printStackTrace();
       }
       return connection;
    }
    

image-20230716093639997

day08

第十五章 AOP前奏

15.1 动态代理

  • 代理:生活中【中介】
  • 总结:目标对象不能转换为代理对象,因为是“兄弟”关系【宠物猫不能转换为宠物狗】

15.2 程序中

  • 需求:在“计算器”加减乘除基础上,添加日志功能【验证】

  • 日志:在计算之前,记录参数;在计算之后,记录返回结果

  • 示例代码

    public class CalcImpl implements Calc {
    
        @Override
        public int add(int a, int b) {
            System.out.println("==>add()方法,参数a:"+a+",b:"+b);
            int rs = a+b;
            System.out.println("==>add()方法,结果:rs"+rs);
            return rs;
        }
    }
    
  • 发现问题

    核心业务代码【加减乘除】,非核心业务代码【日志代码】

    • 日志代码比较分散
    • 核心业务代码与非核心业务代码,书写在一处,导致代码比较混乱
  • 解决问题

    • 思路:
      • 先将日志代码【非核心业务代码】横向提取切面【工具类】
      • 再将【非核心业务代码】动态织入到核心代码中

15.3 手动搭建动态代理

  • 动态代理的方式

    a)基于接口实现动态代理: JDK动态代理

    b) 基于继承实现动态代理: Cglib、Javassist动态代理

  • JDK动态代理实现步骤

    • Proxy类:代理类基类【类似Object】
      • Proxy.newProxyInsatance():创建代理对象
    • InvocationHandler接口:实现动态织入【动态将日志功能添加(织入)到业务代码中】
      • invoke():执行目标对象相应方法【中介帮我们干活】

image-20230716093651645

  • 实现动态代理步骤
    • 提供目标对象
    • 提供方法【获取代理对象】
    • 有参构造器

15.4 搭建动态代理-示例代码

package com.atguigu.aopbefore;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author Chunsheng Zhang 尚硅谷
 * @create 2022/4/24 8:53
 */
public class MyProxy {

    //    提供目标对象
    private Object target;

    //有参构造器【target不为空】
    public MyProxy(Object target){
        this.target = target;
    }

    /**
     * 提供方法【获取代理对象】
         ClassLoader loader,类加载器
         Class<?>[] interfaces,目标对象实现的所有接口集合
         InvocationHandler h,实现动态织入对象【invoke()】
     */
    public Object getProxy(){
        Object obj = null;
        //获取类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        //获取目标对象所有接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        obj = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获取方法名称
                String methodName = method.getName();
                //目标方法执行之前,日志
                MyLogging.methodBefore(methodName,args);
                //执行目标对象的相应方法【add()、sub()、mul()、div()】
                Object rs = method.invoke(target, args);
                //目标方法执行之后,日志
                MyLogging.methodAfter(methodName,rs);
                return rs;
            }
        });

        return obj;
    }

//    private class MyInvo implements InvocationHandler{
//
//        @Override
//        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//            return null;
//        }
//
//    }

}
//目标对象
        Calc calc = new CalcImpl();
        //获取代理对象的工具类对象
        MyProxy myProxy = new MyProxy(calc);
        //获取代理对象
        Calc calcProxy = (Calc)myProxy.getProxy();
        //错误的,代理对象不能转换为目标对象,兄弟关系不能相互转换
//        CalcImpl calcProxy = (CalcImpl)myProxy.getProxy();

        calcProxy.add(1,2);

第十六章 AOP框架【重点】

16.1 AspectJ框架

  • 概述:AspectJ是Java社区里最完整最流行的AOP框架
  • 在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。

16.2 使用AspectJ步骤

  • 导入jar包

    <!--spirng-aspects的jar包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.1</version>
    </dependency>
    
  • 在spring配置文件【applicationContext.xml】中开启AspectJ注解支持

    <!--配置自动扫描的包-->
        <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
    <!--开启AspectJ注解支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
  • 在非核心业务类中【MyLogging】添加注解@Aspect,在方法上添加@Before

16.3 AOP概述

  • OOP全称:Object-Oriented Programming【面向对象编程】
    • 纵向继承机制
  • AOP全称:Aspect-Oriented Programming【面向切面编程】
    • 横向提取机制

16.4 AOP相关术语

  • 横切关注点:非核心业务代码称之为:横切关注点【提取到切面之前】

    • 日志功能
  • 切面(Aspect):将非核心业务代码提取类,称之为切面类

    • MyLogging
  • 通知(Advice)非核心业务代码称之为:通知【提取到切面之后】

  • 目标(Target):被通知的对象称之为目标对象

    • CalcImpl
  • 代理(Proxy):向目标对象应用通知之后创建的代理对象

    //获取代理对象的工具类对象
    MyProxy myProxy = new MyProxy(calc);
    //获取代理对象
    Calc calcProxy = (Calc)myProxy.getProxy();
    
  • 连接点(Joinpoint):通知的位置称之为连接点【通知之前】

  • 切入点(pointcut):通知的位置称之为切入点【通知之后】

第十七章 AspectJ详解

17.1 切入点表达式

  • 语法:execution(权限修饰符 返回值类型 全类名.方法名(参数列表类型))

    execution(public int com.atguigu.aop.CalcImpl.add(int, int))
    
  • 通配符

    【*】可以代表如下语义

    • 可以代表任意权限修饰符及返回值类型
    • 可以代表任意全类名&方法名

    【..】可以代表任意参数类型

  • 示例代码

    //    @Before(value = "execution(public int com.atguigu.aop.CalcImpl.add(int, int))")
    //    @Before(value = "execution(* *.*(..))")
        @Before("execution(* com.atguigu.aop.CalcImpl.*(..))")
     public void methodBefore(JoinPoint joinPoint){}
    
  • 重用切入点表达式

    • 提取可重用的切入点表达式

      @Pointcut("execution(* com.atguigu.aop.CalcImpl.*(..))")
      public void myPointCut(){}
      
    • 使用方法名(),重用切入点表达式

      @Before("myPointCut()")
      public void methodBefore(JoinPoint joinPoint){}
      

17.2 JoinPoint对象

  • JoinPoint连接点对象【切入点对象】

  • 常用方法

    • Signature signature = joinPoint.getSignature():获取方法签名

      • 方法签名=方法名+参数列表

      • signature.getName():获取方法名

    • Object[] args = joinPoint.getArgs();

      • 获取参数

17.3 AspectJ中5个通知

  • 前置通知

    • 语法:@Before

    • 执行时机:在目标方法执行之前触发

    • 如有异常是否执行:是

    • 示例代码

       @Pointcut("execution(* com.atguigu.aop.CalcImpl.*(..))")
          public void myPointCut(){} 
      @Before("myPointCut()")
          public void methodBefore(JoinPoint joinPoint){
              //获取方法名
              Signature signature = joinPoint.getSignature();
      //        System.out.println("signature = " + signature);
              String methodName = signature.getName();
              //获取参数
              Object[] args = joinPoint.getArgs();
              System.out.println("==>前置通知:"+methodName+"()方法,参数:"+ Arrays.toString(args));
          }
      
  • 后置通知

    • 语法:@After

    • 执行时机:在目标方法执行之后触发【所有通知之后】

    • 如有异常是否执行:是

    • 示例代码

      /**
       * 方法之后
       */
      @After("myPointCut()")
      public static void methodAfter(JoinPoint joinPoint){
          String methodName = joinPoint.getSignature().getName();
          Object[] args = joinPoint.getArgs();
          System.out.println("==>后置通知:"+methodName+"()方法,参数:"+ Arrays.toString(args));
      }
      
  • 返回通知

    • 语法:@AfterReturning

    • 执行时机:返回结果之后出发

    • 如有异常是否执行:否

    • 示例代码

      /**
       * 返回通知
       */
      @AfterReturning(value = "myPointCut()",returning = "rs")
      public void afterReturning(JoinPoint joinPoint,Object rs){
          String methodName = joinPoint.getSignature().getName();
          System.out.println("==>返回通知:"+methodName+"()方法,结果rs:"+ rs);
      }
      
  • 异常通知

    • 语法:@AfterThrowing

    • 执行时机:出现异常时执行,未出现异常不执行

    • 如有异常是否执行:是

    • 示例代码

      /**
       * 异常通知
       */
      @AfterThrowing(value = "myPointCut()",throwing = "ex")
      public void afterThrowing(JoinPoint joinPoint,Exception ex){
          String methodName = joinPoint.getSignature().getName();
          System.out.println("==>异常通知:"+methodName+"()方法,异常Ex:"+ ex);
      }
      
    • 小结

      • 有异常:前置通知->异常通知->后置通知
      • 无异常:前置通知->返回通知->后置通知
  • 环绕通知【前四个通知集合】

    • 语法:@Around
    • 注意事项:
      • 必须使用ProceedingJoinPoint对象的proceed()方法,才可以事项环绕通知
      • 环绕通知必须设置返回值,且返回值是目标方法的返回结果
  • 示例代码

    /**
     * 环绕通知
     */
    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint pjp){
        String methodName = pjp.getSignature().getName();
        Object[] args = pjp.getArgs();
        Object rs = null;
        try {
            //前置通知
            System.out.println("==>前置通知:"+methodName+"()方法,参数:"+ Arrays.toString(args));
            //触发目标对象的相应方法【加减乘除方法】
            rs = pjp.proceed();
            //返回通知
            System.out.println("==>返回通知:"+methodName+"()方法,结果rs:"+ rs);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //异常通知
            System.out.println("==>异常通知:"+methodName+"()方法,异常throwable:"+ throwable);
        } finally {
            //后置通知
            System.out.println("==>后置通知:"+methodName+"()方法,参数:"+ Arrays.toString(args));
        }
        return rs;
    }
    

17.4 AspectJ中切面优先级

  • 语法:@Order(int index)

    • index默认值:int存储最大值
    • index数值越小优先级越高
  • 注意:建议index使用正整数

  • 示例代码

    @Component
    @Aspect
    //@Order(value = 1)
    @Order(2)
    public class MyValidate {}
    

17.5 基于XML方式实现AspectJ框架

<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置计算器实现类-->
    <bean id="calcImpl" class="com.atguigu.spring.aop.xml.CalculatorImpl"></bean>

    <!--配置切面类-->
    <bean id="myLogging" class="com.atguigu.spring.aop.xml.LoggingAspect"></bean>
	<bean id="myValidate" class="com.atguigu.aop.MyValidate"></bean>
    
    <!--AOP配置-->
    <aop:config>
        <!--配置切入点表达式-->
        <aop:pointcut id="pointCut"
                      expression="execution(* com.atguigu.spring.aop.xml.Calculator.*(..))"/>
        <!--配置切面-->
        <aop:aspect ref="myLogging">
            <!--前置通知-->
            <aop:before method="beforeAdvice" pointcut-ref="pointCut"></aop:before>
            <!--返回通知-->
            <aop:after-returning method="returningAdvice" pointcut-ref="pointCut" returning="result"></aop:after-returning>
            <!--异常通知-->
            <aop:after-throwing method="throwingAdvice" pointcut-ref="pointCut" throwing="e"></aop:after-throwing>
            <!--后置通知-->
            <aop:after method="afterAdvice" pointcut-ref="pointCut"></aop:after>
            <!--环绕通知-->
            <aop:around method="aroundAdvice" pointcut-ref="pointCut"></aop:around>
        </aop:aspect>
        <!-- 配置切面【验证】-->
        <aop:aspect ref="myValidate">
            <aop:before method="validateData" pointcut-ref="pointCut"></aop:before>
        </aop:aspect>
        
    </aop:config>
</beans>

第十八章 JdbcTemplate持久化层框架

SSH【Spring+Struts2+Hibernate】

SSM【Spring+SpringMVC+Mybatis】

18.1 JdbcTemplate概述

  • JdbcTemplate看作是一个小型的轻量级持久化层框架

18.2 搭建JdbcTemplate步骤

  • 导入jar包

    <!--spring-jdbc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.1</version>
    </dependency>
    <!--spring-orm-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>5.3.1</version>
    </dependency>
    
    <!--spring-context-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.1</version>
    </dependency>
    <!--导入druid的jar包-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
    <!--导入mysql的jar包-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.37</version>
    </dependency>
    <!--junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    
  • 编写配置文件【装配JdbcTemplate】

    • 加载外部属性文件:db.properties
    • 装配DataSource
    • 装配JdbcTemplate
  • 使用核心类库JdbcTemplate

18.3 JdbcTemplate常用API

  • 增删改通用方法:update(String sql,Object... args);

  • 批量增删改通用方法:batchUpdate(String sql,List<Object[]> list );

  • 查询单个数值:queryForObject(String sql,Class clazz,Object... args);

  • 查询单个对象:queryForObject(String sql,RowMapper,Object... args);

    • RowMapper:映射器对象,将对象中属性与表中字段进行映射
  • 查询多个对象:query(String sql,RowMapper mapper,Object... args);

day09

第十九章 Spring声明式事务管理

19.1 回顾事务相关知识点

  • 事务四大特征【特性】:ACID
    • 原子性
    • 一致性
    • 隔离性
    • 持久性
  • 事务三种行为【操作】
    • 开启事务:connection.setAutoCommit(false);
    • 提交事务:connection.commit();
    • 回滚事务:connection.rollback();

19.2 Spring中支持事务管理

  • 编程式事务管理【使用原生的JDBC API进行事务管理的步骤】

    1. 获取数据库连接Connection对象

    2. 取消事务的自动提交【开启事务

    3. 执行操作【核心业务代码

    4. 正常完成操作时手动提交事务

    5. 执行失败时回滚事务

    6. 关闭相关资源

    • 发现问题:
      • 核心业务代码与事务管理代码【非核心业务】相耦合,导致代码分散及代码混乱问题
    • 解决思路
      • 使用AOP思想【框架】,将事务管理代码先横向提取,再动态织入。【声明式事务管理
  • 声明式事务管理

    1. 导入jar包【AspectJ】

      <!--spirng声明式事务管理-->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-aspects</artifactId>
          <version>5.3.1</version>
      </dependency>
      
    2. 编写配置文件

      • 装配事务管理器【DataSourceTransactionManager】

      • 开启事务注解支持:

        <!--配置事务管理器-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <!--配置数据源属性-->
                <property name="dataSource" ref="dataSource"></property>
            </bean>
        
            <!--开启事务注解支持
                当事务管理器的id是transactionManager时,可以省略指定transaction-manager属性
            -->
        <!--    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>-->
            <tx:annotation-driven></tx:annotation-driven>
        
    3. 在需要事务管理的业务上添加注解即可【@Transactional

19.3 Spring中声明式事务管理属性

@Transactional注解属性值

注解位置

  • 类上
  • 方法上
  • propagation【事务传播行为】

    • 概述:当一个事务方法被另一个事务方法调用时,此时当前事务方法必须指定事务传播行为。

      • 如:执行事务方法method()【事务是x】之后,调用事务方法method()2【事务是y】,此时需要设置method()2的执行事务是x还是y。

      image-20230716093727742

    • 类型:Propagation枚举类型

      • REQUIRED【默认值】:如果有事务在运行,当前的方法就在这个事务内运行;否则就启动一个新的事务,并在自己的新事务内运行。

        image-20230716093739046

      • REQUIRES_NEW:当前的方法*必须*启动新事务,并在自己的事务内运行;如果之前有事务正在运行,应该将它挂起。

        image-20230716093745175

      • 其他事务传播行为

        传播属性 描述
        REQUIRED 如果有事务在运行,当前的方法就在这个事务内运行;否则就启动一个新的事务,并在自己的新事务内运行。
        REQUIRES_NEW 当前的方法*必须*启动新事务,并在自己的事务内运行;如果之前有事务正在运行,应该将它挂起。
        SUPPORTS 如果有事务在运行,当前的方法就在这个事务内运行,否则可以不运行在事务中。
        NOT_SUPPORTED 当前的方法不应该运行在事务中,如果有运行的事务将它挂起
        MANDATORY 当前的方法必须运行在事务中,如果没有正在运行的事务就抛出异常。
        NEVER 当前的方法不应该运行在事务中,如果有正在运行的事务就抛出异常。
        NESTED 如果有事务正在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在它自己的事务内运行。
    • 事务传播行为使用场景

      /*去结账:结账时,账号余额支持买多少本书,就允许用户购买
             如账户余额不充足怎么办?
                 需求1:不允许用户购买所有图书
      */
      @Transactional(propagation = Propagation.REQUIRED)
          public void purchase(String username, String isbn) {
              //查询book价格
              Integer price = bookShopDao.findBookPriceByIsbn(isbn);
              //修改库存
              bookShopDao.updateBookStock(isbn);
              //修改余额
              bookShopDao.updateUserAccount(username, price);
          }
      /*
      	去结账:结账时,账号余额支持买多少本书,就允许用户购买
                  如账户余额不充足怎么办?
                      需求2:不允许用户购买最后一本(导致余额不足)的图书及其之后的所有图书,
                              之前的其他图书正常购买
      */
       @Transactional(propagation = Propagation.REQUIRES_NEW)
          public void purchase(String username, String isbn) {
              //查询book价格
              Integer price = bookShopDao.findBookPriceByIsbn(isbn);
              //修改库存
              bookShopDao.updateBookStock(isbn);
              //修改余额
              bookShopDao.updateUserAccount(username, price);
          }
      
      
  • isolation【事务隔离级别】

    • 概述:事务隔离级别就是事务与事务之间隔离等级

    • 隔离级别如下

      • READ UNCOMMITTED【读未提交】:1
      • READ COMMITTED【读已提交】:2
      • REPEATABLE READ【可重复读】:4
      • SERIALIZABLE【串行化】:8
    • Oracle与Mysql隔离级别对比

      Oracle MySQL
      READ UNCOMMITTED ×
      READ COMMITTED √(默认)
      REPEATABLE READ × √(默认)
      SERIALIZABLE
    • 不同隔离级别可能出现现象

      image-20230716093759692

  • timeout【事务超时】

    • 设置事务超时的强制回滚时间
    • 类型:int,单位:秒
    • 默认值:-1
  • readonly【事务只读】

    • 默认值:false
    • 设置当前事务是否只读
    • 一般查询数据时,设置事务只读,提高一点性能
    • 如增删改操作中设置只读,会报如下错误
      • Connection is read-only. Queries leading to data modification are not allowed
  • rollbackFor|noRollbackFor【事务(是否)异常回滚】

    • rollbackFor:设置回滚的指定异常Class
    • noRollbackFor:设置不回滚的指定异常Class
  • 示例代码

    /**
         * //买书->查询book价格->修改库存->修改余额
         *
         * @param username
         * @param isbn
         */
        @Transactional(propagation = Propagation.REQUIRES_NEW,
                        timeout = 3,
                        readOnly = false,
                        noRollbackFor = NullPointerException.class)
        public void purchase(String username, String isbn) {
            //查询book价格
            Integer price = bookShopDao.findBookPriceByIsbn(isbn);
    
            try {
                String s = null;
                s.length();
            } catch (Exception e) {
                e.printStackTrace();
            }
            //测试事务超时
    //        try {
    //            Thread.sleep(5000);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }
    
            //修改库存
            bookShopDao.updateBookStock(isbn);
            //修改余额
            bookShopDao.updateUserAccount(username, price);
        }
    

19.4 基于XML方式使用声明式事务管理

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <property name="maxActive" value="${jdbc.maxActive}"></property>
    </bean>

    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--配置数据源属性-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置BookShopDaoImpl-->
    <bean id="bookShopDao" class="com.atguigu.spring.tx.xml.BookShopDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <!--配置BookShopServiceImpl-->
    <bean id="bookShopService" class="com.atguigu.spring.tx.xml.BookShopServiceImpl">
        <property name="bookShopDao" ref="bookShopDao"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--配置数据源属性-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置声明式事务-->
    <tx:advice id="tx" transaction-manager="transactionManager">
        <!--设置添加事务的方法-->
        <tx:attributes>
            <!--设置查询的方法的只读属性为true-->
            <tx:method name="find*" read-only="true"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="purchase" propagation="REQUIRES_NEW" isolation="READ_COMMITTED"></tx:method>
        </tx:attributes>
    </tx:advice>

    <!--AOP配置-->
    <aop:config>
        <!--配置切入点表达式-->
        <aop:pointcut id="pointCut"
                      expression="execution(* com.atguigu.spring.tx.xml.BookShopServiceImpl.purchase(..))"/>
        <!--将事务方法和切入点表达式关联起来-->
        <aop:advisor advice-ref="tx" pointcut-ref="pointCut"></aop:advisor>
    </aop:config>

</beans>

第二十章 Spring5新特性

20.1 Spring5新增一些注解

名称 含义 可标注位置
@Nullable 可以为空 @Target({ElementType.*METHOD*, ElementType.*PARAMETER*, ElementType.*FIELD*}
@NonNull 不应为空 @Target({ElementType.*METHOD*, ElementType.*PARAMETER*, ElementType.*FIELD*})
@NonNullFields 在特定包下的字段不应为空 @Target(ElementType.*PACKAGE*) @TypeQualifierDefault(ElementType.*FIELD*)
@NonNullApi 参数和方法返回值不应为空 @Target(ElementType.*PACKAGE*) @TypeQualifierDefault({ElementType.*METHOD*, ElementType.*PARAMETER*})
  • 以@Nullable注解为例

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

    此注解通常用来消除NullPointerException

20.2 Spring5整合Log4j2

  • 导入jar包

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.11.2</version>
        <scope>test</scope>
    </dependency>
    
  • 编写log4j2的配置文件:log4j2.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
    <!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
    <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="DEBUG">
                <appender-ref ref="Console"/>
            </root>
        </loggers>
    </configuration>
    

20.3 Spring5整合Junit5

  • 导入jar包:注意将junit4的相关jar包移除

    <!--spring-test-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.1</version>
    </dependency>
    
    <!--junit5-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.7.2</version>
        <scope>test</scope>
    </dependency>
    
  • 在测试类上添加注解

    • 方式一
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(locations = "classpath:beans-tx.xml")
    public class Junit5Test {}
    
    • 方式二
    @SpringJUnitConfig(locations = "classpath:beans-tx.xml")
    public class Junit5Test {}
    

标签:事务,对象,spring,bean,笔记,完整,Spring,方法,public
From: https://www.cnblogs.com/zdyu/p/17557463.html

相关文章

  • #Deeplearning#人工智能导论学习笔记
    神经网络基础线性函数(得分函数)计算每个类别的得分:每个像素点都会影响结果(像素点的权重参数)f(image,parameters)每个像素点都需要有一个权重,每个像素点会按RGB拆分成三个矩阵中的元素单行矩阵(每个像素点的权重)x像素点(所有像素点)=1x1矩阵(得分)f(x,W)=Wx+b简而言之,就是每......
  • 《架构整洁之道》学习笔记 Part 2 编程范式
    计算机编程发展至今,一共只有三个编程范式:结构化编程面向对象编程函数式编程编程范式和软件架构的关系结构化编程是各个模块的算法实现基础多态(面向对象编程)是跨越架构边界的手段函数式编程是规范和限制数据存放位置与访问权限的手段软件架构的三大关注重点:功能性、组......
  • 【学习笔记】山东省队第三轮集训
    Day2A.sequence题目描述:题目分析:考虑一个很简单的\(dp\)就是设\(f[i]\)表示考虑了前\(i\)个位置最多可以划分为多少个序列。转移就是可以直接从\(f[i-1]\)继承,或者从\(j\)满足\(\sum_{k=j+1}^{i}c_i=0\),也就是前缀和相等。可以发现的是对于从\(j\)转移这种......
  • Springboot JPA 集成多租户
    背景:​ iot-kit项目用的是jpa,不是mybatis,项目中需要引入多租户参考文章:【讲解多租户的实现与原理】https://www.bilibili.com/video/BV1F84y1T7yf/?share_source=copy_web&vd_source=981718c4abc87423399e43793a5d3763https://callistaenterprise.se/blogg/teknik/2020/10/17......
  • tarjan 学习笔记
    tarjan学习笔记求解强联通分量我们从一个点开始建立dfs树,有如下四种边:树边若\(u\)到\(v\)有边,且满足\(v\)没有被访问过,则这条边为树边返祖边若\(u\)到\(v\)有边,且满足\(v\)已被访问过,则这条边为返祖边横叉边若\(u\)到\(v\)有边,且满足\(u\)和......
  • 《架构整洁之道》学习笔记 Part 1 概述
    本书主题介绍什么是优秀的软件架构,以提高软件架构质量介绍系统架构的各种属性与成本和生产力的关系,以采用好的设计和架构以便减少构建成本好的软件架构可以带来什么?大大节省软件项目构建与维护的人力成本每次变更:改动少,易于实施,不容易出bug用最小的成本,最大程度满足功能......
  • SpringCloud 集成和使用 Dubbo
    SpringCloud是当前比较流行的微服务开发框架,因此很有必要介绍一下SpringCloud集成和使用Dubbo技术。本篇博客在上一篇博客的Demo基础上,对pom文件和yml配置文件进行了修改,就可以完成SpringCloud集成和使用Dubbo的Demo。是的,你没有看错,没有修改代码,只是修改了pom......
  • 每日一题:SpringBoot中支持的事务类型
    以下是每种事务类型的作用、代码示例和对代码的解释:PROPAGATION_REQUIRED(默认):作用:如果当前存在事务,则方法将在该事务中运行;如果不存在事务,则创建一个新的事务。适用于大多数业务场景,确保方法在事务中执行,如果没有事务,则创建一个新的事务。代码示例:@Transactional(propagatio......
  • springboot配置2
    核心自动配置原理        @condition条件判断注解 如果没配过就给你配 依赖底层的condition注解 里面参数是条件配置类  红色的就是不满足条件的类 ......
  • springboot 配置
    配置文件yam 名字是固定的,yaml后缀也可以比XML更适合 大量的标记被浪费yml语法把空格玩到极致   如何编写yaml文件并绑定  只有这个组件是容器中的组件才能使用容器的功能@COmponent如何在properties编写 value配置对比     ......