spring基础知识点总结

java框架学习之spring基础


前言

自己学习spring时总结的一些知识点笔记

内容来源于动力节点王妈妈,带你走进spring,学会spring的简单使用

一、容器中的对象

  • 放入容器中的对象:
    • dao类,service类,controller类,工具类
    • String中的对象默认都是单例的,在容器中叫这个名字的对象只有一个
  • 不放入容器中的对象:
    • 实体类对象,实体类数据来自于数据库
    • servlet,listener,filter是由tomcat服务器这个容器进行创建的
  • 把对象放入容器中的方法:
    • 使用xml的配置文件,使用bean标签
    • 注解

二、关于IOC的理解

  • 目的:减少对代码的改动,实现不同的功能
  • ioc的使用实现技术为:di(依赖注入):只需要提供对象的名称,对象的查找,创建,赋值都是交给容器来完成
  • 控制反转,把对象的创建,赋值,管理工作都交给代码之外的容器去实现,也就是对象的创建由其他的外部资源进行实现
    • 控制:创建对象,对象的属性赋值,对象之间的关系管理
    • 反转:原来的开发人员管理,创建对象的权限转移给代码之外的容器去实现,由容器来管理对象的创建以及给属性赋值

三,spring的实现步骤:

  • 新建maven项目

  • 加入maven的依赖

    • spring的依赖
    • junit的依赖
  • 创建类

  • 创建spring需要使用的配置文件

    • 声明类的信息,这些信息由spring创建和管理
  • spring配置文件的介绍(applicationContext.xml):

  •  <!--    声明bean,告诉spring创建某个类的对象
     
             id :对象的自定义名称,唯一值(Spring通过这个名称找到对象)
             class :类的全限定名称,(不能是接口也,因为spring底层用的反射来创建的对象)
     
     
             创建对象:SomeService someService = new ServiceImpl();
             spring 把创建好的对象放入map集合中,
             一个bean声明一个对象
     -->
     
         <bean id="someService" class="org.powernode.service.impl.ServiceImpl"/>
    
  • spring创建对象的步骤:

    • spring创建非自定义类的对象:

      • 在spring配置文件中指定id和class=“类的全限定类名”,就可以
    • 在创建spring容器对象时,会创建配置文件中所有的对象

    • //        1,指定spring配置文件的名称
              String config = "beans.xml";
      //        2,创建表示spring容器的对象,ApplicationContext(表示spring容器,通过这个容器可以获取对象)
              ApplicationContext application = new ClassPathXmlApplicationContext(config);
      //        3,new ClassPathXmlApplicationContext(“文件的路径”);  表示从类路径中加载spring配置文件,创建出来的对象需要指定其类型
      //        * application.getBean("someService"); 参数为配置文件中id值
              SomeService someService =(SomeService) application.getBean("someService");
      
  • 获取容器中java对象信息的api

  •   // 获取容器中对应的对象的数量
      int count = application.getBeanDefinitionCount();
      // 获取每个定义的对象的名称
      String[] applicationName = application.getBeanDefinitionNames();
    

在spring的配置文件中,给java对象赋值:

  • di: 依赖注入,表示创建对象,给属性赋值。
  • di的实现语法有两种:
    • 在spring的配置文件中,使用标签和属性完成,基于xml的di实现
    • 在spring中的注解,完成对属性的赋值。
  • di的语法分类:
set注入(设置注入):spring调用类的set方法,在set方法中实现对属性的赋值
  • 在spring的配置文件中:

  •  <bean id="myStudent" class="org.powernode.service.SomeService" >
         <!--多个属性,多个property标签-->
         <property name="属性名字" value="属性值"/> 
         <!--找的时name属性对应的set方法-->
     </bean>
     
     -----------------------------
     一个bean代表一个java对象
    
  • 设值注入的注意事项:

    • 属性的类型是简单类型
    • 需要在java类中设置set方法(set方法在无参构造方法执行之后执行的)
    • 方法不管是不是程序员自己写的,只要有set方法在spring配置文件中,就会被执行
  • 引用数据类型的赋值:

  •  <!--
         <bean id="xxx" class="yyy">
             <properties name="属性名称"  ref="bean的id(就是对象的名称)"/>
         </bean>
      -->
    
  • 例子:

  •   <!--   引用类型的set注入-->
          <bean id="myStudent" class="org.powernode.service.impl.StudentImpl">
              <property name="name" value="lisi"/>
              <property name="age" value="22"/>
      
              <property name="school" ref=""/>
          </bean>
          
          <bean id="mySchool" class="org.lirunxin.powernode.service.impl.SchoolImpl">
              <property name="name" value="海淀"/>
              <property name="address" value="xxx"/>
          </bean>
    
构造注入,spring调用有参类的构造方法,创建对象,在构造方法中完成对属性的赋值
  • spring调用类的带参构造方法的同时,在创建对象的同时,在构造方法中给属性赋值。

  •  <!--构造注入在bean中使用<constructor-arg>标签   一个该标签表示一个构造方法的一个参数-->
     <constructor-arg>标签的属性:
         	name : 表示构造方法的形参名
         	index : 表示构造方法参数的位置,参数下标从0开始
         			index可以省略,但是省略以后必须按照顺序写
         	value :构造方法的形参类型是简单类型,使用value赋值
         	ref : 构造方法的形参是引用类型 ,使用ref来进行赋值
         
         -----------------------------------------------------------------
          <bean id="myStudent" class="org.powernode.service.impl.StudentImpl">
             <constructor-arg name="myName" value="张三"/>
             <constructor-arg name="myAge" value="20"/>
             <constructor-arg name="mySchool" ref="mySchool"/>
         </bean>
         
          <bean id="mySchool" class="org.powernode.service.impl.SchoolImpl">
             <property name="name" value="海淀"/>
             <property name="address" value="xxx"/>
         </bean>
    
  • 构造注入创建文件对象:

    • <bean id="myFile" class="java.io.File">
          <constructor-arg name="parent" value="C:\Users\Desktop"/>
          <constructor-arg name="child" value="chengyu.txt"/>
      </bean>
      
引用类型的自动注入:
  • 只对引用类型的数据有效

    • byName(按名称注入)

      • Java类中引用类型的属性名和spring容器中(配置文件)的bean中的id值一样
      • 并且数据类型一致,这样的容器中的bean,spring能够赋值给引用类型
    • 语法:

    •  <bean id="xx" class="yyy" autowire="byName">
           简单数据类型的属性赋值
       </bean>
       
       ---------------------------------------------------
       <bean id="myStudent" class="org.powernode.service.impl.StudentImpl" autowire="byName">
            <constructor-arg name="name" value="张三"/>
            <constructor-arg name="age" value="20"/>
           
            <!--<constructor-arg name="school" ref="mySchool"/>-->
       </bean>
       
       <!--必须保证属性名和id值一样--->
         <bean id="school" class="org.powernode.service.impl.SchoolImpl">
               <property name="name" value="海淀"/>
               <property name="address" value="xxx"/>
           </bean>
      
    • byType(按照类型进行注入):

      • java类中引用数据类型和spring容器中(配置文件)bean的class属性是同源关系的,这样的bean能够赋值给引用数据类型

      • 同源

        • java类中的引用数据类型的数据类型和bean中的class值是一样的
        • java类中的引用数据类型的数据类型和bean的class的值是父子关系的
        • java类中的引用数据类型的数据类型和bean的class的值是接口和实现类关系的
      • 语法:

      •  <bean id="xx" class="yyy" autowire="byType">
             简单数据类型的属性赋值
         </bean>
        

      注意: 在xml配置文件中,声明bean只能有一个符合条件的

配置文件的使用:

使用多配置文件的原因:
  • 每个文件的大小比一个文件的要小,效率高

  • 避免多人竞争带来的冲突

  • 多文件的分配方式:

    • 按功能模块,一个模块一个配置文件
      • 按类的功能,数据库相关的配置一个配置文件,做事务的功能一个配置文件,做service的一个配置文件
  • total.xml表示主配置文件:

    • 主配置文件是包含其他的配置文件,并且主配置文件一般不定义对象

    • 语法:

    •   <import resource="其他配置文件的路径"/>
        关键字:
        	"classpath:" 表示类路径,(class文件所在的目录),
        						在spring的配置文件要指定其他配置文件的位置
        						需要使用classpath,告诉spring到哪里去加载读取文件
        ----------------------------------------------------------------------
        实例:
        	<import resource="classpath:ba06/spring-school.xml"/>
        
        在包含关系的配置文件中,可以使用通配符("* : 表示任意字符")
        	<import resource="classpath:ba06/spring-*.xml"/>
      

基于注解的DI:

  • 使用注解的步骤:

    • 加入maven的依赖,加入spring-context的同时,间接的加入了spring-aop的依赖,使用注解必须使用spring-aop依赖
    • 在spring中加入注解,(多个不同功能的注解)
    • 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你项目中的位置。
  • 注解类型:

  •  @Component(value = "myStudent") 注解的作用: 创建对象,相当于xml文件中的bean的功能
     									属性:value(可以省略)指明对象的名称,就是bean的id值,value值是唯一的
     									创建的对象在整个spring容器中就只有一个
         							位置:在实体类的上边,表示创建创建本类的对象 
         
         
      @Component : 没有指定value的话spring会提供默认的对象名称: 类名的首字母小写
         
         
         
     然后在applicationContext.xml文件中声明组件扫描器
     base-package	 : 指定注解在你项目中的包名
         <context:component-scan base-package=""/>
    
  • 和@Component功能相似的其他几个:

    • @Repository(持久层):放在dao的实现类上面,表示创建dao对象,dao是对象是能够访问数据库的。

    • @Service(业务层) :放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。

    • @Controller(用在控制器上面的) :放在控制器类的上面,创建控制器对象。能够接收用户提交的参数,显示请求的处理结果

      以上的三个注解使用的语法和@Component一样的,都能创建对象,但是三个注解还有额外的作用

  • 扫描多个包的方式:

    • 使用多次的组件扫描器标签,指定不同的包

    • 使用分隔符(;或者,)分隔多个包名

    •  <context:component-scan base-package="com.powernode.ba01;com.powernode.ba02"/>
      
    • 指定父包:

      • <context:component-scan base-package="com.powernode"/>
        
  • 简单类型的属性赋值:

    • @value(简单类型的属性赋值):

      • 属性: value是String类型的,表示简单数据类型的属性值

      • 位置:在属性定义的上面,无需set方法(常用)或者是在set方法的上面

      • 例子:

        • @Value(value = "李四")
          private String name;
          @Value(value = "29")
          private Integer age;
          
  • 引用类型

  •  /**
      *  给引用类型赋值
      * @Autowired  : spring 框架提供的注解,实现引用数据类型的赋值
      * spring中通过注解给引用类型赋值,使用的是自动注入原理
      * 默认使用的是byType自动注入
      * 位置:在属性定义的上面,无需set方法, 推荐使用
      *      在set方法上
      */
     @Autowired
     private School school;
     
     
     ========================
         @Autowired的byName
         1,在属性的上面加入@Autowired
         2,需要在属性的上面加入@Qualifier(value="bean的id") 
         	: 表示使用的指定的名称完成赋值
         
         例子:
          @Autowired
         @Qualifier(value = "mySchool")
         private School school;
    
  • 引用类型Autowired的required属性:

    • required是一个bool类型的,默认为true : 引用类型赋值失败,程序报错,并且终止执行(在项目中使用,可以暴露错误,尽快的解决问题)。
    • 当required=false时, 引用类型赋值失败,程序不会报错,但是输出结果中引用类型的结果为null
  • JDK中的注解@Resource自动注入

  •  来自jdk中的注解,spring框架提供了注解的功能支持,可以使用她给引用类型进行赋值,使用的原理为自动注入
         			支持byName,byType,默认的是byName
         位置:1,在属性的上面,无需set方法
         	2,在set方法上面
     
     先使用byName进行自动注入,如果byName赋值失败,再使用byType
     @Resource
     private School school;
     
     // 只使用byName的方式
     @Resource(name="mySchool")
     private School school;
    

配置文件和注解的方式的选择:

需要经常修改的就使用xml文件配置,不需要经常修改的使用注解

动态代理:

  • 动态代理:
    • 在程序执行的过程中,创建代理对象,通过代理对象执行方法,给目标的类的方法增加额外的功能。
  • 动态代理的作用:
    • 在目标源代码不变的情况下,增加功能。
    • 减少代码的重复。
    • 让开发专注于逻辑业务。
    • 解耦合,让业务功能和非业务功能分开。

aop

  • 使用时机:

    • 当要给系统本来存在的类修改功能,但是类的功能不完善,并且我们没有源代码,使用aop增强功能
    • 要给系统的多个类增加一个相同的功能,使用aop
    • 给业务方法增加事务,日志输出
  • 面向切面编程,基于动态代理的,可以使用jdk,cglib两种动态代理的方式。

  • aop就是动态代理的规范化,把动态代理的实现方式和步骤定好了,我们使用统一的方式。

  • 面向切面编程:

    • 给目标类额外增加的功能,就是切面。切面的特点是:一般都是非业务方法,独立使用的。
    • 在分析项目的功能时,找到切面 。合理的安排切面的执行时间(在目标方法的前后问题)。合理安全切面执行的位置。
  • aop实现框架:

    • spring:spring在内部实现了aop规范,但是因为比较笨重,所以很少使用

    • aspectj: 专门做aop的框架,spring集成了aspectJ

      • aspectj实现aop有两种方式:
        • 使用配置文件。
        • 使用注解(常用)
    • aspect框架的使用:

      • 切面的执行时间,在规范中叫做Advance(增强),在aspectj中使用注解来表示(一个注解代表一个时间点)

        • @Before : 在目标方法执行前执行的功能
        • @AfterReturning
        • @Around
        • @AfterThrowing
        • @After
      • 表示切面执行的位置,使用的是切入点表达式:

        • 使用步骤:
          • 新建maven项目

            • 加入spring依赖
            • 加入aspectj依赖
          • 创建目标类(包括接口和他的实现类),给类中的方法增强功能

          • 创建切面类,普通类

            • 在类的上面加入注解:@Aspect

            •   /**
                 * @Aspect :是aspectj框架中的注解
                 *    作用 :表示当前类是切面类
                 *    切面类:用来给业务方法增加功能的类,这个类中有切面的功能代码
                 *      位置; 在类定义的上边
                 */
                @Aspect
                public class MyAspect {
                
                
                }
              
            • 在类中定义方法,方法就是切面要执行的功能代码

              • 在方法的上面要加入aspectj中的时间注解,例如:@Before

              • 指定切入点表达式excution();

            • 例子:

            •   /**
                 * 定义方法: 方法是实现切面功能
                 *  方法的定义要求:
                 *      公共方法
                 *      方法没有返回值
                 *      方法名自定义
                 *      方法的参数可有可无
                 *      如果有参数,参数不是自定义的,有几个参数类型可以使用
                 */
                
                
                /**
                 * @Before("") :
                 *  属性: value :是切入点表达式,表示切面功能的执行位置
                 *  位置; 在方法的上边
                 *  特点:
                 *      在目标方法执行之前执行的
                 *      不会改变目标方法的执行结果
                 *      不会影响目标方法的执行
                 */
                @Before(value = "execution(public void com.lirunxin.powernode.ba01.SomeServiceImpl.doSome(String,Integer))")
                public void myBefore() {
                    System.out.println("切面的前置功能:" + new Date());
                }
              
            • 切面表达式的多种写法:

            •  @Before(value = "execution(void com.lirunxin.powernode.ba01.SomeServiceImpl.doSome(String,Integer))")
               
               @Before(value = "execution(void *..SomeServiceImpl.doSome(String,Integer))")
               
               @Before(value = "execution(* *..SomeServiceImpl.doSome(..))")
               
               @Before(value = "execution(* *..SomeServiceImpl.do*(..))")
               
               @Before(value = "execution(* do*(..))")
              
            • 一个业务方法可以有多个增强的功能方法

            • 创建spring的配置文件:声明对象,把对象交给容器统一管理。

              • 声明对象可以使用注解或者xml文件配置bean标签。

              • 声明目标对象,声明切面对象,声明aspectj框架中的自动代理生成器标签

              • 自动代理生成器:用来完成代理对象的自动创建功能的。

              • <!--    自动代理生成器-->
                <!--    创建目标对象的代理对象,创建代理对象是在内存中实现的,修改目标对象的内存中的结构,创建为代理对象
                        所以目标对象就是被修改后的代理对象
                         <aop:aspectj-autoproxy/>  : 这个标签会一次性生成spring容器中所有的代理对象
                -->
                    <aop:aspectj-autoproxy/>
                

JoinPoint

  • 指定通知方法中的参数 : joinPoint :业务方法,要加入切面功能的业务方法,

    • 作用:可以在通知方法中获取方法执行时的信息,例如:方法名称,方法的实参
      如果你的切面功能中需要用到方的信息,就加入joinpoint

    • 这个joinpoint参数的值是由框架赋予的,必须是第一位置的参数。

      @Before(value = "execution(void *..SomeServiceImpl.doSome(String ,Integer))")
      public void myBefore(JoinPoint pj ) { // JoinPoint必须是方法的第一个参数
          System.out.println("切面的前置功能:" + new Date());
      }
      
      
      // 当我们在执行测试目标方法的时候,这个方法的所有信息全部保存在pj中
      //   获取方法的信息 
      
            System.out.println("获取方法的定义" + pj.getSignature());
      
              System.out.println("方法的名称:" + pj.getSignature().getName());
      
              Object[] args = pj.getArgs();
              for (Object arg:
                   args) {
                  System.out.println("方法的实参" + arg);
              }
      
后置通知:
  • 后置通知的定义方法:

    • 要求:
      • 公共方法public
      • 方法没有返回值
      • 方法名自定义
      • 方法有参数,推荐是Object,参数名为自定义
  • 后置通知:AfterReturning

    • 属性:

      • value ,切入点表达式

      • returning ,自定义的变量,表示目标方法的返回值。自定义的变量名必须和通知方法的形参名一致(和方法参数的名字一样)。

      • 例子:

      •  @AfterReturning(value = "execution(* *..SomeServiceImpl.doSome(..)))",returning = "res")
         public void myAfterReturning(Object res) {
         		// Object res:是目标方法执行以后的返回值,根据返回值做切面功能的处理
             System.out.println("后置通知,在目标方法执行之后执行的,获取的返回值为:" + res);
         }
        
    • 位置:在方法的定义的上边

    • 特点:

      • 在目标方法执行之后执行的
      • 能够获取到目标方法的返回值,可以根据返回值做出不同的功能。
      • 可以修改返回值

joinPoint在所有的通知中都可以使用,并且都是位于参数列表的第一位。

环绕通知:
  • 经常做事务,在目标方法执行前开启事务,在目标方法结束后关闭事务

  • 方法的定义格式:

    • public ,必须有返回值,返回值类型为Object,方法名称自定义,方法名称必须有参数,并且参数是固定的。

    • @Around:环绕通知

      • 属性:value : 切入点表达式
      • 位置:在方法定义的上边,它是功能最强的通知,在目标方法的前后都可以加功能
      • 控制目标方法是否被执行
      • 修改原来的目标方法的执行结果。影响最后的调用结果
    • 增强方法中的参数:ProcessdingJoinPoint 作用是执行目标方法

    •  public Object myAround(ProceedingJoinPoint pjp) {
       	//ProceedingJoinPoint  返回值就是目标方法的返回结果,可以被修改
           // ProceedingJoinPoint 继承于 JoinPoint 所以前者可以当作后者使用,
           // 获取增强方法的信息
           
           // 在目标方法执行前加的功能代码
           
       	//目标方法的调用:
           Object result = pjp.proceed();
           
           // 在目标方法执行之后加的功能代码
           return result;
       }
      

异常通知:

  • @AfterThrowing :
    • 定义格式:
      • public
      • 没有返回值
      • 方法名称自定义
      • 方法可以没有参数,如果有的话就是JoinPoint,Exception
    • 属性:
      • value是切入点表达式
      • throwing 自定义的变量,表示目标方法抛出的异常对象。变量名必须和方法的参数的名字一样
    • 特点:
      • 在目标方法出现异常时执行,可以做异常的监控程序,监控目标方法执行时是不是有异常,如果有异常,我们发送邮件或者短信进行通知
最终通知:
  • @After
    • 一般是进行清除操作的
    • 定义格式
      • public
      • 没有返回值
      • 方法名称自定义
      • 方法没有参数, 如果有的话就是JoinPoint
    • 属性:
      • value 切面表达式
      • 位置在方法的上边
    • 特点:
      • 总是会执行
      • 在目标方法执行之后执行
PointCut注解:
  • 定义和管理切入点的,如果你的项目中有多个切入点表达式是重复的,可以复用的,可以使用@PointCut

  • 属性:

    • value : 切入点表达式
    • 位置:在自定义的方法的上边
  • 特点:

    • 当我们在自定义方法的使用@PointCut时,此时的这个方法的名称就是切入点表达式的别名,其他的通知中,value属性就可以使用这个方法的名称,代替切入点表达式
  • 没有接口的是cglib动态代理,但是有接口也可以使用cglib动态代理。

  • 如果希望目标类有接口,那么声明自动代理生成器时需要设置:

  • <aop:aspectj-autoproxy proxy-target-class="true"/>
       
    <!-- proxy-target-class="true" 就是告诉框架使用cglib动态代理  -->
    

spring整合mybatis

  • 新建maven项目

  • 加入maven的依赖

    • spring依赖

    • mybatis依赖

    • mysql驱动

    • spring的事务依赖

    • mybatis和spring集成的依赖

  •  <dependencies>
     <!--    单元测试-->
         <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.11</version>
           <scope>test</scope>
         </dependency>
     
     <!--    spring核心ioc-->
         <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>5.2.5.RELEASE</version>
         </dependency>
     <!--    spring事务-->
         <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-tx</artifactId>
           <version>5.2.5.RELEASE</version>
         </dependency>
         <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
           <version>5.2.5.RELEASE</version>
         </dependency>
     <!--      mybatis依赖-->
           <dependency>
               <groupId>org.mybatis</groupId>
               <artifactId>mybatis</artifactId>
               <version>3.5.2</version>
           </dependency>
     <!--      mybatis和spring集成的依赖-->
           <dependency>
               <groupId>org.mybatis</groupId>
               <artifactId>mybatis-spring</artifactId>
               <version>1.3.1</version>
           </dependency>
     <!--      mysql驱动-->
           <dependency>
               <groupId>mysql</groupId>
               <artifactId>mysql-connector-java</artifactId>
               <version>8.0.26</version>
           </dependency>
     <!--      ali连接池-->
           <dependency>
               <groupId>com.alibaba</groupId>
               <artifactId>druid</artifactId>
               <version>1.1.12</version>
           </dependency>
       </dependencies>
     
     
         <build>
     <!--        目的是将src/main/java目录中的xml文件包含到输出结果中,输出到classes目录中-->
             <resources>
                 <resource>
     <!--                文件所在的目录-->
                     <directory>src/main/java</directory>
                     <includes>
     <!--                    目录下的.properties.xml文件都会被扫描到-->
                         <include>**/*.properties</include>
                         <include>**/*.xml</include>
                     </includes>
                     <filtering>false</filtering>
                 </resource>
             </resources>
     <!--指定jdk的版本-->
             <plugins>
                 <plugin>
                     <artifactId>maven-compiler-plugin</artifactId>
                     <version>3.1</version>
                     <configuration>
                         <source>1.8</source>
                         <target>1.8</target>
                     </configuration>
                 </plugin>
             </plugins>
         </build>
    
  • 创建实体类

  • 创建mapper接口和mapper.xml文件

  • mapper接口

  •   package com.powernode.mapper;
      
      import com.powernode.pojo.Student;
      
      import java.util.List;
      
      public interface StudentMapper {
      
          int insertStudent(Student student);
      
          List<Student> selectStudents();
      }
    
  • Studentmapper.xml文件

  •  <?xml version="1.0" encoding="UTF-8" ?>
     <!DOCTYPE mapper
             PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     <mapper namespace="com.powernode.mapper.StudentMapper">
     
         <insert id="insertStudent">
             insert into student values (#{s_no},#{class_no},#{s_name},#{s_sex});
         </insert>
     
         <select id="selectStudents" resultType="com.powernode.pojo.Student">
             select * from student order by s_no desc;
         </select>
     </mapper>
    
  • 创建mybatis核心配置文件

    • <?xml version="1.0" encoding="UTF-8" ?>
      
      <!DOCTYPE configuration
      
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      
              "http://mybatis.org/dtd/mybatis-3-config.dtd">
      
      <configuration>
      
          <properties resource=""/>
      
      <!--    设置日志-->
          <settings>
              <setting name="logImpl" value="STDOUT_LOGGING"/>
          </settings>
      <!--    设置别名-->
          <typeAliases>
      <!--        实体类所在的包名-->
              <package name="com.powernode.pojo"/>
          </typeAliases>
      
          <mappers>
              <package name="com.powernode.mapper"/>
          </mappers>
      </configuration>
      
  • 创建service接口和实现类,属性是mapper

    • service接口

    • package com.powernode.service;
      
      import com.powernode.pojo.Student;
      
      import java.util.List;
      
      public interface StudentService {
          int addStudent(Student student);
      
          List<Student> queryStudent();
      }
      
    • 实现类:

      • package com.powernode.service.impl;
        
        import com.powernode.mapper.StudentMapper;
        import com.powernode.pojo.Student;
        import com.powernode.service.StudentService;
        
        import java.util.List;
        
        public class StudentServiceImpl implements StudentService {
        
            // 引用类型
            private StudentMapper studentMapper;
            //使用set注入来赋值
            public void setStudentMapper(StudentMapper studentMapper) {
                this.studentMapper = studentMapper;
            }
        
            @Override
            public int addStudent(Student student) {
                int count = studentMapper.insertStudent(student);
                return count;
            }
        
            @Override
            public List<Student> queryStudent() {
                List<Student> students = studentMapper.selectStudents();
                return students;
            }
        }
        
  • 创建spring的配置文件:声明mybatis 的对象交给spring来创建

  • 数据源

    <!--    声明数据源DataSource,作用:连接数据库-->
        <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" >
    <!--        set注入给DruidDataSource提供连接数据库的信息-->
            <property name="url" value="jdbc:mysql://localhost:3306/student"/>
            <property name="username" value="root"/>
            <property name="password" value="xxxx"/>
            <property name="maxActive" value="20"/>
    </bean>
    <!--配置完成表示Connection对象已经创建成功-->
    
  • SqlSessionFactory对象

  •  <!--声明sqlSessionFactoryBean类,这个类内部创建SqlSessionFactory的-->
         <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
     <!--        set注入,把数据量的连接池赋给了DataSource-->
             <property name="dataSource" ref="myDataSource"/>
     <!--mybatis主配置文件的位置
         configLocation :  读取配置文件的
         使用value进行赋值,指定配置文件的路径,使用classPath:表示文件的位置
     -->
             <property name="configLocation" value="classpath:mybatis-config.xml"/>
         </bean>
    
  • mapper对象

  •   <!--    创建mapper对象,使用SqlSession的getMapper(StudentMapper.class)
              MapperScannerConfigurer :在内部调用getMapper()生成每个Mapper接口的代理对象
      -->
          <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
      <!--        指定SqlSessionFactory对象的id-->
              <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
      <!--        指定包名
              MapperScannerConfigurer :会扫描这个包中的所有接口,把每个接口都执行一次getMapper()方法,得到每个接口的mapper对象
              创建好的mapper对象放入spring容器中的。
      -->
              <property name="basePackage" value="com.powernode.mapper"/>
          </bean>
    
  • 声明自定义的service

    • <!--    声明service对象-->
          <bean name="studentService" class="com.powernode.service.impl.StudentServiceImpl">
              <property name="studentMapper" ref="studentMapper"/>
          </bean>
      
  • 测试service:

  •  /**
      * 测试service
      */
     @Test
     public void test03() {
         String config = "ApplicationContext.xml";
         ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
     
         StudentServiceImpl studentMapper = (StudentServiceImpl) ctx.getBean("studentService");
         Student student = new Student();
         student.setS_no(64);
         student.setClass_no("194541");
         student.setS_sex("女");
         student.setS_name("蔡徐坤");
         int count = studentMapper.addStudent(student);
         System.out.println("count = " + count);
     }
    

处理事务的问题

  • 在spring中事务放在service类的业务方法上,因为业务方法会调用多个mapper方法,执行多个sql语句。

  • spring统一处理事务的方式:

    • 使用统一的步骤,方式完成多种不同的数据库访问技术的事务处理

    • 声明式事务:把事务相关的资源和内容提供给spring,spring就能处理事务提交,回滚。

    • 步骤:

      • 事务管理器对象,完成commit,和rollback。事务管理器是一个接口和他众多的实现类。
        • 接口:PlatformTransactionManger,定义了事务的重要方法,commit,rollback
        • 实现类:spring将每一种数据库访问技术的事务处理类都创建好了
      • 声明数据库访问技术对应的实现类,在spring的配置文件中使用bean标签声明
        • 例子: : 声明的是mybatis访问数据库
      • 说明需要的事务的类型:
        • 事务的隔离级别:
          • READ_UNCOMMITTED : 读未提交。未解决任何的并发问题。
          • READ_COMMITTED : 读已提交。解决脏读,存在不可重复读和幻读
          • REPEATABLE_READ : 可重复读。解决了脏读和不可重复读,存在幻读
          • SERIALIZABLE :串行化,不存在并发的问题。
        • 事务的超时时间:
          • 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就进行回滚,单位为s,默认为-1(无限长)。
        • 事务的传播行为:
          • 控制业务方法是否是有事务的
          • 7个传播行为:表示业务方法调用时,事务在方法之间是如何进行使用的(重点的三个)。
            • PROPAGATION_REQUIRED :
              • 指定的方法必须在事务内进行,如果当前存在事务,就加入到当前的事务中,如果当前没有事务,则创建一个新的事务。是spring默认的事务传播行为。
            • PROPAGATION_REQUIRES_new :
              • 总是创建一个新的事务,若当前存在事务,就将当前事务挂起,直到新的事务执行完毕。
            • PROPAGATION_SUPPORTS :
              • 指定的方法支持事务,但若当前没有事务,也可以已非事务方式执行。
      • 事务提交,回滚的时机:
        • 当你的业务方法执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后自动提交事务。
    • 给方法添加事务:

      • spring框架的事务处理注解(适合中小项目使用):

        • @Transactional 这个注解放在public方法的上面,表示当前的方法具有事务。

        • 可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等。

        • 使用@Transactional 的可选的属性:

          • propagation :用于设置事务传播属性,该属性的类型是Propagation 枚举类型。默认值为:

            Propagation .REQUIRED

          • isolation : 用于设置事务的隔离级别,该类型为isolation枚举,默认值为Isolation.DEFAULT

          • readonly:用于设置该方法对数据库的操作是否为只读的。默认值为false

          • timeout:用于设置本操作与数据库连接的超时时限。默认值为-1,即没有时限。

          • rollbackFor:指定回滚的异常类,类型为:Class[] ,默认值为空数组,只有一个异常类时,可以不适用数组。

          • rollbackForClassName:指定需要回滚的异常类类名。类型为String[] ,默认为空数组。

          • noRollbackFor:指定不需要回滚的异常类,类型为Class[] 。

          • noRollbackForClassName:指定不需要回滚的异常类类名

    • 使用@Transactional的步骤:

      • 1,声明事务管理器对象

      •  <bean id="xxx" class="DataSourceTransactionManger"/>
        
      • 2,开启事务注解驱动,告诉spring框架,要使用注解的方式管理事务,spring使用aop机制,创建注解所在类的代理对象,给方法加入事务的功能。

        • 在ApplicationContext.xml文件中配置
      •  <!--    声明事务管理器-->
             <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <!--        连接数据库的信息-->
                 <property name="dataSource" ref="myDataSource"/>
         <!--        开启事务注解驱动
                     transaction-manager:事务管理器对象的id-->
                 <tx:annotation-driven transaction-manager="transactionManager"/>
             </bean>
        
      • spring给业务方法加入事务:

        • 在业务方法执行之前开启事务,在方法执行之后提交或者回滚事务。使用的是aop的环绕通知

        •   /**
             * rollbackFor;表示发生的异常一定回滚
             	处理逻辑:
             		spring框架会首先检查方法抛出的异常是不是在rollbackFor的属性值中,
             		如果异常在rollbackFor列表中,不管什么类型的异常,一定执行回滚。
             		2,如果抛出的异常不在rollbackFor列表中,spring会判断异常是不是runtimeExecption,如果				是就一定进行回滚
             * @return
             */
            @Transactional(
                    propagation = Propagation.REQUIRED,
                    isolation = Isolation.DEFAULT,
                    readOnly = false,
                    rollbackFor = {
                            NullPointerException.class,NotEnoughExpection.class
                    }
            )
            
            
            // 另外一种直接在方法上边添加@Transactional就等同上边的
            public void buy(Integer goodsId,Integer nums) {
                
            }
          
      • aspectj配置aop

        • 适合大型的项目,有很多的类,方法。需要大量的配置事务,使用aspectj框架功能,在spring配置文件中声明类,方法需要的事务。这种方式实现了业务方法和事务的配置的完全分离。

        • 实现步骤(在xml配置文件中实现的):

          • 在pom文件中加入sapectj依赖

            • <!--      aspectj依赖-->
                    <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                        <version>5.2.5.RELEASE</version>
                    </dependency>
              
        • 声明事务管理器

          • <!--    声明事务管理器-->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--        连接数据库的信息 ,声明数据源-->
                    <property name="dataSource" ref="myDataSource"/>
                </bean>
            
      • 声明方法需要的事务类型:(配置方法的事务属性:隔离级别,传播行为,超时设置)

        • <!--
              声明业务方法的他的事务属性:(隔离级别,传播行为,超时时间)
                  id: 自定义名称,来表示tx:advance这个标签的中的配置内容
                  transaction-manager:事务管理器对象的id
          -->
          
              <tx:advice id="myAdvance" transaction-manager="transactionManager">
                  
          <!--     tx:attributes :   配置事务属性-->
                  
                  <tx:attributes>
          <!--      tx:method : 给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
                      name : 方法的名称:  
          						完整的方法名称,不带有包和类,
          						方法可以使用通配符 * 表示任意字符
                      propagation : 传播行为
                      isolation  : 隔离级别
                      no-rollback-for : 指定的异常类类名 :全限定类名。发生异常时一定回滚。
              -->
                      <tx:method name="" propagation="" isolation="" no-rollback-for=" "/>
                  </tx:attributes>
              </tx:advice>
          
        • 配置aop,指定哪些类需要创建代理。

        •   <!--    配置aop-->
                <aop:config>
            <!--        配置切入点表达式 : 指定哪些包中的类,要使用事务
                               id : 切入点表达式的名称,唯一值
                               expression : 切入点表达式,aspectj会创建代理对象
                               com.bjpowernode.service
                               com.crm.service
                               com.service
                        -->
                    <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
            
            <!--        配置增强器:关联advice和pointcut  :
                                advice-ref : 通知,上面tx:advice那里的配置
                                pointcut-ref : 切入点表达式的id
            
                           : 将tx:advice和切入点表达式相关联
                                -->
                    <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/>
                </aop:config>
          

配置监听器:

    • web项目中的容器对象只需要创建一次,将容器对象放入到全局变量作用域ServletContext中
  • 使用监听器当全局作用域对象被创建的时候,创建容器,放入ServletContext

    • 监听器的作用:

      • 创建容器对象:

      •   ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        • 把容器对象放入到ServletContext。
    • 监听器可以自己创建,也可以使用框架提供的ContextLoaderListener。

      • 加入依赖:

      •  <!--      监听器依赖-->
               <dependency>
                   <groupId>org.springframework</groupId>
                   <artifactId>spring-web</artifactId>
                   <version>5.2.5.RELEASE</version>
               </dependency>
        
    • 在web.xml文件中注册监听器:

    •   <listener>
        	<listener-class>...ContextLoaderListener</listener-class>
        </listener>
      
      • 监听器创建对象后,会读取/WEB—INF/applicationContext.xml文件

        • 在监听创建ApplicationContext对象,需要加载配置文件

        • 修改默认的文件位置:

        •  <context-param>
              <!-- contextConfigLocation : 表示配置文件的路径 --> 
           	<param-name>contextConfigLocation</param-name>
               <!--自定义配置文件的路径-->
               <param-value>classpath:applicationContext.xml</param-value>
           </context-param>
          
      • 使用监听器(自己写的):

        • WebApplicationContext ctx = null;
           
             String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
           
             Object attr = getServletContext().getAttribute(key);
          
工具类的使用:
  • ServletContext sc = getServletContext();
    WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
    
  • 配置监听器

    • 目的:创建容器对象,创建了容器对象,就能把spring.xml文件中所有的对象都创建好

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值