Spring框架从入门到精通(纯干货,建议收藏)

文章目录

    • 概述
    • ioc控制反转
      • 配置文件
      • 使用spring创建对象
      • 给属性赋值
        • set注入
        • 构造注入
        • 引用类型的自动注入
        • 注解
          • 简单类型属性注入@Value(掌握)
          • 引用类型注入@Autowired
          • 引用类型注入@Resource
    • 注解和配置文件的对比
    • 多配置文件优势
    • 组件扫描器
    • AOP面向切面编程
      • @Aspect:表示当前类是切面类
      • @Before:前置通知注解
      • @AfterReturning:后置通知
      • @Around 环绕通知
      • @AfterThrowing:异常通知(了解)
      • @After:最终通知(了解)
      • @Pointcut注解:定义和管理切入点
      • 实际操作:
    • 指定通知方法中的参数:JoinPoint
    • spring集成Mybatis
      • 步骤
    • spring的事务处理
      • PROPAGATION_REQUIRED
      • PROPAGATION_SUPPORTS
      • PROPAGATION_REQUIRES_NEW
      • spring提交事务,回滚事务的时机
      • spring框架中提供的事务处理方案
    • web项目中怎么使用spring
        • 使用方法:
    • 思维导图(建议保存下来回顾)![在这里插入图片描述](https://img-blog.csdnimg.cn/20210607223312429.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDAwNjY4Ng==,size_16,color_FFFFFF,t_70#pic_center)

前言,文章很长,但是满满干货,建议认真阅读.

概述

spring全家桶:spring,springmvc,spring boot,spring cloud

spring:出现在2002左右,为了解决企业开发难度.能够减轻对项目模块之间的管理和类和类之间的管理,帮助开发人员创建对象,管理对象之间的关系

spring核心技术:ioc(控制反转),aop(面向切面编程)能实现模块之间,类之间的解耦合.

依赖:class A中使用class B的属性或者方法,叫做class A依赖class B

Spring框架从入门到精通(纯干货,建议收藏)_第1张图片

maven加入spring的依赖


      <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-contextartifactId>
          <version>5.2.5.RELEASEversion>
      dependency>

ioc控制反转

框架的理解:框架是一个软件,是其他人写好的软件

  1. 知道框架能做什么,mybatis–访问数据库,对表中的数据执行增删改查
  2. 框架的语法,框架要完成一个功能,需要一定的步骤支持的
  3. 框架的内部实现,框架内部怎么做,原理是什么—>进一步的提升
  4. 通过学习,可以实现一个框架

spring的第一个核心功能 ioc

ioc(Inversion of Control):控制反转,是一个理论,概念,思想

简单描述:把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是说对象的创建是由其他外部资源来完成.

  • 控制:创建对象,对象的属性赋值,对象之间的关系管理.

  • 反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现由容器来代替开发人员管理对象,创建对象,给属性赋值.

  • 正转:由开发人员在代码中,使用new构造方法创建对象,开发人员主动管理对象.

    public static void main(String args[]){

    ​ Student student = new Student ();//在代码中,创建对象–正转

    }

  • 容器:是一个服务器软件,一个框架(spring)

为什么要使用ioc:对就是减少对代码的改动,也能实现不同的功能.实现解耦合.

java中创建对象有哪些方式:

  1. 构造方法
  2. 反射
  3. 序列化
  4. 克隆
  5. ioc:容器创建对象
  6. 动态代理

ioc的体现:servlet :

  1. 创建类继承HttpServlet

  2. 在web.xml注册servlet,使用

<servlet-name>myservletservlet-name>

   <servlet-calss>bjpowernode.MyServletservlet-calss>
  1. 没有创建servlet对象,从没有MyServlet myservlet = new MyServlet()

  2. servlet是tomcat服务器他给你创建的.tomcat也称为容器

    tomcat作为容器:里面存放的有Servlet对象,Listener,Filter对象

IOC的技术实现:

DI是ioc的技术实现,

DI(Dependency Injection):依赖注入,只需要在程序中提供要是用的对象名称就可以,至于对象如何在容器中创建,赋值,查找都由容器内部实现.

spring是使用了DI实现了ioc的功能,spring底层创建对象,使用的是反射机制

spring是一个容器,管理对象,给属性赋值,底层是反射创建对象

配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="someServlet" class="com.bjpowernode.service.impl.SomeServletImpl">bean>

beans>

使用spring创建对象

  //使用spring容器创建的对象
        //1.指定spring配置文件的名称
        String config = "beans.xml";
        //2.创建表示spring容器的对象,ApplicationContext
        //ApplicationContet就是表示Spring容器,通过容器对象获取对象了
        //ClassPathXmlApplicationContext:表示从类路径中加载spring的配置文件
       /*
       * spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中的所有对象
       * */
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);

        //从容器中获取某个对象,你要调用对象的方法
        //getBean("配置文件中的bean的id值")
        SomeServlet servlet = (SomeServlet)ac.getBean("someServlet");

        //使用spring创建好的对象
        servlet.doSome();
 //使用spring提供的方法,获取容器中定义的对象的数量
        int nums = ac.getBeanDefinitionCount();
//容器中每个定义的对象的名称
        String[] names = ac.getBeanDefinitionNames();

给属性赋值

set注入



<bean id="myStudent" class="com.bjpowernode.ba01.Student">
        <property name="name" value ="张三"/>
        <property name="age" value ="20"/>
    bean>

相当于调用了对象的set方法

注意事项:

  1. 执行顺序是:先执行无参构造方法,后执行的是set方法赋值(如果没有set方法会报错,但set方法里面由开发人员决定)
  2. 如果id=“email” ,但是这个类中没有email属性,有一个setEmail()方法,则会执行setEmail()方法,只要有set方法就能用

注入引用对象方法:

  2).引用类型的注入:spring调用类的set方法
             <bean id = "xxx" class = "yy">
                  <property name ="属性名称" ref = "bean的id(对象的名称)"/>
             bean>

构造注入

构造注入:spring调用类的有参构造方法,在创建构造参数的同时,在构造方法中给属性赋值
构造注入 使用标签
标签:一个表示构造方法中的一个参数.
标签属性:
name表示构造方法的形参名
index:表示构造方法的参数的位置,参数从左往右位置时0,1,2的顺序
value:构造方法的形参类型是简单类型的,使用value
ref:构造方法的形参类型是引用类型的,使用value


    <bean id="myStudent" class="com.bjpowernode.ba03.Student">
      <constructor-arg name="myname" value="张三"/>
      <constructor-arg name="myage" value="20"/>
      <constructor-arg name="myschool" ref="myXueXiao"/>
    bean>


    <bean id="myStudent2" class="com.bjpowernode.ba03.Student">
        <constructor-arg index="0" value="李四"/>
        <constructor-arg index="1" value="26"/>
        <constructor-arg index="2" ref="myXueXiao"/>
    bean>

引用类型的自动注入

spring框架根据某些规则,可以给引用类型赋值.不需要你再给引用类型赋值了,适用的规则常用的byName,byType

  1. byName(按名称注入):java类中引用类型的属性名和spring容器中(配置文件)的id名称一样,且数据类型一致,这样的容器中的bean,spring能够赋值给引用类型

  2. 语法:

   <bean id = "xx" class ="yyy" autowire="byName">  

简单类型属性赋值

  1. byType(按类型注入):java类中引用类型和spring容器中(配置文件)的class属性是同源关系的,这样bean能够赋值给引用类型

    同源就是一类的意思:

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

注解

基于注解的DI:通过注解完成java对象的创建,属性赋值

使用注解的步骤:

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

需要学习的注解:

  1. @Component
  2. @Respotory
  3. @Service
  4. @Controller
  5. @Value
  6. @Autowired
  7. @Resource

@Component:(value属性指定对象的名称)

简写@Component(“myStudent”)

如果不写对象名称,由spring提供默认对象名称名称:类名的首字母小写

/**
 * @Compoent:是用来创建对象的,等同于bean的功能
 *    属性value就是对象的名称,也就是的id值,
 *    value的值是唯一的,创建的对象在整个spring容器中就一个
 *    位置:在类的上面
 *
 *    @Component(value = "myStudent")等同于
 *    
 *
 *    spring中和@Component功能一致,创建对象的注解还有:
 *    1.@Repository(用在持久层类的上面):放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的
 *    2.@Service(放在业务层类的上面):放在Service的实现类的上面,创建service对象,
 *           service对象是做业务处理,可以有事务功能的
 *    3.@Controller(放在控制器的上面):放在控制器类的上面,创建控制器对象的控制器对象,
 *           能够接受用户提交的参数,显示请求的处理结果.(Servlet)
 *
 *    以上三个注解的使用语法和@Component一样的.都能够创建对象,但是这三个注解还有额外的功能
 *
 *    @Repository,@Service,@Controller是给项目的对象分层的
 *    当一个类既不是dao,service,controller的时候,可以使用@Component
 */

@Component@Respotory@Service@Controller看上面的注释

简单类型属性注入@Value(掌握)

@Value:简单类型的属性赋值

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

  • 位置:1.在属性定义上面,无需set方法,推荐使用

    ​ 2.在set方法的上面

        @Value("张飞")
        private String name ;
        @Value("29")
        private  int age;
    
引用类型注入@Autowired

引用类型

  • @Autowired:spring框架提供的注解,实现引用类型的赋值

  • spring中通过注解给引用类型赋值,使用的是自动注入原理 ,支持byName,byType

  • @Autowired:默认使用的是byType自动注入

  • 位置:1.在属性定义的上面,无需set方法,推荐使用

    ​ 2.在set方法的上面

  • 属性:required,是一个boolean类型的,默认为true

    required= true:表示引用类型赋值失败,程序保存,并终止执行

    required = false:引用类型如果赋值失败,程序正常执行,引用类型是null

  • 如果要使用byName的方式,需要做 的是:

  1. 在属性的上面,加入@autowired

  2. 在属性的上面加入**@Qualifier(value=“bean的id”)*表示使用指定名称的bean完成赋值

  @Autowired
    @Qualifier(value="mySchool")
    private School school;
引用类型注入@Resource

引用类型

  • @Resource:来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值
  •        使用的也是自动注入的原理,支持byName,byType默认为byName
    
  • 位置:1.在属性定义的上面,无需set方法,推荐使用
  • 2.在set方法上面
    
  • 默认是byName:先使用byName自动注入,如果byName赋值失败,在使用byType
  • @Resource只使用byName方式,需要增加一个属性 name
  • name的值是 bean的id
@Resource//(name = "mySchool")
private School school;

注解和配置文件的对比

经常改动的对象使用配置文件,不经常改动的使用注解

注解的缺点:使代码不易读

多配置文件优势

  1. 每个文件的大小比一个文件要小很多,效率高
  2. 避免多人竞争带来的冲突

如果你的项目由多个模块(相关的功能在一起),一个模块一个配置文件.

多文件的分配方式:

  1. 按功能模块,一个模块一个配置文件
  2. 按照类的功能,数据库相关的配置一个配置文件

怎样做:

分为主配置文件(包含关系的配置文件)和其他配置文件

主配置文件包含其他配置文件,主配置文件一般不定义对象

语法:

<import resource ="其他配置文件的路径"/>
       关键字:"classpath:"表示类路径(calss所在的目录),在spring的配置文件中要制定其他文件的地址
需要使用classpath,告诉pring到哪去架子啊读取文件.
<import resource="classpath:ba06/spring-school.xml"/>

在包含关系的配置文件中,可以通配符

组件扫描器


<context:component-scan base-package="com.bjpowernode.ba01"/>

指定多个包的三种方式:

  1. 使用多次组件扫描器,指定不同的包

  2. 使用分隔符(;或,)分隔多个包名

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

    <context:component-scan base-package="com.bjpowernode"/>
    

AOP面向切面编程

aop底层,就是采用动态代理模式实现的

  1. 动态代理:jdk动态代理,使用jdk中的Proxy,Method,InvocationHander创建的对象

    jdk动态代理要求目标类必须实现接口

    chlib动态代理:第三方的工具库,创建代理对象,原理是继承.通过继承目标类,创建子类.子类就是代理对象.要求目标类不能是final的,方法也不能是final的

  2. 动态代理的作用:

    1).在目标类源码不改变的情况下,增加功能

    2). 减少代码的重复

    3). 专注业务逻辑代码

    4).解耦合,让你的业务功能和日志,事务非业务功能分离

  3. AOP:面向切面编程,基于佛那个太代理的,可以使用jdk,cglib两种代理方式.

    aop就是动态代理的规范化,把动态代理的实现步骤,方式都定义好了,让开发人员使用一种统一的方式,就用动态代理.

  4. AOP(Aspect Orient Programming)面向切面编程

    Aspect:切面,给你的目标类增加的功能,就是切面.像上面用的日志,事务都是切面.

    Orient:面向

    Programming:编程

    **切面的特点:**一般都是非业务方法,独立使用的

    Orient:面向,对着.

    Programming:编程

    怎么理解面向切面编程 ?

    1. 需要在分析项目功能时,找出切面
    2. 合理的安排切面的执行时间(在目标方法前,还是目标方法后)
    3. 合理的安排切面执行的位置,在哪个类,那个方法增加增强功能

    术语:

    1. Aspect:切面,表示增强的功能,就是一堆代码,完成某一个功能.非业务功能,常见的切面功能有日志,事务,统计信息,参数检查,权限验证
    2. JoinPoint:连接点,连接业务方法和切面的位置,就是某类中的业务方法
    3. Pointcut:切入点,指多个连接点方法的集合.多个方法
    4. 目标对象:给哪个类的方法增加功能,这个类就是目标对象
    5. Advice:通知,表示切面功能执行的时间

    一个切面有三个关键的要素:

    1. 切面的功能代码,切面干什么
    2. 切面的执行为止,使用Pointcut表示切面的执行位置
    3. 切面的执行时间:使用Advice表示时间,在目标方法之前,还是在目标方法之后
  5. AOP的实现

    aop是一个规范,是动态代理的一个规范化,一个标准

    aop的技术实现框架:

    1. spring:spring在内部实现了aop的规范,能做aop的工作

      spring主要在事务处理时使用aop

      我们项目开发中很少使用spring的aop实现.因为spring的aop比较笨重

    2. aspectJ:一个开源的,专门做aop的框架.spring框架中继承了aspectJ框架,通过spring就能使用aspectJ的功能

      aspectJ框架实现aop有两种方式:

      1. 使用xml的配置文件
      2. 使用注解,我们在项目中要做sop功能,一般都是用注解,aspectJ有五个注解
  6. 学习aspectJ框架的使用:

    1. 切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强)

      在aspectJ框架中使用注解表示的,也可以使用xml配置文件中的标签

      1).@Before

      2). @AfterReturning

      3). @Around

      4). @AfterThrowing

      5). @After

    2. 表示切面执行的位置,使用的是切入点表达式

      execution(访问权限 方法返回值 方法声明(参数) 异常类型)

      加黑的是必须有的,其他可选.在其中可以使用以下符号:

      • *:0至多个任意字符
      • …:用在方法参数中,表示任意多个参数,用在报名后,表示当前包及其子包路径
      • 用在类名后,表示当前类及其子类,用在接口后,表示当前接口及其实现类

@Aspect:表示当前类是切面类

@Aspect:是aspectJ框架中的注解

  • 作用:表示当前类是切面类

  • 切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码

  • 位置:类定义的上面

    定义方法,是实现切面功能的.

    方法的定义要求:

    • 1.必须是公共方法
    • 2.没有返回值
    • 3.方法名称自定义
    • 4.方法可以有参数,也可以没有参数
    • 如果有参数,参数不是自定义的,有几个参数类型可以使用'
      

@Before:前置通知注解

@Before:前置通知注解

  • 属性:value,是切入点表达式,表示切面的功能执行的位置
    
  • 位置:在方法的上面
    
  • 特点:
  • 1.在目标方法之前先执行的
  • 2.不会改变目标方法的执行结果
  • 3.不会影响目标方法的执行

@AfterReturning:后置通知

属性:1.value 切入点表达式

  • 2.returning 自定义的一个变量,表示目标方法的返回值

  • 自定义的变量名必须和通知方法的形参名一样

  • 位置:方法定义的上面

  • 特点:

    在目标方法之后执行

    能够获取到目标方法的返回值,可以根据这个返回这做不同的处理

    可以修改这个返回值

后置通知定义方法,是实现切面功能的.

  • 方法的定义要求:
  • 1.必须是公共方法
  • 2.没有返回值
  • 3.方法名称自定义
  • 4.方法有参数,推荐使用Object

@Around 环绕通知

环绕通知 方法的定义格式

  • 1.public
  • 2.必须要有一个返回值,推荐使用Object
  • 3.方法名称自定义
  • 4.方法有参数,固定的参数ProceedingJoinPoint

@Around 环绕通知

  • 属性:value 切入点表达式

  • 位置:在方法定义的上面

  • 特点:

    1.他是功能最强的通知

    2.在目标方法前和后都能增强功能

    3.能够控制目标方法是否被调用执行

    4.修改原来的目标方法的执行结果,影响最后的调用结果

  • 环绕通知:等同于动态代理,InvocationHandler接口

  • 参数:ProceedingJoinPoint 就等同于Method

  •  作用:执行目标方法的
    
  • 返回值:目标方法的执行结果,可以被修改

  • 环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标之后提交事务

@AfterThrowing:异常通知(了解)

异常通知 方法的定义格式

  • 1.public
  • 2.没有返回值
  • 3.方法名称自定义
  • 4.方法有一个Exception,如果还有就是JoinPoint

@AfterThrowing:异常通知

  • 属性:

  • 1.value 切入点表达式

  • 2.throwing 自定义的变量,表是目标方法抛出的异常对象

  • 变量名必须和方法的参数名一样

  • 特点:

  • 1.在目标方法抛出异常时执行的

  • 2.可以做异常的监控程序,可以监控目标方法执行时是不是有异常

  •   如果有异常,可以发送邮件,短信进行通知
    
  • 执行就是

     try{
     SomeServiceImpl.doSecond(..);
    }catch(Exception e){
     myAfterThrowing(e);
      }
    

@After:最终通知(了解)

最终通知 方法的定义格式

  • 1.public
  • 2.没有返回值
  • 3.方法名称自定义
  • 4.方法没有参数,有的话就是JoinPoint

@After:最终通知

  • 属性:value 切入点表达式
  • 位置:在方法的上面
  • 特点:
  • 1.总是会执行
    
  • 2.在目标方法之后执行的
  • 一般做资源清除工作的

理解为

try{
      SomeServiceImpl.doFinally(..)
  }catch(Exception e){

  }finally{
      myAfter()
  }

@Pointcut注解:定义和管理切入点

@Pointcut :定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,可以复用的

  •        可以使用@Pointcut
    
  • 属性:value 切入点表达式
  • 位置:在自定义的方法上面
  • 特点:
  • 1.当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式别名
    
  • 其他的通知中,value属性就可以使用这个方法名称,代替切入点表达式了
    

实际操作:

ch06-aop-aspectj:使用aspectj框架实现aop
使用aop:给已经存在的一些类和方法,增加额外的功能,前提是不改变原来的类的代码.

使用aspectj实现aop的基本步骤:
1.新建一个maven的项目
2.加入依赖
     1).spring依赖
     2).aspectj依赖
     3).junit单元测试
3.创建目标类:接口合它的实现类
  要做的事给类中的方法增加功能

4.创建切面类:普通类
     1).在类的上面加入@Aspect
     2).在类中定义方法,方法就是切面要执行的功能代码
         在方法上面加入aspectJ中的通知注解,例如@Before
         还需要指定切入点表达式execution()

5.创建spring的配置文件:声明对象,把对象交给容器统一管理
     声明对象可以使用注解,或者xml配置文件
     1).声明目标对象
     2).声明切面类对象
     3).声明aspectj框架中的自动代理生成器标签
         自动代理生成器:用来完成代理对象的自动创建功能的.
6.创建测试类,从spring容器中获取目标对象(实际就是代理对象).
   通过代理执行方法,实现aop的功能增强.

3.创建目标类:

public interface SomeService {
    void doSome(String name,Integer age);
}

//目标类
public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name, Integer age) {
        //给dosome方法增加功能,在dosome ()执行之前,输出方法的执行时间
        System.out.println("=============目标方法dosome()=============");
    }
}

4.创建切面类

/**
 * @Aspect:是aspectJ框架中的注解
 *     作用:表示当前类是切面类
 *     切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
 *     位置:类定义的上面
 */
@Aspect
public class Myaspect {
    /**
     * 定义方法,是实现切面功能的.
     * 方法的定义要求:
     * 1.必须是公共方法
     * 2.没有返回值
     * 3.方法名称自定义
     * 4.方法可以有参数,也可以没有参数
     *     如果有参数,参数不是自定义的,有几个参数类型可以使用
     */

    /**
     * @Before:前置通知注解
     *     属性:value,是切入点表达式,表示切面的功能执行的位置
     *     位置:在方法的上面
     * 特点:
     *   1.在目标方法之前先执行的
     *   2.不会改变目标方法的执行结果
     *   3.不会影响目标方法的执行
     *
     */
    @Before(value="execution(public void com.bjpowernode.ba01.SomeServiceImpl.doSome(String,Integer))")
    public void myBefore(){
        //就是你切面要执行的功能
        System.out.println("前置通知    ,    切面功能:在目标方法之前输出时间:"+new Date());

    }
}

5.配置文件


    <bean id="someService" class="com.bjpowernode.ba01.SomeServiceImpl"/>


    <bean id="myAspect" class="com.bjpowernode.ba01.Myaspect"/>


    <aop:aspectj-autoproxy/>

6.测试类:

  String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ctx.getBean("someService");
        //通过代理对象执行方法,实现目标方法之行时,增强了功能
        proxy.doSome("lisi
                     
                     
                     
                     ,20);

指定通知方法中的参数:JoinPoint

JoinPoint:业务方法,要加入切片功能的业务方法

作用:可以在通知方法中获取方法之行时的信息 ,例如方法名称,方法的实参

如果你的切面功能中需要用到方法的信息,就加入Joinpoint

这个Joinpoint参数的值是有框架赋予,必须是第一个位置的参数

@Before(value="execution(void *..SomeServiceImpl.doSome(String,Integer))")
    public void myBefore(JoinPoint jp){
        //获取方法的完整定义
        System.out.println("方法的签名(定义) = "+jp.getSignature());
        System.out.println("方法的名称=="+jp.getSignature().getName());
        //获取方法的实参
        Object[]  args  = jp.getArgs();
        for (Object arg : args) {
            System.out.println("参数"+arg);
        }
        //就是你切面要执行的功能
        System.out.println("前置通知    ,    切面功能:在目标方法之前输出时间:"+new Date());
    }

spring集成Mybatis

使用到的技术:ioc

为什么使用ioc:能把mybatis和spring集成在一起,像一个框架,是因为ico能创建对象.可以把mybatis框架中的对象 交给spring统一创建,开发人员从spring中获取对象

开发人员就不用同时面对两个或多个框架了,只需要会spring

复习mybatis使用步骤,对象

  1. 定义dao接口,StudentDao
  2. 定义mapper文件 StudentDao.xml
  3. 定义mybatis的主配置文件 mybatis.xml
  4. 创建dao的代理对象 StudentDao dao = new SqlSession.getMapper(StudentDao.class);

怎么使用dao对象,需要使用getMapper方法.怎么能使用getMapper方法,需要哪些条件

  1. 获取SqlSession对象,需要使用SqlSessionFactory的openSesssion()方法
  2. 创建SqlSessionFactory对象.通过读取mybatis的主配置文件,能创建SqlSessionFactory对象

需要SqlSessionFactory对象,使用Factory能获取Sqlsession,有了SqlSession就能有dao,目的就是获取dao对象,factory创建需要兑取主配置文件

SqlSessionFactory—>SqlSession—>dao对象

我们会使用独立的连接池类替换mybatis默认自己带的,把连接池也交给spring创建

通过以上的说明,我们需要让spring创建以下对象:

  1. 独立的连接池类的对象,使用阿里的druid连接池
  2. SqlSessionFactory对象
  3. 创建出dao对象

需要学习就是上面三个对象的创建语法,使用xml的bean标签.

步骤

  1. 新建maven项目
  2. 加入maven的依赖
    1).spring依赖
    2).mybatis依赖
    3).mysql驱动
    4).spring的事务依赖
    5).mybatis和spring集成的依赖:mybatis官方提供的,用来在spring项目中创建mybatis
    的SqlSessionFactory,dao对象的
  3. 创建实体类
  4. 创建dao接口和mapper文件
  5. 创建mybatis主配置文件
  6. 创建Service接口和实现类,属性是dao
  7. 创建spring的配置文件:声明mybatis的对象交给spring创建
    1).数据源DateSource
    2).SqlSessionFactory
    3).Dao对象
    4).声明自定义的service
  8. 创建测试类,获取Service对象,通过Service调用dao,来完成数据库的访问

Spring配置文件


    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="myDetaSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">



        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="20"/>

    bean>


    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="myDetaSource"/>

        <property name="configLocation" value="classpath:mybatis.xml"/>
    bean>


    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

        <property name="basePackage" value="com.bjpowernode.dao"/>
    bean>

    <bean id="studentService" class="com.bjpowernode.service.impl.StudentServiceImpl">
        <property name="studentdao" ref="studentDao"/>
    bean>

Mybatis配置文件

 <settings>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>


    <typeAliases>

        <package name="com.bjpowernode.domain"/>
    typeAliases>

    <mappers>

       <package name="com.bjpowernode.dao"/>
    mappers>

spring的事务处理

  1. 什么是事务

    事务是指一组sql语句的集合,集合中有多条sql语句,可能是insert,update等.我们希望这些sql语句执行是一致的,作为一个整体来执行,一起成功或者一起失败.

  2. 在什么时候想到使用事务

    在我的操作,涉及得到多个表,或者是多个sql语句的insert,update,delete.保证这些语句都是成功才能完成饿哦的功能,或者都失败,保证操作时候符合要求的

    在java代码中写程序,控制事务,此时事务应该放在哪里呢?因为业务方法会调用多个dao方法,执行多个sql语句

  3. 通常使用jdbc访问数据库,还是mybatis访问数据库怎么处理事务?

    jdbc访问数据库,处理事务: Connection conn;conn.commit();conn.rollback();

    mybatis访问数据库,处理事务,SqlSession.commit();SqlSession.rollback();

  4. 问题中的事务处理方式,有什么不足?

    1. 不同的数据库访问技术,处理事务的对象,方法不同,需要了解不同数据库访问技术使用事务的原理
    2. 掌握多种数据库中事务的处理逻辑,什么时候提交事务,是么时候回滚事务
    3. 处理事务的多种方法

    总结:多种数据库的访问技术,由不同的事务处理机制,对象,方法

  5. 怎么解决不足

    spring提供了一种处理事务的同一模型,能够使用统一步骤,方式完成多种不同数据库访问技术的事务处理.

    使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理

  6. 处理事务,需要怎么做,做什么

    spring处理事务的模型,使用步骤都是固定的.把事务使用的信息提供给spring就可以了.

    1).事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback.事务管理器是一个接口和他的众多实现类.

    接口:PlatformTransactionManager,定义了事务重要方法commit,rollback

    实现类:spring把每一种数据库访问计数对应的事务处理类都创建好了

    mybatis访问数据库-------spring创建好的是DatSourceTransctionManager

    怎么使用:你需要告诉spring 你用的是哪种数据库的访问技术,怎么告诉spring呢?

    声明数据库访问技术对应的事务管理器实现类.,在spring的配置文件中声明就可以了

    例如:mybatis访问数据库,在xml配置文件中

    2).你的业务方法需要什么样的事务,说明需要的事务的类型

    说明方法需要的事务:

    • 事务的隔离级别(四级)

    • 事务的超时事件:表示一个方法的最长执行时间,如果方法执行时超过了时间,事务就回滚 单位是秒(一般不设置)

    • 事务的传播行为:控制业务方法是不是有事务的,是什么样的事务的

      7个传播行为,表示你的业务方法调用时,事务在方法之间是如何使用的

spring事务处理

Spring框架从入门到精通(纯干货,建议收藏)_第2张图片

PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS
以上三个需要掌握的

PROPAGATION_MANDATORY
PROPAGATION_NESTED
PROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED

PROPAGATION_REQUIRED

指定的方法必须在事务内执行,若当前存在事务,就加入到当前事务中,若当前没有则新建事务

PROPAGATION_SUPPORTS

指定的方法支持当前事务,但若当前没有事务,也可以以非事务的方式执行

PROPAGATION_REQUIRES_NEW

总是新建一个事务,若是当前存在事务,就将当前事务挂起,直到新事务执行完毕

spring提交事务,回滚事务的时机

  1. 当你的业务方法执行成功,没有异常抛出,当方法执行完毕,spring在方法后执行提交事务

  2. 当你的业务方法抛出运行时异常,spring执行回滚,调用事务管理器的rollback

    运行时异常的定义:RuntimeException,和他的子类都是运行时异常.

  3. 当你的业务方法抛出非运行时异常,主要是受查时异常ERROR时,提交事务

    受查异常:在你写的代码中,必须处理的异常.例如IOException,SqlException

总结spring的事务:

  1. 管理事务的是 事务管理和他的实现类

  2. spring的事务是一个统一模型

    1. 指定要使用的事务管理器实现类,使用
    2. 指定哪些类,哪些方法需要加入事务的功能
    3. 制定方法需要的隔离级别,传播行为,超时

    你需要告诉spring,你的项目中类的信息,方法的名称,方法的事务传播行为

spring框架中提供的事务处理方案

  1. 适合中小项目使用的,注解方案

    spring框架自己用aop实现给业务方案增加事务的功能,使用@Transactional注解增加事务.

    @Transactional是spring框架自己注解放在public方法的上面,表示当前方法具有事务.可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

    使用@Transactional的步骤:

    • 需要声明事务管理器对象

    • 开启事务注解驱动,告诉spring框架,我要是用注解的方式管理事务.spring使用aop机制,创建@Transacational所在的类代理对象,给方法加入事务的功能

      spring给业务方法加入事务:

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

      里面机制
      @Around("你要增加的事务功能的业务方法名称")
      Object myAround(){
         开启事务,spring给你开启
         try{
         buy(1001,10);
         spring的事务管理.commit();
         }catch(Exception e){
          spring的事务管理.roolback();
         }
      }
      
    • 在你的方法上面加入@Trancational

        /**
           * rollbackFor:表示发生指定的异常一定回滚
           *1).处理逻辑是:spring框架会首先检查方法跑出的异常是不是在rollbackFor的属性值中
           *  处理异常在rollbackFor列表中,不管是什么类型的异常,一定回滚
           *2).如果你抛出的异常不在rollbackFor列表中,spring会判断异常是不是RuntimeException,
           * 如果是一定回滚.
           */
      //    @Transactional(
      //            propagation = Propagation.REQUIRED,
      //            isolation = Isolation.DEFAULT,
      //            readOnly = false,
      //            rollbackFor = {
      //                    NullPointerException.class,
      //                    NotEnoughException.class
      //            }
      //    )
          @Transactional   //不写东西也行,默认就是上面的四个
          @Override
          public void buy(Integer goodsId, Integer nums) {
      
  2. 适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中,声明类,方法需要的事务.这种方法业务方法和事务,这种方式业务方法和事务配置完全分离.

    实现步骤:都是在xml配置文件中实现的

    • 要使用的是aspectj框架,需要加入依赖

    • 声明事务管理器对象

    • 声明方法需要的事务类型(配置方法的事务属性[隔离级别,传播行为,超时])

    • 配置aop:指定哪些类要创建代理

    配置文件

    
        <context:property-placeholder location="classpath:jdbc.properties"/>
    
        <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
    
    
    
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
            <property name="maxActive" value="20"/>
    
        bean>
    
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    
            <property name="dataSource" ref="myDataSource"/>
    
            <property name="configLocation" value="classpath:mybatis.xml"/>
        bean>
    
    
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    
            <property name="basePackage" value="com.bjpowernode.dao"/>
        bean>
    
         <bean id ="buyService" class="com.bjpowernode.service.impl.BuyGoodsServiceImpl">
             <property name="goodsdao" ref="goodsDao"/>
             <property name="saledao" ref="saleDao"/>
         bean>
    
    
           <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
               <property name="dataSource" ref="myDataSource"/>
           bean>
    
        <tx:advice id="myAdvice" transaction-manager="transactionManager">
    
             <tx:attributes>
    
                 <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
                     rollback-for="java.lang.NullPointerException,com.bjpowernode.excep.NotEnoughException"/>
    
                 <tx:method name="remove*" propagation="SUPPORTS" read-only="true"/>
             tx:attributes>
        tx:advice>
    
    
        <aop:config>
    
            <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
            
            <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt"/>
        aop:config>
    
    

web项目中怎么使用spring

  1. 做的是javase项目有main方法的,执行代码是执行main方法的

    在main里面创建的容器对象

    ApplicationContxt ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);

  2. web项目是tomcat服务器上运行的.tomcat已启动,项目一直运行.

需求:web项目中容器的对象只需要创建一次,把容器对象放入到全局作用于ServletContext中

怎么实现?

使用监听器 当全局作用域对象被创建时 创建容器 存入ServletContext

监听器作用:

  1. 创建容器对象,执行ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);
  2. 把容器对象放入到ServletContext,servletContext.setAttribute(key,ctx)

监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener

使用方法:

  1. 配置maven依赖

    
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-webartifactId>
                <version>5.2.5.RELEASEversion>
            dependency>
    
  2. web.xml配置监听器

    
        
        <context-param>
            <param-name>contextConfigLocationparam-name>
    
            <param-value>classpath:spring.xmlparam-value>
        context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderlistener-class>
        listener>
    
  3. 在servlet中使用

        //创建spring的容器对象
    //        String config = "spring.xml";
    //        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
    
            WebApplicationContext ctx = null;
    //        //获取ServletContext中的容器对象,创建好的容器对象,拿来就能用
    //        System.out.println("容器对象的信息========="+ctx);
    //        String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;//key值
    //        Object attr = getServletContext().getAttribute(key);
    //        if(attr!=null){
    //            ctx = (WebApplicationContext)attr;
    //        }
    
            //使用框架中的一个方法,获取容器对象
            ServletContext sc = getServletContext();
            ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
            //上面这两行一定要记住
    
            //获取Service
            StudentService service = (StudentService) ctx.getBean("studentService");
            Student stu = new Student(Integer.valueOf(strid),strName,strEmail,Integer.valueOf(strAge));
            service.addStudent(stu);
            request.getRequestDispatcher("/result.jsp").forward(request,response);
    

    使用工具类调用的的方式一定要记住

    org.springframework.web.context.ContextLoader ```
  4. 在servlet中使用

        //创建spring的容器对象
    //        String config = "spring.xml";
    //        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
    
            WebApplicationContext ctx = null;
    //        //获取ServletContext中的容器对象,创建好的容器对象,拿来就能用
    //        System.out.println("容器对象的信息========="+ctx);
    //        String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;//key值
    //        Object attr = getServletContext().getAttribute(key);
    //        if(attr!=null){
    //            ctx = (WebApplicationContext)attr;
    //        }
    
            //使用框架中的一个方法,获取容器对象
            ServletContext sc = getServletContext();
            ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
            //上面这两行一定要记住
    
            //获取Service
            StudentService service = (StudentService) ctx.getBean("studentService");
            Student stu = new Student(Integer.valueOf(strid),strName,strEmail,Integer.valueOf(strAge));
            service.addStudent(stu);
            request.getRequestDispatcher("/result.jsp").forward(request,response);
    

    使用工具类调用的的方式一定要记住

思维导图(建议保存下来回顾)Spring框架从入门到精通(纯干货,建议收藏)_第3张图片

你可能感兴趣的:(Java,数据库,spring,java,mybatis)