spring基础入门篇

文章目录

一、Spring框架

第一章 Spring框架概述

​ 官网:https://spring.io

1.1 主要作用

​ 1、Spring是轻量级的开源的Java EE框架。

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

1.2 优点

​ 1)轻量。

​ 2)针对接口编程,解耦合。

​ 3)AOP编程的支持。

​ 4)方便集成各种优秀的框架。

1.3 Spring体系结构

在这里插入图片描述

第二章 IOC 控制反转

​ 作用:能够实现业务对象之间的解耦合,例如service和dao对象之间的解耦合。

2.1 入门案例

2.1.1 导入Maven依赖
        <!--        spring依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.14</version>
</dependency>
2.1.2 插件
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
2.1.3 定义接口和实现类
//接口
public interface SomeService {
    void doSome();
}

//实现类
public class SomeServiceImpl implements SomeService {
    public SomeServiceImpl() {
        System.out.println("SomeServiceImpl的无参数构造方法!");
    }
    
    @Override
    public void doSome() {
        System.out.println("执行了SomeServiceImpl的doSome()方法");
    }
}
2.1.4 创建spring配置文件

​ 在src/main/resources/目录下创建一个xml文件,文件名建议为applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
        告诉spring创建对象
        声明bean,就是告诉spring要创建某个类的对象
        id:对象的自定义名称,唯一值。spring通过这个名称找到对象
        class:类的全限定名称。(不能是接口,因为spring是反射机制创建对象,必须使用类)
        spring就完成  SomeService someService = new SomeServiceImpl();
        spring是把创建好的对象放入到Map中,spring框架中有一个map存放对象的。
            springMap.put(id的值,对象)
         例如:
             springMap.put("someService", new SomeServiceImpl());
        一个bean标签声明一个对象。
    -->
    <bean id="someService" class="com.service.impl.SomeServiceImpl"/>
    <bean id="someService1" class="com.service.impl.SomeServiceImpl"/>
    <!--
        spring 能创建一个非自定义类的对象吗,创建一个存在的某个类的对象。
    -->
    <bean id="myDate" class="java.util.Date"/>
</beans>
        <!--
            spring的配置文件
            1、beans:是根标签,spring吧Java对象成为bean
            2、spring-beans.xsd 是约束文件,和mybatis指定,dtd是一样的。
        -->
2.1.5 定义测试类
public class SomeServiceImplTest {

    /**
     * spring 默认创建对象的时间:在创建spring的容器的时,会创建配置文件中的所有的对象。
     * spring 创建对象:默认调用的是无参数构造方法
     */
    @Test
    public void doSome() {
//        1、指定spring配置文件的名称。
        String config = "beans.xml";
//        2、创建表示spring容器的对象,ApplicationContext
//        ApplicationContext表示spring容器,通过容器获取对象
//        ClassPathXmlApplicationContext从类路径中去加载spring的配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
//        3、从容器中获取某个对象,你要调用对象方法
//          getBean("配置文件中的id属性的值")
        SomeService someService = (SomeService) context.getBean("someService");
//        4、使用spring创建好的对象。
        someService.doSome();
    }
}

2.2 容器接口 和 实现类

2.2.1 ApplicationContext 接口 (容器)

ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现类有两个。

​ 1)ClassPathXmlApplicationContext实现类

​ ---------->用于类路径

​ 若Spring配置文件存放在项目的类路径下,则使用ClassPathXmlApplicationContext实现类加载。

ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。 以后代码中若要使用到这些对 象,只需从内存中直接获取即可。执行效率较高。但占用内存

​ 2)FileSystemXmlApplicationContext实现类

​ 针对于磁盘的路径,可以将配置文件放在电脑磁盘的任意一个位置,然后使用FileSystemXmlApplication来获取配置文件信息。

2.3 DI注入

​ DI:依赖注入,表示创建对象,给对象赋值。

​ DI的两种实现:

​ 1)在spring配置文件中,使用标签和属性完成,叫做基于XML的d实现。

​ 2)使用spring中的注解,完成属性赋值,叫做基于注解的DI实现。

​ DI注入分类:

​ 1)set注入(设值注入):spring调用类的set方法,在set方法可以实现属性的赋值

​ 2)构造注入,spring调用类的有参数构造方法,创建对象。在构造方法中完成赋值。

2.3.1 set注入(配置文件)
2.3.1.1 简单类型的注入

语法:

<bean id = "xx" class = "yy">
    
	<property name = "属性名字" value = "此属性的值"/>
    
    <!-- 一个property只能给一个属性赋值 -->
</bean>

示例:

<bean id="myStudent" class="com.Ioc_DI.domain.Student">
        <property name="name" value="李四"/>
        <property name="age" value="20"/>
 </bean>
2.3.1.2 引用类型的set注入

语法格式:

<!--引用类型的注入-->
<bean id="xxx" class="com.Ioc_DI.domain.Student">
    <property name="属性名称" ref="bean的id(对象名称)"
</bean>

示例:

    <bean id="myStudent" class="com.Ioc_DI.domain.Student">
        <property name="name" value="李四"/>
        <property name="age" value="23"/>
        <!--引用类型的注入-->
        <property name="school" ref="mySchool"/>
    </bean>

    <bean id="mySchool" class="com.Ioc_DI.domain.School">
        <property name="name" value="凤鸣中学"/>
        <property name="address" value="重庆市云阳县凤鸣镇"/>
    </bean>
2.3.2 构造注入

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

构造注入使用 标签。

语法:

标签:一个 表示构造方法一个参数。

标签属性:

​ 1)name:表示构造方法的形参名。

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

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

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

示例:

2.3.2.1 name属性 实现构造注入
    <!--    使用name属性构造注入  -->
    <bean id="myStudentConstructor" class="com.Ioc_DI.domain.Student">
        <constructor-arg name="name" value="Jane"/>
        <constructor-arg name="age" value="18"/>
        <constructor-arg name="school" ref="SchoolConstructor"/>
    </bean>

    <bean id="SchoolConstructor" class="com.Ioc_DI.domain.School">
        <constructor-arg name="name" value="重庆大学"/>
        <constructor-arg name="address" value="重庆市"/>
    </bean>
2.3.2.2 index属性 实现构造注入
    <!--    使用index属性构造注入  -->
    <bean id="myStudentConstructor02" class="com.Ioc_DI.domain.Student">
        <constructor-arg index="0" value="邓进"/>
        <constructor-arg index="1" value="21"/>
        <constructor-arg index="2" ref="mySchoolConstructor02"/>
    </bean>

    <bean id="mySchoolConstructor02" class="com.Ioc_DI.domain.School">
        <constructor-arg index="0" value="广州"/>
        <constructor-arg index="1" value="广州大学"/>
    </bean>

2.4 引用数据类型自动注入

​ 自动注入:spring框架根据某些规则可以给引用类型赋值

​ 使用的规则常用的是:byName,byType。

2.4.1 byName(按名称注入)

​ Java类中引用类型的属性名和spring容器中的(配置文件)<bean>的id名称一样。且数据类型是一致的。这样的容器中的bean,spring能够赋值给引用类型。

​ 语法:

<bean id = "xxx" class = "yyy" autowire = "byName">
	简单类型属性赋值
</bean>

​ 示例:

<!-- 采用自动注入的方式 -->
<bean id="myStudent" class="com.autowire.domain.Student" autowire="byName">
        <property name="name" value="马化腾"/>
        <property name="age" value="47"/>
        
</bean>
<!-- 引用类型School,通过id为上面Studet的属性school,实现按名称自动注入 -->
<bean id="school" class="com.autowire.domain.School">
        <property name="name" value="香港大学"/>
        <property name="address" value="香港"/>
</bean>
2.4.2 byType(按类型注入)

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

​ 什么是同源关系?

​ 1、Java类中引用类型的数据类型bean的class的值一样的。

​ 2、Java类中引用类型的数据类型和bean的class的值父子类关系的。

​ 3、Java类中引用类型的数据类型和bean的class的值接口和实现类关系的。

​ 示例:

    <!--    通过引用类型注入-->
    <bean id="stu" class="com.autowire.domain.Student" autowire="byType">
        <property name="name" value="小风"/>
        <property name="age" value="22"/>
    </bean>

    <bean id="mySchool" class="com.autowire.domain.School">
        <property name="name" value="澳门大学"/>
        <property name="address" value="澳门"/>
    </bean>

注意:

​ 1、在byType中,在xml配置文件中声明bean只能有一个符合条件的,多余一个是错误的。

2.5 多个配置文件的优势

​ 1、每个文件的大小比一个文件要小很多,效率高。

​ 2、避免多人竞争带来的冲突。

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

​ 学生考勤模块一个配置文件,张三。

​ 学生成绩一个配置文件,李四。

​ 多文件的分配方式:

​ 1、按功能模块:一个模块一个配置文件。

​ 2、按类的功能:数据库相关的配置一个文件配置文件,做事务的功能一个配置文件,做service功能的一个配置文件等。

2.6 包含其他配置文件

关键字:"classpath:"表示类路径(class文件所在的目录),在spring的配置文件中要指定其他文件的位置,需要使用classpath,告诉 spring到哪去加载读取配置文件。

语法:

		<import resource = "其他配置文件的路径"/>

示例:

<import resource = "classpath:autowire/autowire.xml"/>

通配符:*

total.xml配置文件

<import reource = "classpath:autowire/spring-student.xml"/>
<import reource = "classpath:autowire/spring-school.xml"/>

<!-- 可以将以上的文件利用通配符一次性加载,抽取公共部分 -->
<import reource = "classpath:autowire/spring-*.xml"/>

spring-student.xml配置文件

<bean id="student" class="com.includeFile.Student" autowire="byType">
    <property name="name" value="小王"/>
    <property name="age" value="20"/>
</bean>

spring-school.xml配置文件

<bean id="school" class="com.includeFile.School">
    <property name="name" value="湖北大学"/>
    <property name="address" value="湖北省"/>
</bean>

2.7 基于注解的DI

​ 通过注解完成Java对象的创建,属性赋值。

2.7.1 使用注解的步骤

​ 1、加入Maven依赖

​ 加入依赖spring-context,在加入spring-context的同时,间接加入spring-aop的依赖。使用注解必须加入spring-aop依赖。

​ 2、在类中加入spring的注解(多个不同功能的注解)

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

​ 4、使用注解创建对象,创建容器ApplicationContext

2.7.2 涉及到使用的注解

​ 1、@Component

​ 2、@Respository

​ 3、@Service

​ 4、Controller

​ 5、@Value

​ 6、@Autowired

​ 7、@Resource

2.7.3 组件扫描器

​ 在resource目录下, 声明组件扫描器(component-scan),组件就是java对象

​ 语法格式:

基于applicationContext.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"
       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">    

<!--
		第一种方式:指定一个包
        base-package:指定注解在你的项目中的包名。
		加入了component-scan标签,配置文件有相应的变化:
			1、加入一个新的约束文件spring-context.xsd
			2、给这个新的约束文件起个命名空间的名称
    -->
    <context:component-scan base-package="com.annotation_DI"/>

<!-- 
	第二种方式:指定多个包
-->
<context:component-scan base-package="com.annotation_DI"/>
<context:component-scan base-package="com.autowire"/>
<context:component-scan base-package="com.Ioc_DI"/>

<!-- 
	指定多个包的第二种方式 
	使用分隔符(;或,)分隔多个包名
-->
<context:component-scan base-package="com.autowire;com.Ioc_DI;com.annotation_DI"/>

<!-- 
	指定多个包的第二种方式 
	使用父包
-->
<context:component-scan base-package="com"/>
    
</beans>

​ 工作方式:

​ spring会扫描遍历base-package指定的包,把包中和子包中所有的类,找到类中的注解,按照注解的功能创建对象,或 给属性赋值。

2.7.4 @Component

​ 含义:

/**
* @Component :创建对象的,等同于<bean>的功能
* 属性:value就是对象的名称,也就是bean的id值。
* Value的值是唯一的,创建的对象在整个spring容器中只有一个。
* 位置:在类的上面
*/
//1、使用value属性,指定对象名称
@Component(value = "myStudent")

//2、等同于,省略value
@Component("myStudent")

//3、不指定对象名称,由spring提供默认名称:类名的首字母小写
@Component

注意

1、以下三个注解的使用语法和@Component一样的。都能创建对象,但是这三个注解都有格外的功能。
2、@Repository、@Service、@Controller是给项目分层的。

2.7.5 @Repository

​ 放在dao的是实现类上面,表示创建dao对象,dao对象是能访问数据库的。用在持久层类的上面。

2.7.6 @Service

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

2.7.7 @Controller

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

2.7.8 @Value
1. 简单类型的属性赋值

​ 属性:value 是String类型的,表示简答数据类型的属性值。

​ 位置:

​ 1、在属性定义的上面,无需set方法,推荐使用。

​ 2、在set方法上面。

在属性上赋值

    @Value(value = "王五")
    private String name;
    
    @Value(value = "23")
    private Integer age;

//value属性可以省略
    @Value("王五")
    private String name;
    
    @Value("23")
    private Integer age;

在set方法上赋值(用的很少)

@Value("30")
public void setAge(Integer age) {
    System.out.println("age = " + age);
    this.age = age;
}
2. 引用类型的属性赋值

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

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

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

​ 属性:required,是一个Boolean类型的,默认为true。

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

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

@Autowired(required = true)
2.1 byType方式

​ 位置:

​ 1、在属性定义的上面,无需set方法,推荐使用。

​ 2、在set方法的上面。

在Student.java中


    @Value("故里")
    private String name;

    @Value("30")
    private Integer age;
    /**
     * 申明一个引用类型
     */
    @Autowired
    private School school;

在School.java中

@Value("北京大学")
private String name;

@Value("北京市")
private String address;

2.2 byName方式

​ 1、在属性上面加入@AutoWired

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

//byName自动注入
	@Autowired
    @Qualifier("mySchool")
    private School school;
2.7.9 @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;

第三章 AOP面向切面编程

3.1 AOP简介

​ AOP(Aspect Orient Programming),面向切面编程。面向切面编是从动态角度考虑程序运行过程。

​ Aspect(切面):切面,给你的目标类增加的功能,就是切面。

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

​ AOP底层,就是采用动态代理模式实现的。可以使用jdk,cglib两种代理的方式。

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

3.1.1 如何理解面向切面编程(*)

​ 1)需要在分析项目功能时,找出切面。

​ 2)合理的安排切面的执行时间(在目标方法前,还是目标方法后)

​ 3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能。

3.1.2 术语

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

​ 2)JoinPoint:连接点,连接 业务方法和切面的位置。就是某类中的业务方法。

​ 3)PointCut:切入点,指多个连接点方法的集合。多个方法。

​ 4)目标对象:给哪个类的方法增加功能,这个类就是目标对象。

​ 5)Advice:通知,通知表示切面功能执行的时间。

3.1.3 三个关键要素

​ 1)切面的功能代码,切面干什么。

​ 2)切面的执行位置,使用PointCut表示切面执行的位置。

​ 3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。

3.2 动态代理

3.2.1 实现方式(*)

​ 1)jdk动态代理,使用jdk中的proxy,Method,InvocationHandler创建代理对象。

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

3.2.2 cglib动态代理(*)

​ 1)第三方的工具库,创建代理对象,原理是继承。通过继承目标类,创建子类。

​ 2)子类就是代理对象。要求目标类不能是final的,方法也不能是final的。

3.2.3 作用(*)

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

​ 2)减少代码的重复。

​ 3)专注业务逻辑代码。

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

3.3 AOP的实现

​ aop是一个规范,是动态的一个规范化,一个标准。

3.3.1 aop的技术实现框架

​ 1)spring:spring在内部实现了aop规范,能做到aop的工作。

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

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

​ 2)aspectJ:一个开源的专门做aop的框架。

​ spring中集成了aspectJ框架,通过spring就能使用aspectJ的功能。

​ 在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。

​ 官网地址:http://www.eclipse.org/aspectj/

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

​ 1)使用xml的配置文件:配置全局事务。

​ 2)使用注解,在项目中要做aop功能,一般都是使用注解,aspectJ有5个注解。

3.4 aspectJ框架的使用

3.4.1 通知类型

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

​ 在aspectJ框架中使用注解表示的:

1)@Before

2)@AfterReturning

3)@Around

4)AfterThrowing

5)@After

也可以使用xml配置文中的标签。

3.4.2 AspectJ 的切入点表达式execution(掌握)

​ 切入点表达式要匹配的对象就是目标方法的方法名。

​ 表达式原型:

execution(modifiers-pattern? ret-type-pattern 
declaring-type-pattern?name-pattern(param-pattern)
 throws-pattern?)
解释:
1、modifiers-pattern] 访问权限类型
2、ret-type-pattern 返回值类型
3、declaring-type-pattern 包名类名
4、name-pattern(param-pattern) 方法名(参数类型和参数个数)
5、throws-pattern 抛出异常类型
6、?表示可选的部分

​ 示例:

1、execution(public * *(..)) 
指定切入点为:任意公共方法。

2、execution(* set*(..)) 
指定切入点为:任何一个以“set”开始的方法。

3、execution(* com.xyz.service.*.*(..)) 
指定切入点为:定义在 service 包里的任意类的任意方法。

4、execution(* com.xyz.service..*.*(..))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。

5、execution(* *..service.*.*(..))
指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点。

3.5 aspectJ实现aop的基本步骤

​ 1、新建maven项目

​ 2、加入依赖

​ 1)spring依赖

​ 2)aspectJ依赖

​ 3)junit单元测试

        <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.14</version>
        </dependency>
<!-- aspectJ框架依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.14</version>
        </dependency>

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

//接口
public interface SomeService {
    /**
     *
     * @param name
     * @param age
     */
    void doSome(String name, Integer age);
}

//实现类
public class SomeServiceImpl implements SomeService {
    @Override
    public void doSome(String name, Integer age) {
        System.out.println("====目标方法doSome()方法执行====");
    }
}

​ 4、创建切面类:普通类

​ 1)在类中定义方法,方法就是切面要执行的功能代码。

​ 2)在方法的上面加入aspectJ中的通知注解,例如@Before

​ 还需要指定切入点表达式execution()。

    @Before(value = "execution(void com.example.SomeServiceImpl.doSome(String,Integer))")
    public void myBefore() {
//        就是你切面要执行的功能代码
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        System.out.println("1====前置通知,切面功能:在目标方法之前输出执行时间:" + sdf.format(new Date()));
    }

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

​ 声明对象你可以使用注解,或者xml配置文件

​ 1)声明目标对象。

​ 2)声明切面类对象。

​ 3)声明aspectJ框架中的自动代理生成器标签。

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


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

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

<!--声明自动代理生成器:使用aspectJ框架内部的功能,创建目标对象的代理对象.
    创建代理对象是在内存中实现的,修改目标对象的内存结构.
    创建为代理对象所以目标对象就是被修改后的代理对象,
    aspectj-autoproxy:会把spring容器中的所有目标对象,一次性生成代理对象.
-->
    <aop:aspectj-autoproxy/>

​ 6、创建测试类,从spring容器中获取目标对象(实际就是代理对象)。

​ 通过代理执行方法,实现aop的功能增强。

    @Test
    public void test01() {
        String config = "example/applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
        SomeService someService = (SomeService) context.getBean("someService");
        someService.doSome("lisi",20);
    }

3.6 通知类型及术语解析

3.6.1 @Before 前置通知

​ 含义:

​ 1、在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参 数。

​ 2、该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、 目标对象等。

​ 3、不光前置通知的方法,可以包含一个 JoinPoint 类型参数,所有的通知方法均可包含该参数。

     * @Before:前置通知注解 属性:value,是切入点表达式,表示切面的功能执行的位置。
     * 位置:在方法的上面。
     * 特点:
     * 1、在目标方法之前先执行的
     * 2、不会改变目标方法的执行结果。
     * 3、不会影响目标方法的执行。

​ 示例:

   @Before(value = "execution(void com.example.SomeServiceImpl.doSome(String,Integer))")
    public void myBefore() {
		//就是你切面要执行的功能代码
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        System.out.println("1====前置通知,切面功能:在目标方法之前输出执行时间:" + sdf.format(new Date()));
    }

3.6.2 JoinPoint 连接点

​ 业务方法,要加入切面功能的业务方法。

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

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

​ 这个JoinPoint参数的值是由框架赋予的,必须是第一个位置参数

    @Before(value = "execution(void *..SomeServiceImpl.do*(..))")
    public void myBefore(JoinPoint jp) {
//        就是你切面要执行的功能代码
        System.out.println(jp.getArgs());
        //获取方法的实参。 
        Object[] args = jp.getArgs();
        for (Object obj:args) {
            System.out.println(obj);
        }
        System.out.println("目标方法名称" + jp.getSignature().getName());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        System.out.println("4====前置通知,切面功能:在目标方法之前输出执行时间:" + sdf.format(new Date()));
    }
}
3.6.3 @AfterReturning 后置通知

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

​ 1)方法定义的要求:

​ 1、公共方法public。

​ 2、方法没有返回值。

​ 3、方法名称自定义。

​ 4、方法有参数,推荐是Object,参数名自定义。

* @AfterReutrning: 后置通知 属性:
* 1、value 切入点表达式
* 2、returning 自定义变量,表示目标方法的返回值的。
* 自定义变量名必须和通知方法的形参名一样。

​ 2)位置:在方法定义的上面。

​ 3)特点:

​ 1、在目标方法之后执行的。

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

​ 3、可以修改返回值。

示例:

	@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther02(..))",
            returning = "obj")
    public void myAfterReturning(Object obj) {
        //Object obj:是目标方法执行后的返回值,根据返回值做你的切面的功能处理。
        ((User) obj).setName("罗翔");
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:" + obj);
    }

// 添加JoinPoint参数,获取目标方法的参数值,JoinPoint只能放到第一个参数的位置。


3.6.4 @Around 环绕通知

​ 经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务。

​ 1)环绕通知方法的定义格式

​ 1、public

​ 2、必须有一个返回值,推荐使用Object。

​ 3、方法名称自定义。

​ 4、方法有参数,固定的参数 ProceedingJoinPoint。

​ 2)属性:value切入点表达式

​ 3)位置:在方法定义的上面

​ 4)特点

​ 1、它是功能最强的通知。

​ 2、在目标方法前和后都能增强功能。

​ 3、控制目标方法是否被调用执行。

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

​ 5)作用:执行目标方法

​ 6)返回值:就是目标方法的执行结果,可以被修改。

3.6.5 @AfterThrowing 异常通知

1)环绕通知方法的定义格式。

​ 1、public

​ 2、没有返回值

​ 3、方法名称自定义。

​ 4、方法有一个Exception参数,如果有是JoinPoint,Exception。

​ 2)属性:

​ 1. value切入点表达式。

​ 2. throwing 自定义变量,表示目标方法抛出的异常对象。变量名必须和方法的参数名一样。

​ 3)特点

​ 1、在目标方法抛出异常时执行的。

​ 2、可以做异常的监控程序,监控目标方法执行时是不是有异常。如果有异常,可以发送邮件,短信通知。

示例:

​ aspect切面类代码

    @AfterThrowing(value = "execution(* *..SomeServiceImpl.doException(..))", throwing = "e")
    public void myAfterThrowing(Exception e) {
        System.out.println("异常通知:方法发生异常时,执行:" + e.getMessage());
//        通过短信或邮件发送给开发人员
    }

接口实现类中,制造异常

    @Override
    public User doException(User user) {
        int i = 1/0;
        System.out.println("执行了doOther02()方法,user=" + user);
        return user;
    }

测试类执行代码

    @Test
    public void doException() {
        String config = "exception/applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
        SomeService proxy = (SomeService) context.getBean("someService");
        proxy.doException(new User("王五","wang"));
    }

异常通知执行原理

try{
	SomeServiceImpl.doException(..);
}catch(Exception e){
	myAfterThrowing(e);
}
3.6.6 @After 最终通知

​ 1)环绕通知方法的定义格式
​ 1、public
​ 2、没有返回值。
​ 3、方法名称自定义。
​ 4、方法没有参数,如果还有就是JoinPoint。

​ 2)属性:value 切入点表达式

​ 3)位置:在方法的上面

​ 4)特点:

​ 1、总会执行

​ 2、在目标方法之后执行。

​ 示例:

​ 切面类Aspect中:

    @After(value = "execution(* com.after.SomeServiceImpl.doAfter(..))")
    public void myAfter() {
        System.out.println("执行最终通知,总是会被执行的代码。");
//        一般是做资源清除工作的
    }

实现类

    @Override
    public User doAfter(User user) {
//        int i = 1/0;
        System.out.println("执行了doOther02()方法,user=" + user);
        return user;
    }

执行原理:

try{
    myAfter();
}catch(Exception e){
    doException();
}finally{
    doAfter();
}
3.6.7 @pointcut 定义切入点

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

​ 2)属性:value 切入点表达式。

​ 3)位置:在自定义的方法上面。

​ 4)特点:

​ 1、当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名。

​ 2、其他通知中,value属性就可以使用这个方法名称,代替切入点表达式了。

​ 示例:

切面类:

@Aspect
public class MyAspect {

    @After(value = "myPointcut()")
    public void myPointcutAfter() {
        System.out.println("执行最终通知,总是会执行的代码!");
//        通过短信或邮件发送给开发人员
    }

    @Before(value = "myPointcut()")
    public void myPointcutBefore() {
        System.out.println("前置通知,在目标方法之前执行");
//        通过短信或邮件发送给开发人员
    }

    @Pointcut(value = "execution(* com.pointcut.SomeServiceImpl.doOther(..))")
    private void myPointcut() {
//        无需代码
    }
}

目标方法的代码

   @Override
    public String doOther(String name, Integer age) {
        System.out.println("目标方法doOther()执行");
        return name;
    }

3.7 有接口也可以使用cglib动态代理

proxy-target-class属性:当为true时,表示使用cglib动态代理创建对象。

不写表示默认为false,也就是使用JDK动态代理创建对象。

<!--
	1、目标类没有接口,使用cglib动态代理,spring框架会自动应用cglib。
	2、如果目标类有接口,默认使用JDK动态代理,如果想要使用cglib动态代理,则设置属性proxy-target-class="true"。

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

第四章 Spring集成MyBatis

4.1 整合原因

​ 将 MyBatis 与 Spring 进行整合,主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以,该整合,只需要将 SqlSessionFactory 的对象生成器 SqlSessionFactoryBean 注 册在 Spring 容器中,再将其注入给 Dao 的实现类即可完成整合。

​ 使用到的技术:IOC。

4.2 为什么IOC能整合MyBatis?

​ 因为IOC能够创建对象,可以把mybatis框架中的对象交给spring统一创建,开发人员从spring中获取对象。开发人员就不用同时面对两个或多个框架了,就面对一个spring。

4.3 实现步骤
4.3.1 新建maven项目
4.3.2 加入maven依赖
<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!--        spring框架-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.14</version>
        </dependency>
        <!--        mybatis框架-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</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>
        <!--        spring整合mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.3</version>
        </dependency>
        <!--        mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <!--        数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.3</version>
        </dependency>

<!-- 插件 -->
 <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>
4.3.3 创建实体类
public class Student {
    private Integer id;
    private String name;
    private String email;
    private Integer age;
...
}
4.3.4 创建Dao接口和mapper文件

​ dao接口

public interface StudentDao {
    /**
     * 添加学生
     *
     * @param student
     * @return
     */
    int insertStudent(Student student);

    /**
     * 查询所有学生信息
     *
     * @return
     */
    List<Student> selectStudent();
}

​ mapper文件

<?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.dao.StudentDao">
    <!-- 使用insert,update,delete,select标签写sql-->
    <insert id="insertStudent">
        insert into student
        values (#{id}, #{name}, #{email}, #{age})
    </insert>
    <select id="selectStudent" resultType="com.domain.Student">
        select id, name, email, age
        from student
        order by id desc;
    </select>
</mapper>
4.3.5 创建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>
    <!--    设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
    <package name="com.domain"/>
    </typeAliases>

    <!--    指定其他mapper文件的位置
            找到其他文件中的sql语句
    -->
    <mappers>
        <!--告诉 mybatis 要执行的 sql 语句的位置,可以有多个mapper文件。
            使用mapper的resource属性指定mapper文件的路径。
            这个路径是从target/classes路径开始的。
            1、resource = “mapper文件的路径,使用 / 分割路径”。
            一个mapper resource 指定一个mapper文件。
        -->
        <package name="com.dao"/>
    </mappers>
</configuration>
4.3.6 创建Service接口和实现类

​ service接口

public interface StudentService {
    /**
     * 添加对象
     *
     * @param student
     * @return
     */
    int addStudent(Student student);

    /**
     * 查询所有的学生信息
     *
     * @return
     */
    List<Student> queryStudents();
}

​ 实现类

public class StudentServiceImpl implements StudentService {
    private StudentDao studentDao;

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

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

    @Override
    public List<Student> queryStudents() {
        return studentDao.selectStudent();
    }
}
4.3.7 创建spring配置文件
 <!--    把数据库中的配置信息,写在一个单独的文件,便于修改数据库的配置内容
            spring知道jdbc.properties文件的位置。
    -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--    声明数据源-->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--        set注入给DruidDataSource提供连接数据库信息-->
        <!--        使用属性配置文件中的数据,语法${key}-->
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
    </bean>

    <!--  (固定写法)  创建SqlSessionFactory,mybatis中提供了创建SqlSessionFactoryBean类,这个类就是创建创建SqlSessionFactory的-->
    <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>

    <!--    创建dao对象,使用SqlSession的getMapper(StudentDao.class)
            MapperScannerConfigurer:在内部调用getMapper()生成每个dao接口的代理对象
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--        指定SqlSessionFactory的对象-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!--  指定包名,包名是dao接口所在的包名
                MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper()方法,得到每个接口的dao对象
                创建好的dao对象是放在spring的容器中。dao对象的默认名称是 接口的首字母小写
        -->
        <property name="basePackage" value="com.dao"/>
    </bean>

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

​ 4.3.8 创建测试类

    @Test
    public void testDaoInsert() {
        String config = "applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
        StudentDao dao = (StudentDao) context.getBean("studentDao");
        int i = dao.insertStudent(new Student(1009, "小马", "horse@qq.com", 12));
        System.out.println(i);
    }

第五章 Spring事务

5.1 事务简介

​ 事务原本是数据库中的概念,在 Dao 层。但一般情况下,需要将事务提升到业务层, 即 Service 层。

​ 这样做是为了能够使用事务的特性来管理具体的业务。

在 Spring 中通常可以通过以下两种方式来实现对事务的管理:

​ (1)使用 Spring 的事务注解管理事务 。

​ (2)使用 AspectJ 的 AOP 配置管理事务。

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

5.2 如何处理事务

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

​ 1)事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback。

​ 事务管理器( PlatformTransactionManager)是一个接口和它的众多的实现类。

​ 接口中定义了事务重要方法 commit,rollback。

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

​ mybatis访问数据库------->spring创建好的是DataSourceTransactionManager

​ Hibernate访问数据库------->spring创建好的是HibernateTransactionManager

​ 2)怎么使用?

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

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

​ 例如:

<!--使用mybatis访问数据库,你要在xml的配置文件中声明事务管理器-->
<bean id = "xxx" class = "..DataSourceTransactionManager"/>

5.3 事务类型

​ 1、事务类型

​ 这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。

​ 1) DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle 默认为 READ_COMMITTED。

​ 2) READ_UNCOMMITTED:读未提交。未解决任何并发问题。

​ 3) READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。

​ 4)REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读 。

​ 5)SERIALIZABLE:串行化。不存在并发问题。

​ 2、事务的超时时间:表示一个方法执行的最长时间,如果方法执行时超过了时间,事务就会回滚。单位是秒,整数值,默认为-1。

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

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

​ 事务传播行为常量都是以 PROPAGATION_ 开头,形如 PROPAGATION_XXX。

​ 1)PROPAGATION_REQUIRED

//指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事
//务,则创建一个新事务。这种传播行为是最常见的选择,也是 Spring 默认的事务传播行为

​ 2)PROPAGATION_REQUIRES_NEW

指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。
例如查询操作

​ 3)PROPAGATION_SUPPORTS

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

​ 以上三个需要掌握。

​ 4)PROPAGATION_MANDATORY

​ 5)PROPAGATION_NESTED

​ 6)PROPAGATION_NEVER

​ 7)PROPAGATION_NOT_SUPPORTED

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

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

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

​ 运行时异常定义:RunTimeException 和它的子类都是运行时异常,例如NullPointerException

​ NumberFormatException。

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

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

5.4 使用Spring的事务注解管理事务

适合中小型项目使用的注解方案。

5.4.1实现注解事务的基本步骤

​ 1、声明事务管理器(applicationContext.xml)

    <!--    声明事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--        需要知道连接数据库的信息-->
        <property name="dataSource" ref="myDataSource"/>
    </bean>

​ 2、开启注解驱动(applicationContext.xml)

    <!--    开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象
            transaction-manager:事务管理器对象的id
    -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

​ 3、业务层 public 方法加入事务属性

    private SaleDao saleDao;
    private GoodsDao goodsDao;

    /**
     * @param goodsId 购买商品的编号
     * @param nums    购买的数量
     *                rollbackFor:表示发送的异常一定回滚。
     	rollback处理逻辑:
     				1)spring框架首先会检查方法抛出的异常是不是在rollback的属性值中,
	     				如果异常在rollback列表中,不管是什么类型的异常,一定回滚。
	     			2)如果你抛出的异常不在rollback列表中,spring会判断异常是不是RunTimeException,如果是,就一定会							回滚。
     */

    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {Exception.class}
    )
    @Override
    public void buy(Integer goodsId, Integer nums) {
        System.out.println("=====buy()方法的开始====");
//        记录销售信息,向sale表添加记录
        Sale sale = new Sale();
        sale.setGid(goodsId);
        sale.setNums(nums);
        saleDao.insertSale(sale);

//        更新库存
        Goods goods = goodsDao.selectGoods(goodsId);
        if (goods == null) {
//            商品不存在
            throw new NullPointerException("编号是:" + goodsId + "的商品不存在!");
        } else if (goods.getAmount() < nums) {
            throw new NoEnoughException("编号是:" + goodsId + "的商品库存不足!");
        }
//        修改库存
        Goods buyGoods = new Goods();
        buyGoods.setId(goodsId);
        buyGoods.setAmount(nums);
        goodsDao.updateGoods(buyGoods);
        System.out.println("=====buy()方法的结束====");
    }
5.4.2 注意事项

​ 如果我们的spring代码没有问题,但还是会出现不会回滚事务,问题在于我们的数据库引擎,

MYISAM不支持事务,INNODB支持事务处理,Mysql版本从5.5.8开始,默认使用INNODB存储引擎。

修改涉及到的数据库表的引擎为InnoDB

1、查看此数据库中所使用的引擎
show variables like 'default_storage_engine'

2、查看指定表所使用的引擎
show table status where NAME ='表名' 

3、 修改指定表的引擎
alter table 表名 engine=innodb;

*修改mysql默认的数据库引擎*

打开配置文件my.ini,将“default-storage-engine=MYISAM”改为你想设定的,然后重启即可。

5.5 总结spring事务

​ 1、管理事务的是,事务管理和它的实现类。

​ 2、spring的事务是一个统一模型

​ 1)指定要使用的事务管理器实现类,使用

​ 2)指定哪些类,哪些方法需要加入事务的功能。

​ 3)指定方法需要的隔离级别,传播行为,超时等。

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

5.6 使用 AspectJ 的 AOP 配置管理事务

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

5.6.1 要使用的是aspectJ框架,需要加入依赖。
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.14</version>
</dependency>
5.6.2 声明事务管理器对象
<bean id = "xx" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager"/>
5.6.3 声明方法需要的事务类型

​ 配置方法的事务属性【隔离级别,传播行为,超时】

<!--    2、声明业务方法它的事务属性(隔离级别,传播行为,超时时间)-->
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <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,transaction_aspectJ.excep.NoEnoughException"/>
            <!--            使用通配符,指定很多方法-->
            <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>
5.6.4 配置aop

​ 指定哪些类要创建代理。

    <!--配置aop-->
    <aop:config>
        <!--    配置切入点表达式,指定哪些包中的类,要使用事务
                id:切入点表达式的名称,唯一值。
                expression:切入点表达式,指定哪些类要使用事务,aspectJ会创建代理对象。
        -->
        <aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>

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

    </aop:config>

执行测试类

    @Test
    public void test01() {
        String config = "com/applicationContext.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(config);
        BuyGoodsService service = (BuyGoodsService) context.getBean("buyService");
        System.out.println("service.getClass() = " + service.getClass().getName());
//        调用方法
        service.buy(1002,100);
    }

第六章 Spring与web

​ 在 Web 项目中使用 Spring 框架,首先要解决在 web 层(这里指 Servlet)中获取到 Spring 容器的问题。

​ 只要在 web 层获取到了 Spring 容器,便可从容器中获取到 Service 对象。

6.1 加入依赖

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!--        spring框架-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.14</version>
        </dependency>
        <!--        mybatis框架-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</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>
        <!--        spring整合mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.3</version>
        </dependency>
        <!--        mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <!--        数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>com</groupId>
            <artifactId>Spring-Transaction</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <!--        servlet依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
        <!--        jsp依赖-->
        <dependency>
            <groupId>tomcat</groupId>
            <artifactId>jsp-api</artifactId>
            <version>5.5.23</version>
        </dependency>
<!--        使用监听器对象,加入依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.13</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>

6.2 定义Servlet

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        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 context = new ClassPathXmlApplicationContext(config);
//        获取ServletContext中的容器对象,创建好的容器对象,拿来就用

//      第二种方法
/*        WebApplicationContext context = null;
        String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
        Object obj = getServletContext().getAttribute(key);
        if (obj != null) {
            context = (WebApplicationContext) obj;
        }*/
//        第三种方法 使用框架中的方法,获取容器对象
        WebApplicationContext context = null;
        ServletContext sc = getServletContext();
        context = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
        StudentService service = (StudentService) context.getBean("studentService");
        System.out.println("容器的对象信息:context = " + context);

        Student stu = new Student();
        stu.setId(Integer.parseInt(strId));
        stu.setName(strName);
        stu.setEmail(strEmail);
        stu.setAge(Integer.parseInt(strAge));
        service.addStudent(stu);

//        给定一个页面
        request.getRequestDispatcher("/result.jsp").forward(request, response);
    }

6.3 使用 Spring 的监听器 ContextLoaderListener(掌握)

​ 配置监听器:

​ 目的是创建容器对象,创建了容器对象,就能把spring.xml配置文件中的所有对象都创建好。
​ 用户发起请求就可以直接使用对象了。

    <!--    注册监听器 ContextLoaderListener
            监听器被创建对象后,会读取/WEB-INF/applicationContext.xml
            为什么要读取文件:因为在监听器中要创建ApplicationContext对象,需要加载配置文件。
            /WEB-INF/applicationContext.xml就是监听器默认读取的spring配置文件路径。

            可以修改默认的文件位置,使用context-param重新指定文件的位置。
    -->
    <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>

<!-- 涉及依赖 -->
<!-- 使用监听器对象,加入依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.13</version>
        </dependency>

第七章 SPring整合Junit5

7.1 整合Juni4

​ 1、导入依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.15</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

		<dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>

​ 2、编写测试类

//指定单元测试框架的版本
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class UserControllerTest extends TestCase {
    @Autowired
    private TestService testService;
    @Autowired
    private AccountService accountService;

    @Test
    public void testSelectUsers() {
        accountService.moneyTransfer("0102030", "0103040", 1000);
    }

    @Test
    public void test02() {
        testService.test();
    }
}
7.2 整合Junit5

​ 1、导入依赖

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <version>2.7.1.Final</version>
            <scope>test</scope>
        </dependency>

​ 2、测试类

@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:applicationContext.xml")
以上两个注解效果等价于以下一个注解
@SpringJUnitConfig(locations = "classpath:applicationContext.xml")

    注意:
    	其中的@Test需要重新进行选择指定包下的Test注解
//@ExtendWith(SpringExtension.class)
//@ContextConfiguration("classpath:applicationContext.xml")
@SpringJUnitConfig(locations = "classpath:applicationContext.xml")
public class AccountServiceTest {
    @Autowired
    private TestService testService;

    @Test
    public void test02() {
        testService.test();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿姨洗铁路℡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值