Spring教程

2 篇文章 0 订阅

Spring

spring的第一个核心功能 ioc

IoC (Inversion of Control) : 控制反转, 是一个理论,概念,思想。
描述的:把对象的创建,赋值,管理工作都交给代码之外的容器实现, 也就是对象的创建是有其它外部资源完成。

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

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

   public static void main(String args[]){
            Student student = new Student(); // 在代码中, 创建对象。--正转。
}

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

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

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

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

ioc的体现:

  servlet  1: 创建类继承HttpServelt 
	       2:  在web.xml 注册servlet , 使用<servlet-name> myservlet  </servlet-name>
<servelt-class>com.bjpwernode.controller.MyServlet1</servlet-class>
           3. 没有创建 Servlet对象, 没有 MyServlet myservlet = new      MyServlet()

		   4. Servlet 是Tomcat服务器它能你创建的。 Tomcat也称为容器
			   Tomcat作为容器:里面存放的有Servlet对象, Listener , Filter对象

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

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

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

实现步骤

  1. 创建maven项目
  2. 加入maven的依赖 spring的依赖,junit依赖
  3. 创建类(接口和他的实现类)和没有使用框架一样,就是普通的类。
  4. 创建spring需要使用的配置文件,声明类的信息,这些类由spring创建和管理
  5. 测试spring创建的对象。
<properties>
        <project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
<!--spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.9</version>
    </dependency>

基于注解的DI

设值注入
<bean id="mystudent" class="com.ysh.pojo.Student">
        <property name="name" value="张曼玉"/>
        <property name="age" value="22"/> //执行setAge方法,参数值是22
        <property name="school" ref="myschool"/>
 </bean>
<bean id="myschool" class="com.ysh.pojo.School">
    <property name="name" value="Gongxueyuan"/>
    <property name="address" value="神火大道"/>
</bean>
 @Test
    public  void NewStudentTest(){
        String config="beans.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);
        Student mystudent = (Student) ac.getBean("mystudent");
        System.out.println(mystudent);
    }
构造注入

spring调用类有参构造方法,在创建对象的同时,在构造方法中给属性赋值

构造注入使用< constructor-arg > 标签

name:表示构造方法的形参名

index:表示构造方法的参数的位置,参数从左往右是 0,1,2 的顺序

value:构造方法的形参类型是简单类型,使用value

ref: 构造方法的形参类型是引用类型的,使用ref

<!--使用name属性实现构造注入-->
    <bean id="mystudent" class="com.ysh.pojo.Student">
        <constructor-arg name="name" value="张三"/> //name值是形参
        <constructor-arg name="age" value="20"/>
        <constructor-arg name="myschool" ref="myschool"/>//这里的myschool是实例化后的对象 是school类的bean的id值
    </bean>
<!--使用index属性-->
    <bean id="mystudent2" class="com.ysh.pojo.Student">
        <constructor-arg index="0" value="张三"/>
        <constructor-arg index="1" value="20"/>
         <constructor-arg index="2" ref="myschool"/>
    </bean> //可以省略index只写value 默认0,1,.. t

自动注入ByName

byType 方式自动注入

​ 当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用 byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean 类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CNGyisPB-1632043710637)(https://i.loli.net/2021/09/12/fosFPYS8lDwEe6N.png)]

byType 方式自动注入

​ 使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类, 要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子 类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配 哪一个了。

image-20210912151312504

配置文件包含

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

如果你的项目有多个模块(相关的功能在一起) ,一个模块一个配置文件。
学生考勤模块一个配置文件, 张三
学生成绩一个配置文件, 李四

多文件的分配方式:

  1. 按功能模块,一个模块一个配置文件
  2. 按类的功能,数据库相关的配置一个文件配置文件, 做事务的功能一个配置文件, 做service功能的一个配置文件等
    3. 使用通配符时候主配置文件不能含在统配符的范围内

image-20210912153238579

基于注解的DI

使用注解的步骤:
1.加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring- aop的依赖。 使用注解必须使用spring-aop依赖
2.在类中加入spring的注解(多个不同功能的注解)

3.在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置

实现步骤

  1. 加入依赖
  2. 创建类,在类中加入注解
  3. 创建spring的配置文件,声明组件扫描器的标签,指明注解在你的项目中的位置。
  4. 使用注解创建对象,创建容器ApplicationContext
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
/*
* @Component:创建对象的,等同于<bean>的功能
*      属性:value 就是对象的名称,也就是bean的id值
*           value 的值是唯一的,创建的对象在整个spring容器中就一个
*      位置:在类的上面
* @Component(value = "mystudent")等同于
* <bean id="mystudent" class="com.ysh.Dome1.Student>
* */
//不指定对象名称,由spring提供默认名称:类名的首字母小写
//最常用方法省略value @Component("mystudent")
@Component(value = "mystudent")
public class Student {
    private String name;
    private Integer age;
}
组件扫描器
 <!--声明组件扫描器
        bae-package:指定注解在你项目中的包名。
        component-scan工作方式:spring会扫描遍历base-package指定的包
          把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值
    -->
    <context:component-scan base-package="com.ysh.Dome1"/>

spring中和@Component功能一致,创建对象的注解还有:

  1. @Repository (用在持久层类的上面):放在 dao的实现类上面,表示创建的dao对象,dao对象是能访问数据库的。
  2. @Service (用在业务类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务功能的。
  3. @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象能够接受 用户提交的参数,显示请求的处理结果。

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

@Repository @Service @Controller是给项目对象分层的。

简单类型的属性赋值
@Data
@AllArgsConstructor
@NoArgsConstructor
/*
* @Value:简单类型的属性赋值
*    属性:value 是String类型的,表示简单类型的属性值
*    位置:1.在属性定义的上面,无需set方法,推荐使用。
*         2.在set方法的上面*/
@Component("mystudent")
public class Student {
    @Value("张飞")
    private String name;
    @Value("25")
    private Integer age;
}
引用类型赋值

@Autowired

@Data
@AllArgsConstructor
@NoArgsConstructor
/*
* @Value:简单类型的属性赋值
*    属性:value 是String类型的,表示简单类型的属性值
*    位置:1.在属性定义的上面,无需set方法,推荐使用。
*         2.在set方法的上面*/
/*
* 引用类型
* @Autowired:spring框架提供的注解,实现引用类型的赋值
* spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
* @Autowired:默认使用的是byType自动注入
* */
@Component("mystudent")
public class Student {
    @Value("张飞")
    private String name;
    @Value("25")
    private Integer age;
    @Autowired
    private School school;
}

/*
* 如果要使用byName方式,需要做的是:
* 1.在属性上面加入@Autowired
* 2.在属性上面加入@Qualifier(value="bean的id)表示指定名称的bean*/
@Component("mystudent")
public class Student {
    @Value("张飞")
    private String name;
    @Value("25")
    private Integer age;
    @Autowired
    @Qualifier("myschool")
    private School school;
}

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

​ true表示引用类型赋值失败,程序报错,并终止执行

​ false:引用类型赋值失败,程序正常运行,引用类型为空

    @Autowired(required=false)
    @Qualifier("myschool")
    private School school;

image-20210913085616146

Aop

1.动态代理
实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
jdk动态代理要求目标类必须实现接口

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

2.动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能。
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离。

3.Aop:面向切面编程, 基于动态代理的,可以使用jdk,cglib两种代理方式。
Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了,
让开发人员用一种统一的方式,使用动态代理。

  1. AOP(Aspect Orient Programming)面向切面编程
    Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。
    切面的特点: 一般都是非业务方法,独立使用的。
    Orient:面向, 对着。
    Programming:编程

oop: 面向对象编程

怎么理解面向切面编程 ?
1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能

术语:
1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,
常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。

2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
5)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.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。

Aop实现步骤

使用aspectj实现aop的基本步骤:
1.新建maven项目
2.加入依赖
1)spring依赖
2)aspectj依赖
3)junit单元测试

     <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.9</version>
     </dependency>

3.创建目标类:接口和他的实现类。
要做的是给类中的方法增加功能

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

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

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

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

5.创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解或者xml配置文件< bean>
1)声明目标对象
2)声明切面类对象
3)声明aspectj框架中的自动代理生成器标签。
自动代理生成器:用来完成代理对象的自动创建功能的。

  <!--把对象交给spring容器,由spring容器统一创建,管理对象-->
    <!--声明目标对象-->
    <bean id="someService" class="com.ysh.ba01.SomeServiceImpl" />

    <!--声明切面类对象-->
    <bean id="myAspect" class="com.ysh.ba01.MyAspect" />

    <!--声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象。
        创建代理对象是在内存中实现的, 修改目标对象的内存中的结构。 创建为代理对象
        所以目标对象就是被修改后的代理对象.

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象。
    -->
    <!--<aop:aspectj-autoproxy />-->


    <!--
       如果你期望目标类有接口,使用cglib代理
       proxy-target-class="true":告诉框架,要使用cglib动态代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

6.创建测试类,从spring容器中获取目标对象(实际就是代理对象)。
通过代理执行方法,实现aop的功能增强。

@Test
    public void test(){
        String config="applicationContext.xml";
        ApplicationContext ctx=new ClassPathXmlApplicationContext(config); //切面表达式
        //从容器中获取目标对象
        SomeService proxy=(SomeService) ctx.getBean("someService");
        //通过代理对象执行方法
        proxy.doSome("lisi", 23);
    }
JoinPoint
 /**
     * 指定通知方法中的参数 : 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("2=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }

执行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QWhWb2DP-1632043710644)(https://i.loli.net/2021/09/13/JvEMmfFZ7ksDjKB.png)]

@AfterReturning :后置通知
/**
     * 定义方法,方法是实现切面功能的。
     * 方法的定义要求:
     *  1.公共方法 public
     *  2.方法没有返回值
     *  3.方法名称自定义
     *  4,方法有参数
     *     推荐是Object,参数名自定义
     */
    /**
     * @AfterReturning :后置通知
     *   属性:1.value 切入点表达式
     *        2,returning 自定义的变量,表示目标方法的返回值。
     *   位置:在方法定义的上面
     * 特点:
     *    1.在目标方法之后执行的。
     *    2,能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
     *    Object res=doOther()
     *    3.可以修改这个返回值
     */
    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")
    public void myBefore2(Object res){

        //res:是目标方法的返回值
        System.out.println("=====后置通知, 切面功能:在目标方法之后"+res);
    }
}
@Around:环绕通知
 /**
     * 环绕通知方法的定义格式
     *  1.public
     *  2.必须要有一个返回值,推荐使用Object
     *  3.方法名称自定义
     *  4,方法有参数,固定的参数ProceedingJoinPoint
     */
    /**
     * @Around:环绕通知
     *   属性:value 切入点表达式
     *   位置:在方法的定义什么
     * 特点:
     *   1.它是功能最强的通知
     *   2.在目标方法的前和后都能增强功能
     *   3.控制方法是否被调用执行
     *   4,修改原来的目标方法的执行结果。影响最后的调用结果
     *
     *   环绕通知,等同于jdk动态代理的,InvocationHandler接口
     *
     *   参数:ProceedingJoinpoint 就等同于 Method
     *        作用:执行目标方法的
     *
     * @param pij
     * @return 返回值:就是目标方法的执行结果,可以被修改
     */
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pji) throws Throwable {
        //实现环绕通知
        Object result=null;
        System.out.println("环绕通知在目标方法之前,输出时间:" +new Date());
        //1.目标方法调用
        result=pji.proceed();//等同于method.incoke(); Object result=doFirst()
        System.out.println("环绕通知在目标方法之后,输出时间:" +new Date());

        return result;
    }

如果你希望目标类接口,使用cglib代理 在主配置文件加入

<aop:aspectj-autoproxy proxy-target-class="true"/>

Spring 整合MyBatis

把mybatis和spring集成在一起,像一个框架一样使用。用的技术是:ioc

可以把mybatis框架中的对象交给spring统一创建,开发人员从spring中获取对象

通过以上的说明,我们需要让spring创建以下对象
1.独立的连接池类的对象, 使用阿里的druid连接池
2.SqlSessionFactory对象
3.创建出dao对象

步骤:

1.新建maven项目
2.加入maven的依赖
1)spring依赖
2)mybatis依赖
3)mysql驱动
4)spring的事务的依赖
5)mybatis和spring集成的依赖: mybatis官方体用的,用来在spring项目中创建mybatis
的SqlSesissonFactory,dao对象的

 <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.9</version>
    </dependency>
    <!--spring做事务的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.3.9</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.3.9</version>
    </dependency>
    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.7</version>
    </dependency>
    <!--mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.6</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
    </dependency>
    <!--阿里巴巴数据库连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.6</version>
    </dependency>
  </dependencies>
  <build>
  <resources>
  <resource>
    <directory>src/main/java</directory><!--所在的目录-->
    <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
      <include>**/*.properties</include>
      <include>**/*.xml</include>
    </includes>
    <filtering>false</filtering>
  </resource>
  </resources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

3.创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    //属性名和列名一样
    private Integer id;
    private String name;
    private String email;
    private Integer age;
}

4.创建dao接口和mapper文件

public interface StudentDao {
    int insertStudent(Student student);
    List <Student> selectStudent();
}
 <insert id="insertStudent">
        insert into student values (#{id},#{name},#{email},#{age})
    </insert>
    <select id="selectStudent" resultType="com.ysn.dao.StudentDao">
        select id,name,email,age from student order by id desc 
    </select>

5.创建mybatis主配置文件

  <!--settings:控制日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
   <!--设置别名-->
    <typeAliases>
        <!--实体类所在的包名-->
        <package name="com.ysh.daomain"/>
    </typeAliases>
    <!--sql mapper (sql映射文件)的位置-->
    <mappers>
        <!--
            一个mapper标签指定一个文件的位置
            从类路径开始的路径信息,target/clasess(类路径)
         -->
        <!--<mapper resource="com/ysh/dao/StudentDao.xml"/>-->
        <!--name:是包名 ,这个包中所有的mapper.xml一次都能加载-->
        <package name="com.ysh.dao"/>
    </mappers>

6.创建Service接口和实现类,属性是dao。

public interface StudentService {
    int addStudent (Student student);
    List<Student> queryStudent();
}
    //引用类型
    private StudentDao studentDao;

    //使用set注入,赋值
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    @Override
    public int addStudent(Student student) {
        int nums=studentDao.insertStudent(student);
        return nums;
    }

    @Override
    public List<Student> queryStudent() {
        List <Student> students=studentDao.selectStudent();
        return students;
    }

7.创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源DataSource

    <!--声明数据源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/ssm"/>
        <property name="username" value="root"/>
        <property name="password" value="ysh"/>
        <property name="maxActive" value="20" />
    </bean>

2)SqlSessionFactory

  <!--声明的是mybatis中提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory的
       SqlSessionFactory  sqlSessionFactory = new ..
   -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set注入,把数据库连接池付给了dataSource属性-->
        <property name="dataSource" ref="myDataSource" />
        <!--mybatis主配置文件的位置
           configLocation属性是Resource类型,读取配置文件
           它的赋值,使用value,指定文件的路径,使用classpath:表示文件的位置
        -->
        <property name="configLocation" value="classpath:mybatis.xml" />
    </bean>
  1. Dao对象
<!--创建dao对象,使用SqlSession的getMapper(StudentDao.classMapperScannerConfigurer:在内部调用getMapper()生成每个dao接口的代理对象。
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <!--指定包名, 包名是dao接口所在的包名。
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行
            一次getMapper()方法,得到每个接口的dao对象。
            创建好的dao对象放入到spring的容器中的。 dao对象的默认名称是 接口名首字母小写
        -->
        <property name="basePackage" value="com.ysh.dao"/>
    </bean>
  1. 4)声明自定义的service

    <!--声明service-->
    <bean id="studentService" class="com.ysh.service.impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao" />
    </bean>

8.创建测试类,获取Service对象,通过service调用dao完成数据库的访问

 @Test
    public void testServiceInsert(){

        String config="applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //获取spring容器中的dao对象
        StudentService service = (StudentService) ctx.getBean("studentService");
        Student student  = new Student();
        student.setId(1015);
        student.setName("李胜利");
        student.setEmail("zhoufeng@qq.com");
        student.setAge(26);
        int nums = service.addStudent(student);
        //spring和mybatis整合在一起使用,事务是自动提交的。 无需执行SqlSession.commit();
        System.out.println("nums="+nums);
    }

Spring事务的处理

电商购买商品演示事务的处理

1.创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Sale {         //商品的销售订单
    private Integer id;
    private Integer gid;
    private Integer nums;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods  {     //商品表
    private Integer id;
    private String name;
    private Integer amount;
    private Float price;
}

2.创建dao和mybatis映射文件

商品

public interface GoodsDao {
    //更新库存
    //goods表示本次用户购买的商品信息,id,购买数量
    int updateGoods(Goods goods);

    //查询商品的信息
    Goods selectGoods(Integer id);
}

    <select id="selectGoods" resultType="com.ysh.domain.Goods">
        select id,name,amount,price from goods where id=#{gid}
    </select>

    <update id="updateGoods">
        update set amount =amount-#{amount} where id={id}
    </update>

订单

public interface SaleDao {
    //增加销售记录
    int insertSale(Sale sale);
}
<insert id="insertSale">
        insert into sale(gid,nums) values (#{gid},#{nums})
    </insert>

配置文件和上面基本一致

测试方法

 @Test
    public void test01(){
        String config="applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器获取service
         BuyGoodService service = (BuyGoodService) ctx.getBean("buyService");

        //调用方法
        service.buy(1001,10);
    }

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

1.首先我们要在spring配置文件中声明事务的处理

 <!--使用spring的事务处理-->
    <!--1.声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--连接的数据库,指定数据源-->
        <property name="dataSource" ref="myDataSource"/>
    </bean>
    <!--2.开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象transaction-manager:事务管理器对象的id-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

执行事务的方法

 @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {NullPointerException.class,NotEnoughException.class}
    )
    @Override
    public void buy(Integer goodsId, Integer nums) {
大型项目的事务

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

实现步骤: 都是在xml配置文件中实现。
1)要使用的是aspectj框架,需要加入依赖

<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-aspects</artifactId>
		<version>5.2.5.RELEASE</version>
	</dependency>

2)声明事务管理器对象

<bean id="xx" class="DataSourceTransactionManager">
  1. 声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
  <!--使用spring的事务处理-->
    <!--1.声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--连接的数据库,指定数据源-->
        <property name="dataSource" ref="myDataSource"/>
    </bean>
  
    <!--2.声明业务方法它的事务属性(隔离级别,传播行为,超时时间
          id:自定义名称,表示<tx:advice> 和 </tx:advice>之间的配置内容的
          transaction-manager:事务管理器对象的id
    -->
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <!--tx:attributes:配置事务属性-->
        <tx:attributes>
            <!--tx:method:给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
                name:方法名称,1)完整的方法名称,不带有包和类。
                              2)方法可以使用通配符,* 表示任意字符
                propagation:传播行为,枚举值
                isolation:隔离级别
                rollback-for:你指定的异常类名,全限定类名。 发生异常一定回滚
            -->
            <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
                       rollback-for="java.lang.NullPointerException,com.ysh.excep.NotEnoughException"/>

            <!--使用通配符,指定很多的方法-->
            <tx:method name="add*" propagation="REQUIRES_NEW" />
            <!--指定修改方法-->
            <tx:method name="modify*" />
            <!--删除方法-->
            <tx:method name="remove*" />
            <!--查询方法,query,search,find-->
            <tx:method name="*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>

4.配置aop:指定哪些哪类要创建代理。

<!--配置aop-->
    <aop:config>
        <!--配置切入点表达式:指定哪些包中类,要使用事务
            id:切入点表达式的名称,唯一值
            expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象

            com.bjpowernode.service
            com.crm.service
            com.service
        -->
        <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>

        <!--配置增强器:关联adivce和pointcut
           advice-ref:通知,上面tx:advice哪里的配置
           pointcut-ref:切入点表达式的id
        -->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt" />
    </aop:config>

Web项目中使用容器对象

和上面的项目基本一样就是利用监听器来创建spring容器

添加依赖

 <!--为了使用监听器对象,加入依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.3.9</version>
 <!--注册监听器ContextLoaderListener
      监听器被创建对象后,会读取/WEB-INF/spring.xml
      为什么要读取文件:因为在监听器中要创建ApplicationContext对象,需要加载配置文件。
      /WEB-INF/applicationContext.xml就是监听器默认读取的spring配置文件路径

      可以修改默认的文件位置,使用context-param重新指定文件的位置


      配置监听器:目的是创建容器对象,创建了容器对象, 就能把spring.xml配置文件中的所有对象都创建好。
      用户发起请求就可以直接使用对象了。
  -->
    <context-param>
        <!-- contextConfigLocation:表示配置文件的路径  -->
        <param-name>contextConfigLocation</param-name>
        <!--自定义配置文件的路径-->
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

image-20210916150041647

@Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("utf8");
        System.out.println("开始执行");
        String strId=request.getParameter("id");
        String strName=request.getParameter("name");
        String strEmail=request.getParameter("email");
        String strAge=request.getParameter("age");

        //创建spring容器对象
        //String config ="applicationContext.xml";
        //ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

        WebApplicationContext ctx=null;
        ServletContext sc=getServletContext();
        ctx=WebApplicationContextUtils.getWebApplicationContext(sc);


        //获取service
        StudentService studentService = (StudentService) ctx.getBean("studentService");
        Student student=new Student(Integer.parseInt(strId),strName,strEmail,Integer.parseInt(strAge));
        studentService.addStudent(student);

        //  给一个页面
        request.getRequestDispatcher("/result.jsp").forward(request,response);
    }
@Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("utf8");
        System.out.println("开始执行");
        String strId=request.getParameter("id");
        String strName=request.getParameter("name");
        String strEmail=request.getParameter("email");
        String strAge=request.getParameter("age");

        //创建spring容器对象
        //String config ="applicationContext.xml";
        //ApplicationContext ctx = new ClassPathXmlApplicationContext(config);

        WebApplicationContext ctx=null;
        ServletContext sc=getServletContext();
        ctx=WebApplicationContextUtils.getWebApplicationContext(sc);


        //获取service
        StudentService studentService = (StudentService) ctx.getBean("studentService");
        Student student=new Student(Integer.parseInt(strId),strName,strEmail,Integer.parseInt(strAge));
        studentService.addStudent(student);

        //  给一个页面
        request.getRequestDispatcher("/result.jsp").forward(request,response);
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值