Spring

 

Spring

引言

原生 web 开发中存在哪些问题?

  • 传统 Web 开发存在硬编码所造成的过度程序耦合(例如:Service 中作为属性 Dao 对象)。

  • 部分Java EE API较为复杂,使用效率低(例如:JDBC 开发步骤)。

  • 侵入性强,移植性差(例如:DAO 实现的更换,从 Connection 到 SqlSession)。

Spring 框架概述

【重点】Spring 是一个轻量级的一站式开发框架,核心功能为控制反转和切面编程。

概念

  • Spring 框架,由 Rod Johnson 开发(音乐家)

  • Spring 是一个非常活跃的开源框架,基于 IOC(Inverse of Control 控制反转)和 AOP (Aspect Oriented Programming 面向切面编程为内核)来构架多层JavaEE系统,以帮助分离项目组件之间的依赖关系

  • 它的主要目地是简化企业开发

优点

  • 方便解耦,简化开发:Spring 就是一个大工厂,可以将所有对象创建和依赖关系维护,交给 Spring 管理

  • AOP 编程的支持:Spring 提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

  • 声明式事务的支持:只需要通过配置就可以完成对事务的管理,而无需手动编程

  • 方便程序的测试:Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序

  • 方便集成各种优秀框架:Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持

  • Spring 对 JavaEE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等),都提供了封装,降低 JavaEE API 的使用难度

缺点

  • 配置过多

  • 启动缓慢,不具备热部署功能

访问与下载

官方网站:Spring | Home

下载地址:JFrog

官方文档:Spring Framework Documentation

GitHub:GitHub - spring-projects/spring-framework: Spring Framework

API:Spring Framework 5.3.20 API

Spring 架构组成

Spring 架构由诸多模块组成,可分类为:

  • 核心技术:依赖注入,事件,资源,i18n,验证,数据绑定,类型转换,SpEL,AOP。

  • 测试:模拟对象,TestContext 框架,Spring MVC 测试,WebTestClient。

  • 数据访问:事务,DAO支持,JDBC,ORM。

  • Web:WebSocket、Spring MVC 和 Spring Web 框架。

  • 集成:远程处理,JMS,JCA,JMX,电子邮件,任务调度,缓存。

  • 语言:Kotlin,Groovy,动态语言。

模块说明

GroupIdArtifactId描述
org.springframeworkspring-beansBeans 支持,包含 Groovy
org.springframeworkspring-aop基于代理的AOP支持
org.springframeworkspring-aspects基于AspectJ 的切面
org.springframeworkspring-context应用上下文运行时,包括调度和远程抽象
org.springframeworkspring-context-support支持将常见的第三方类库集成到 Spring 应用上下文
org.springframeworkspring-core其他模块所依赖的核心模块
org.springframeworkspring-expressionSpring 表达式语言,SpEL
org.springframeworkspring-instrumentJVM 引导的仪表(监测器)代理
org.springframeworkspring-instrument-tomcatTomcat 的仪表(监测器)代理
org.springframeworkspring-jdbc支持包括数据源设置和 JDBC 访问支持
org.springframeworkspring-jms支持包括发送/接收JMS消息的助手类
org.springframeworkspring-messaging对消息架构和协议的支持
org.springframeworkspring-orm对象/关系映射,包括对 JPA 和 Hibernate 的支持
org.springframeworkspring-oxm对象/XML 映射(Object/XML Mapping,OXM)
org.springframeworkspring-test单元测试和集成测试支持组件
org.springframeworkspring-tx事务基础组件,包括对 DAO 的支持及 JCA 的集成
org.springframeworkspring-webweb支持包,包括客户端及web远程调用
org.springframeworkspring-webmvcREST web 服务及 web 应用的 MVC 实现
org.springframeworkspring-webmvc-portlet用于 Portlet 环境的MVC实现
org.springframeworkspring-websocketWebSocket 和 SockJS 实现,包括对 STOMP 的支持
org.springframeworkspring-jclJakarta Commons Logging 日志系统

Spring IOC & DI

控制反转-IOC

IOC 是 Inversion of Control 的简写,意思是控制反转。是降低对象之间的耦合关系的设计思想。

通过IOC,开发人员不需要关心对象的创建过程,交给Spring容器完成。具体的过程是,程序读取 Spring 配置文件,获取需要创建的 Bean 对象,通过反射机制创建对象的实例。

缺点:对象是通过反射机制实例化出来的,因此对系统的性能有一定的影响。

依赖注入-DI

Dependency Injection,说的是创建对象实例时,同时为这个对象注入它所依赖的属性。相当于把每个 Bean 与 Bean 之间的关系交给容器管理。而这个容器就是 Spring。

例如我们通常在 Service 层注入它所依赖的 Dao 层的实例;在 Controller 层注入 Service 层的实例。

工作原理

 

入门

1、pom.xml 中导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>com.fc</groupId>
    <artifactId>04_Spring_01</artifactId>
    <version>1.0-SNAPSHOT</version>
​
    <dependencies>
        <!--Spring核心依赖,包含aop、beans、core、expression四个jar包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.3</version>
        </dependency>
​
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

2、创建 dao 层接口以及实现类

public interface StudentDao {
    void addStudent();
}
public class StudentDaoImpl implements StudentDao {
    @Override
    public void addStudent() {
        System.out.println("addStudent be executed!");
    }
}

2、创建 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">
​
    <!--使用bean标签声明一个对象,必须指定class为完整的路径名,id或者name任选一个-->
    <bean id="studentDao" class="com.fc.dao.impl.StudentDaoImpl"/>
​
</beans>

【注意】配置文件要放在 resources 目录下

3、测试

public class StudentDaoTest {
    @Test
    public void testAddStudent() {
        // 根据配置文件创建核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 根据配置文件中bean的id或者name获取对象
        StudentDao studentDao = applicationContext.getBean("studentDao", StudentDao);
​
        // 调用对象的方法
        studentDao.addStudent();
    }
}

【补充】BeanFactory 与 ApplicationContext 区别

ApplicationContext:它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。

BeanFactory:它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。

ApplicationContext 对 BeanFactory 提供了扩展:

  • 国际化处理

  • 事件传递

  • Bean 自动装配

  • 各种不同应用层的Context实现

Spring 对 bean 的管理

Spring IoC 容器管理一个或多个 bean。这些 bean 是使用您提供给容器的配置元数据创建的(例如,以 XML <bean/>定义的形式)。

bean 标签

使用该标签描述需要 spring 容器管理的对象

Bean 标签的属性

属性描述
class被管理对象的完整的包名.类名
name给被管理的对象起个名字,可以通过这个名字获取被管理的对象
id与 name 属性作用相同,如果id和name同时存在,则name属性为别名,都可以使用
ScopeBean的作用域
Constructor arguments使用构造方法进行依赖注入
Properties使用set方法进行依赖注入
Lazy initialization mode懒加载模式
Initialization method初始化方法
Destruction method销毁方法

创建 bean 的三种方式

使用无参构造方法

StudentDaoImpl

public class StudentDaoImpl implements StudentDao {
    @Override
    public void addStudent() {
        System.out.println("addStudent be executed!");
    }
}

配置文件

<?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">
​
    <!--默认使用类中的无参构造方法创建对象-->
    <bean id="studentDao" class="com.fc.dao.impl.StudentDaoImpl"/>
​
</beans>

采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建并报错!!!

No default constructor found

使用普通工厂

使用类中的方法创建对象,并存入spring容器

普通工厂类

public class StudentDaoFactory {
    public StudentDaoImpl getStudentDaoImpl() {
        return new StudentDaoImpl();
    }
}

配置文件

<?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">
​
    <!--声明一个工厂对象-->
    <bean id="studentDaoFactory" class="com.fc.dao.factory.StudentDaoFactory"/>
    <!--通过工厂的方法获取对象-->
    <bean id="studentDao2" factory-bean="studentDaoFactory" factory-method="getStudentDaoImpl"/>
</beans>

使用工厂中的静态方法

使用某个类中的静态方法创建对象,并存入spring容器

静态工厂类

public class StaticStudentDaoFactory {
    // 通过静态方法获取对象
    public static StudentDaoImpl getStudentDaoImpl() {
        return new StudentDaoImpl();
    }
}

配置文件

<?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">
    <!--通过类中的静态方法获取对象-->
    <bean id="studentDao3" class="com.fc.dao.factory.StaticStudentDaoFactory" factory-method="getStudentDaoImpl" />
</beans>

bean 的作用范围

bean 标签的 scope 属性用于声明对象的作用域,即指定对象的作用范围。Spring Framework 提供了六种作用域,甚至还可以自定义作用域(了解)。

常用的作用域为 singleton,对应设计模式中的单例模式,使用此模式的 Bean 会在容器加载时创建好。而 prototype 对应设计模式中的原型模式,会在调用 getBean 方法时通过工厂创建。

ScopeDescription
singleton(默认值)每个 Spring IoC 容器将单个 bean 定义范围限制到单个对象实例。(单例)
prototype将单个 bean 定义的作用域限定为任意数量的对象实例。(多例)
request将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期;也就是说,每个 HTTP 请求都有一个自己的 bean 实例,它是在单个 bean 定义的后面创建的。仅在可感知网络的 Spring ApplicationContext中有效。
session将单个 bean 定义的范围限定为 HTTP Session的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
application将单个 bean 定义的范围限定为ServletContext的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
websocket将单个 bean 定义的范围限定为WebSocket的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。

【注意】后五种作用域只有在 Web 项目中可用

配置文件

<?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">
​
    <!--默认不写作用域为单例模式-->
    <bean id="studentDao" class="com.fc.dao.impl.StudentDaoImpl"/>
​
    <!--设置作用域为多例模式-->
    <bean id="studentDao4" class="com.fc.dao.impl.StudentDaoImpl" scope="prototype"/>
</beans>

案例代码

public class StudentDaoTest {
    // 测试bean作用域
    @Test
    public void testScope() {
        // 根据配置文件创建核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 根据配置文件中bean的id或者name获取对象
        // 单例
        StudentDao studentDao1 = (StudentDao) applicationContext.getBean("studentDao");
        StudentDao studentDao2 = (StudentDao) applicationContext.getBean("studentDao");
        StudentDao studentDao3 = (StudentDao) applicationContext.getBean("studentDao");
​
        // 多例
        StudentDao studentDao4 = (StudentDao) applicationContext.getBean("studentDao4");
        StudentDao studentDao5 = (StudentDao) applicationContext.getBean("studentDao4");
        
        System.out.println(studentDao1 == studentDao2); // true
        System.out.println(studentDao2 == studentDao3); // true
        System.out.println(studentDao3 == studentDao4); // false
        System.out.println(studentDao4 == studentDao5); // false
    }
}

bean 的生命周期

// 配置一个方法作为生命周期初始化方法. spring会在对象创建之后立即调用
init-method
​
// 配置一个方法作为生命周期的销毁方法. spring容器在关闭并销毁所有容器中的对象之前调用
destory-method

配置文件

<?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">
    <!--生命周期-->
    <bean id="studentDao5" class="com.fc.dao.impl.StudentDaoImpl" init-method="init" destroy-method="destroy"/>
</beans>

案例代码

public class StudentDaoTest {
    // 测试Bean的生命周期
    @Test
    public void testLife() {
        // 根据配置文件创建核心容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 根据配置文件中bean的id或者name获取对象
        StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDao5");
​
        // 执行对应的方法
        studentDao.addStudent();
​
        // 关闭Ioc容器
        ((ClassPathXmlApplicationContext) applicationContext).close();
    }
}

结果

init method be executed!
addStudent be executed!
destroy method be executed!

延迟加载

默认情况下,作为初始化过程的一部分,ApplicationContext实现会急切地创建和配置所有单例 bean。通常,这种预实例化是可取的,因为配置或周围环境中的错误会立即发现,而不是几小时甚至几天之后。当这种行为不可取时,您可以通过将 bean 定义标记为延迟初始化来防止单例 bean 的预实例化。延迟初始化的 bean 告诉 IoC 容器在第一次被请求时创建一个 bean 实例,而不是在启动时。

使用 lazy-init 属性以启用延迟加载,只对单例中有效

<!--默认值,不延迟创建,即在启动时候就创建对象-->
lazy-init="false" 
​
<!--延迟初始化,在用到对象的时候才会创建对象-->
lazy-init="true" 

引入其他配置文件

<!--在当前applicationContext.xml配置文件中引入其他spring配置文件-->
<import resource="XXX.xml"/>

Spring 依赖注入

Spring 中的依赖注入

依赖注入:Dependency Injection。它是 Spring 框架核心 Ioc 的具体实现。 我们的程序在编写时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。Ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。 那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了,我们只需要在配置文件中说明。

构造方法注入

使用类中的构造函数,给成员变量赋值

使用到的标签:

constructor-arg

标签中的属性描述:

属性描述
type用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
name用于指定给构造函数中指定名称的参数赋值
value用于提供基本类型和String类型的数据
ref用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
  • 优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。

  • 弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

Car 实体类

public class Car {
    private Float speed;
    private String name;
​
    public Car(Float speed, String name) {
        this.speed = speed;
        this.name = name;
    }
}

User 实体类

public class User {
    private String name;
    private int age;
    private Car car;
    private List<String> food;
​
    public User(String name, int age, Car car, List<String> food) {
        this.name = name;
        this.age = age;
        this.car = car;
        this.food = food;
    }
}

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">
​
    <!--创建Car对象-->
    <bean id="car" class="com.fc.bean.Car">
        <!--通过构造方法对指定属性赋值-->
        <constructor-arg name="speed" value="100.0F" type="java.lang.Float" index="0"/>
        <constructor-arg name="name" value="保时捷" type="java.lang.String" index="1"/>
    </bean>
​
    <!--创建User对象-->
    <bean id="user" class="com.fc.bean.User">
        <!--通过构造方法对指定属性赋值-->
        <constructor-arg name="name" value="张三" type="java.lang.String" index="0"/>
        <constructor-arg name="age" value="20" type="int" index="1"/>
        <constructor-arg name="food" type="java.util.List">
            <!--给集合中赋值-->
            <list>
                <value>烤羊排</value>
                <value>烤面筋</value>
                <value>烤韭菜</value>
            </list>
        </constructor-arg>
        <!--引用一个Car对象-->
        <constructor-arg name="car" ref="car" type="com.fc.bean.Car"/>
    </bean>
</beans>

测试类

public class UserTest {
    // 测试构造方法注入
    @Test
    public void testUser() {
        // 创建Ioc容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 从容器中获取User对象
        User user = applicationContext.getBean("user", User.class);
        
        System.out.println(user);
    }
}

set 方法注入【重点】

通过实体类中的 set 方法进行依赖注入

使用到的标签:

property

标签中的属性描述:

属性描述
name用于指定给构造函数中指定名称的参数赋值
value用于提供基本类型和String类型的数据
ref用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

Car 实体类

public class Car {
    private Float speed;
    private String name;
    
    // Constructor、Setters、Getters
}

User 实体类

public class User {
    private String name;
    private int age;
    private Car car;
    private List<String> food;
    
    // Constructor、Setters、Getters
}

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">
    <!--创建Car对象-->
    <bean id="car2" class="com.fc.bean.Car">
        <!--给speed和name属性设置对应的值-->
        <property name="speed" value="100.0F"/>
        <property name="name" value="兰博基尼"/>
    </bean>
​
    <!--创建User对象-->
    <bean id="user2" class="com.fc.bean.User">
        <!--给User类中的属性设置值-->
        <property name="name" value="玉田"/>
        <property name="age" value="30"/>
        <property name="food">
            <!--给List集合设置值-->
            <list>
                <value>烤地瓜</value>
                <value>烤玉米</value>
                <value>烤韭菜</value>
            </list>
        </property>
        <!--引用一个Car对象-->
        <property name="car" ref="car2"/>
    </bean>
</beans>

测试类

public class UserTest {
    // 测试构造方法注入
    @Test
    public void testUser() {
        // 创建Ioc容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 从容器中获取User对象
        User user = applicationContext.getBean("user2", User.class);
        
        System.out.println(user);
    }
}

复杂类型的注入

给 List、Set、Map 以及数组这种复杂类型进行注入

使用到的标签:

标签描述
list用于给List集合赋值(标签中声明value标签)
set用于给Set集合赋值(标签中声明value标签)
map用于给Map映射赋值(标签中声明entry标签,使用key和value的属性赋值)【注意与props互斥】
props用于给Map映射赋值(标签中声明prop标签,使用key属性赋值)【注意与map互斥】
array用于给数组赋值

ComplexType 实体类

public class ComplexType {
    private List<String> list;
    private Set<Integer> set;
    private Map<Integer, String> map;
    private Object[] objects;
​
    // Constructor、Getters、Setters、toString
}

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">
    <!--测试复杂类型的注入-->
    <bean id="complexType" class="com.fc.bean.ComplexType">
        <property name="list">
            <!--给List设置值-->
            <list>
                <value>Hello</value>
                <value>World</value>
                <value>Java</value>
            </list>
        </property>
​
        <property name="set">
            <!--给Set设置值-->
            <set>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </set>
        </property>
​
        <property name="map">
            <!--给Map设置键值对-->
            <map>
                <entry key="1" value="易烊千玺"/>
                <entry key="2" value="迪丽热巴"/>
                <entry key="3" value="张三"/>
            </map>
            
            <!--使用这种方式也可以-->
            <!--<props>-->
                <!--<prop key="1">易烊千玺</prop>-->
                <!--<prop key="2">迪丽热巴</prop>-->
                <!--<prop key="3">张三</prop>-->
            <!--</props>-->
        </property>
​
        <property name="objects">
            <!--给数组设置值-->
            <array>
                <value>1</value>
                <value>1.1</value>
                <value>true</value>
                <value>吃饭</value>
            </array>
        </property>
    </bean>
</beans>

测试类

public class UserTest {
    // 测试复杂类型的注入
    @Test
    public void testComplexType() {
        // 创建Ioc容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 从容器中获取ComplexType对象
        ComplexType complexType = applicationContext.getBean("complexType", ComplexType.class);
​
        System.out.println(complexType);
    }
}

结果

ComplexType{list=[Hello, World, Java], set=[1, 2, 3], map={1=易烊千玺, 2=迪丽热巴, 3=张三}, objects=[1, 1.1, true, 吃饭]}

注解注入【非常重要】

控制反转常用注解

注解描述
@Component用于把当前类对象存入Spring容器中。value属性:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写
@Controller一般用在控制层,和 Component 的效果一样
@Service一般用在业务层,和 Component 的效果一样
@Repository一般用在持久层,和 Component 的效果一样

依赖注入常用注解

注解描述
@Autowired自动按照类型注入(首字母小写)
@Qualifier在根据类型中注入的基础之上再按照名称注入,value属性:用于指定注入bean的id
@Resource直接按照bean的id注入。它可以独立使用,name属性:用于指定bean的id
@Value用于给成员变量注入基本类型和String类型的数据

【注意】

1、以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现,另外,集合类型的注入只能通过XML来实现。因为 Resource 注解是J2EE的,而不是Spring本身的,所以在使用时需要在 pom.xml 中导入依赖

<dependency>
	<groupId>javax.annotation</groupId>
	<artifactId>javax.annotation-api</artifactId>
	<version>1.3.2</version>
</dependency>

scope

用于改变作用范围的,作用和在 bean 标签中使用 scope 属性实现的功能是一样的

注解描述
Scope用于指定bean的作用范围,value:指定范围的取值。常用取值:singleton(单例) prototype(多例)

生命周期

生命周期相关,作用和在bean标签中使用 init-method 和 destroy-method 的作用是一样的

注解描述
@PreDestroy用于指定销毁方法
@PostConstruct用于指定初始化方法

spel 注入【了解】

实体类

@Data
public class Car {
    private String name;
}

@Data
public class User {
    private String name;
    private Integer age;
    private Car car;
}

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">

    <bean name="car" class="com.fc.bean.Car">
        <property name="name" value="兰博基尼"/>
    </bean>

    <bean name="user" class="com.fc.bean.User">
        <!--使用 spel 注入-->
        <property name="name" value="#{car.name}"/>
        <property name="age" value="23"/>
        <property name="car" ref="car"/>
    </bean>
</beans>

测试类

public class SetDITest {
    @Test
    public void SetTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
​
        User user = (User) applicationContext.getBean("user");
​
        System.out.println(user);
    }
}

结果

User(name=兰博基尼, age=23, car=Car(name=兰博基尼))

p命名空间注入【了解】

实体类

@Data
public class Car {
    private String name;
}
​
@Data
public class User {
    private String name;
    private Integer age;
    private Car car;
}

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">

    <bean name="car" class="com.fc.bean.Car">
        <property name="name" value="兰博基尼"/>
    </bean>

    <bean name="user" class="com.fc.bean.User" p:name="Smoot" p:age="22" p:car-ref="car"/>
</beans>

测试类

public class SetDITest {
    @Test
    public void SetTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "applicationContext.xml");

        User user = (User) applicationContext.getBean("user");

        System.out.println(user);
    }
}

结果

User(name=Smoot, age=22, car=Car(name=兰博基尼))

Spring 访问数据库【了解】

概述

Spring 框架提供了可扩展的 SQL 数据库的支持。JdbcTemplate 是 Spring 提供的最经典也是最流行的 jdbc 实现方式之一。

搭建环境

创建 User 数据表

create table user(id int primary key auto_increment, username varchar(20) unique not null, password varchar(16) not null);

pom.xml 引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.fc</groupId>
    <artifactId>04_Spring_03</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--Spring核心依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.3</version>
        </dependency>

        <!--Spring Jdbc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.3</version>
        </dependency>

        <!--数据库连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

声明 User 实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
}

xml 方式访问数据库

Spring的 JdbcTemplate(了解会用)在 Spring 中提供了一个可以操作数据库的对象org.springframework.jdbc.core.JdbcTemplate,对象封装了 jdbc 技术,JDBC 的模板对象与 DBUtils 中的 QueryRunner 非常相似。

声明 dao 层实现类

public class JdbcTemplateDaoImpl {

    // 声明一个JdbcTemplate,类似于DbUtils中的QueryRunner
    private JdbcTemplate template;

    // 查询方法
    public void select() {

        // 调用查询方法,传入一个Sql语句和结果集映射处理器对象
        List<User> list = template.query("select * from user", new BeanPropertyRowMapper<>(User.class));

        // 增强for循环遍历
        for (User user : list) {
            System.out.println(user);
        }
    }

    public void setTemplate(JdbcTemplate template) {
        this.template = template;
    }
}

applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd ">

    <!--引入外部资源文件-->
    <context:property-placeholder location="jdbc.properties"/>

    <!-- 配置druid数据库连接池,并从外部资源文件中获取对应参数 -->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
    </bean>

    <!-- 配置spring的jdbcTemplate-->
    <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置dao层实现类-->
    <bean name="jdbcTemplateDaoImpl" class="com.fc.dao.impl.JdbcTemplateDaoImpl">
        <property name="template" ref="jdbcTemplate"/>
    </bean>
</beans>

测试类

public class JdbcTemplateTest {
    @Test
    public void testSelect() {
        // 声明Spring容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 获取dao层实现类对象
        JdbcTemplateDaoImpl jdbcTemplateTest = applicationContext.getBean("jdbcTemplateDaoImpl", JdbcTemplateDaoImpl.class);
​
        // 调用方法
        jdbcTemplateTest.select();
    }
}

注解方式访问数据库

Spring 中的相关注解【非常重要】

注解描述属性注意
@Configuration指定当前类是一个配置类当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写
@ComponentScan用于通过注解指定 Spring 在创建容器时要扫描的包value等同于xml中: <context:component-scan base-package="com.fc"/>
@PropertySource用于指定 properties 文件的位置value关键字:classpath,表示类路径下 等同于xml中: <context:property-placeholder location="classpath:jdbc.properties"/>
@Bean用于把当前方法的返回值作为bean 对象存入 Spring 的 ioc 容器中,通常用在配置类中name当使用注解配置方法时,如果方法有参数,在参数前加:@Qualifier("@Bean注解中name的值"),Spring框架会去容器中查找有没有可用的 bean 对象查找的方式和Autowired注解的作用是一样的。
@Import用于导入其他的配置类value当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类 等同于xml中: <import resource="xxx.xml"/>

案例代码

JdbcConfiguration 配置类

// 引入jdbc.properties文件
@PropertySource("classpath:jdbc.properties")
// 扫描指定包下的注解
@ComponentScan("com.fc")
// 声明这是一个配置类
@Configuration
public class JdbcConfiguration {
    @Value("${jdbc.driverClassName}")
    private String driveClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    /**
     * 此方法用于获取一个JdbcTemplate对象
     *
     * 并通过@Bean注解将获取到的JdbcTemplate对象注入到Ioc容器中
     */
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate getJdbcTemplate() {
        JdbcTemplate jdbcTemplate = null;

        // 声明Properties对象并且设置参数
        Properties properties = new Properties();

        properties.setProperty("driveClassName", driveClassName);
        properties.setProperty("url", url);
        properties.setProperty("username", username);
        properties.setProperty("password", password);

        try {
            // 使用Properties对象创建Druid连接池数据源
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

            // 通过数据源对象获取JdbcTemplate
            jdbcTemplate = new JdbcTemplate(dataSource);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return jdbcTemplate;
    }
}

测试类

public class AnnotationTest {
    @Test
    public void testAnnotation() {
        // 通过注解获取Ioc容器
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JdbcConfiguration.class);

        // 从容器中获取JdbcTemplate模板对象
        JdbcTemplate template = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);

        // 查询数据库并获取List集合
        List<User> list = template.query("select * from user", new BeanPropertyRowMapper<>(User.class));

        // 增强for循环遍历
        for (User user : list) {
            System.out.println(user);
        }
    }
}

Spring AOP

概述

AOP Aspect Oriented Programing 面向切面编程

AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存、日志)

Spring AOP 使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码

AOP 底层原理

代理机制

动态代理

特点:字节码随用随创建,随用随加载

作用:不修改源码的基础上对方法增强

分类:

  • 基于接口的动态代理

  • 基于子类的动态代理

Spring 的 AOP 代理

JDK 动态代理:被代理对象必须要实现接口。才能产生代理对象。如果没有接口将不能使用动态代理技术。

CGLib 动态代理:第三方代理技术,CGLib代理。可以对任何类生成代理。代理的原理是对目标对象进行继承代理,如果目标对象被 final 修饰。那么该类无法被 CGLib 代理。

【重点】Spring 框架,如果类实现了接口,就使用 JDK 的动态代理生成代理对象,如果这个类没有实现任何接口,使用 CGLIB 生成代理对象。

AOP 相关术语

术语描述
Joinpoint(连接点)所谓连接点是指那些被拦截到的点。在 Spring 中,这些点指的是方法,因为 Spring 只支持方法类型的连接点
Pointcut(切入点)所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强)所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介)引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或字段
Target(目标对象)代理的目标对象(被代理对象)
Weaving(织入)是指把增强应用到目标对象来创建新的代理对象的过程。 spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
Proxy(代理)一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面)是切入点和通知(引介)的结合

通知类型

通知类型描述
Before前置通知,目标方法调用之前执行
After-returning后置通知,目标方法运行之后调用 (如果出现异常不会调用)
After-throwing异常通知,出现异常调用
After最终通知,在目标方法运行之后调用(无论是否出现异常)
Around环绕通知,目标方法之前和之后都会调用(ProceedingJoinPoint对象 -->> 调用proceed方法)

Spring 使用 AOP

1、pom.xml 文件中引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.fc</groupId>
    <artifactId>04_Spring_05_AOP</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <!--Spring核心容器-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.3</version>
        </dependency>

        <!--AOP-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
</project>

2、UserService 接口

public interface UserService {
    void addUser();

    void updateUser();
}

3、UserServiceImpl 接口实现类

public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("添加了一位新同学");
    }

    @Override
    public void updateUser() {
        int i = 1 / 0;
        System.out.println("修改了一位学生的信息");
    }
}

通过 XML 配置文件 【重点】

1、使用注解声明切面类

// 增强,切面类
public class XMLAdvice {
    // 前置通知
    public void before() {
        System.out.println("before advice --> 前置通知,方法执行前调用");
    }

    // 后置通知
    public void afterReturning() {
        System.out.println("AfterReturning --> 后置通知,出现异常时不执行");
    }

    // 异常通知
    public void afterThrowing() {
        System.out.println("AfterThrowing --> 出现异常时执行");
    }

    // 最终通知
    public void after() {
        System.out.println("After advice --> 最终通知,出现异常时也会调用");
    }

    // 环绕通知
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("Around --> 环绕通知,方法调用之前执行");

        // 执行方法
        Object proceed = joinPoint.proceed();

        System.out.println("Around --> 环绕通知,方法调用之后执行");

        return proceed;
    }
}

2、applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
​
    <!-- 配置目标对象 -->
    <bean name="userServiceImpl" class="com.fc.service.impl.UserServiceImpl"/>
    <!-- 配置通知对象 -->
    <bean name="XMLAdvice" class="com.fc.advice.XMLAdvice"/>
​
    <!--aop配置,声明基于类的方式实现代理-->
    <aop:config proxy-target-class="true">
        <!--声明切点-->
        <aop:pointcut id="pointcut" expression="execution(* com.fc.service.impl.*ServiceImpl.*(..))"/>
​
        <!--配置切面-->
        <aop:aspect ref="XMLAdvice">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
​
</beans>

3、测试类

public class XMLTest {
    @Test
    public void testXML() {
        // 获取IOC容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从Ioc容器中获取对象
        UserService userService = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);

        // 执行方法
        userService.addUser();

        userService.updateUser();
    }
}

【注意】如果出现 BeanNotOfRequiredTypeException 异常时说明使用了接口的动态代理,需要将 proxy-target-class 属性设置为 true 即可

<aop:config proxy-target-class="true">
...
</aop:config>

通过注解【重点】

使用注解声明切面类

// 声明切面类
@Aspect
public class AnnotationAdvice {
    // 声明切点
    @Pointcut("execution(* com.fc.service.impl.*ServiceImpl.*(..))")
    public static void pointCut() {}

    // 声明前置通知
    @Before("AnnotationAdvice.pointCut()")
    public void before() {
        System.out.println("before advice --> 前置通知,方法执行前调用");
    }

    // 声明后置通知,出现异常时不执行
    @AfterReturning("AnnotationAdvice.pointCut()")
    public void afterReturning() {
        System.out.println("AfterReturning --> 后置通知,出现异常时不执行");
    }

    // 声明后置通知,出现异常时执行
    @AfterThrowing("AnnotationAdvice.pointCut()")
    public void afterThrowing() {
        System.out.println("AfterThrowing --> 出现异常时执行");
    }

    // 最终通知
    @After("AnnotationAdvice.pointCut()")
    public void after() {
        System.out.println("After advice --> 最终通知,出现异常时也会调用");
    }

    // 环绕通知
    @Around("AnnotationAdvice.pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around --> 环绕通知,方法调用之前执行");

        // 执行方法
        Object proceed = joinPoint.proceed();

        System.out.println("Around --> 环绕通知,方法调用之后执行");

        return proceed;
    }
}

applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">

    <!-- 配置目标对象 -->
    <bean name="userServiceImpl" class="com.fc.service.impl.UserServiceImpl"/>
    <!-- 配置通知对象 -->
    <bean name="myAdvice" class="com.fc.advice.AnnotationAdvice"/>
    <!-- 开启使用注解完成织入,声明基于类的方式实现代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

</beans>

测试类

public class AnnotationTest {
    @Test
    public void testAnnotation() {
        // 从配置文件中获取IOC容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 从Ioc容器中获取对象
        UserService userService = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
​
        // 执行方法
        userService.addUser();
​
        userService.updateUser();
    }
}

【注意】如果出现 BeanNotOfRequiredTypeException 异常时说明使用了接口的动态代理,需要将 proxy-target-class 属性设置为 true 即可

<!-- 开启注解配置AOP,并且基于类的动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
​
<!-- 开启注解配置AOP,并且基于接口的动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="false"/>

补充:切入点表达式的写法

applicationContext.xml 中 execution 表达式的写法

类型匹配语法

*   匹配任何数量字符,只有一个。
​
..  匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
​
+   匹配指定类型的子类型;仅能作为后缀放在类型模式后边

案例

// 匹配String类型;
java.lang.String 

// 匹配java包下的任何“一级子包”下的String类型;如匹配java.lang.String,但不匹配java.lang.ss.Strin   
java.*.String   
    
// 匹配java包及任何子包下的任何类型; 如匹配java.lang.String、java.lang.annotation.Annotation
java..*
    
// 匹配任何java.lang包下的以ing结尾的类型;  
java.lang.*ing
    
// 匹配java.lang包下的任何Number的自类型;如匹配java.lang.Integer,也匹配java.math.BigInteger
java.lang.Number+     

基本语法格式

执行(注解 访问修饰符 返回值类型 方法名(参数列表) 异常列表)

execution(@org.junit.Test public java.lang.String com.fc.service.impl.UserServceImpl.add(String username, Sring passowrd) )
  • 注解:可选,方法上持有的注解,如@Deprecated;

  • 修饰符:可选,如public、protected;

  • 返回值类型:必填,可以是任何类型模式;“*”表示所有类型;

  • 方法名:必填,可以使用“*”进行模式匹配;

  • 参数列表:“()”表示方法没有任何参数;“(..)”表示匹配接受任意个参数的方法

  • 异常列表:可选,以“throws 异常全限定名列表”声明,异常全限定名列表如有多个以“,”分割

模式描述
public * *(..)任何公共方法的执行
* cn.javass..IPointcutService.*()cn.javass包及所有子包下IPointcutService接口中的任何无参方法
* cn.javass.. * .*(..)cn.javass包及所有子包下任何类的任何方法
* cn.javass..IPointcutService.*( *)cn.javass包及所有子包下IPointcutService接口的任何只有一个参数方法
* (!cn.javass..IPointcutService+).*(..)非“cn.javass包及所有子包下IPointcutService接口及子类型”的任何方法
* cn.javass..IPointcutService+.*()cn.javass包及所有子包下IPointcutService接口及子类型的的任何无参方法
* cn.javass..IPointcut*.test *(java.util.Date)cn.javass包及所有子包下IPointcut前缀类型的的以test开头的只有一个参数类型为java.util.Date的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据执行时传入的参数类型决定的如定义方法:public void test(Object obj);即使执行时传入java.util.Date,也不会匹配的;
@java.lang.Deprecated * *(..)任何持有@java.lang.Deprecated注解的方法

常见写法

<aop:config>
	<!-- 配置切入点 切入点表达式的写法:execution(表达式)
		public void com.fc.service.UserServiceImpl.save() 
		void com.fc.service.UserServiceImpl.save()  其他修饰符无返回值的save空参方法
		* com.fc.service.UserServiceImpl.save()  有或者无返回值的save空参方法
		* com.fc.service.UserServiceImpl.*()  有或者无返回值的所有空参方法
		
		* com.fc.service.*ServiceImpl.*(..)  有或者无返回值的所有有参或者空参方法
		* com.fc.service..*ServiceImpl.*(..)  一般不用,service包下的子包和孙包以ServiceImpl结尾的类中的方法
	-->
	<aop:pointcut expression="execution(* com.fc.service.*ServiceImpl.*(..))" id="pc"/>
	<aop:aspect ref="myAdvice" >
		<!-- 指定名为before方法作为前置通知 -->
		<aop:before method="before" pointcut-ref="pc" />
		<!-- 后置通知,出现异常不会执行 -->
		<aop:after-returning method="afterReturning" pointcut-ref="pc" />
		<!-- 环绕通知 -->
		<aop:around method="around" pointcut-ref="pc" />
		<!-- 异常拦截通知,出现异常时执行 -->
		<aop:after-throwing method="afterException" pointcut-ref="pc"/>
		<!-- 后置通知,无论是否出现异常都会执行 -->
		<aop:after method="after" pointcut-ref="pc"/>
	</aop:aspect>
</aop:config>

Spring 事务

Spring 并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给 MyBatis、Hibernate 或者 JTA 等持久化机制所提供的相关平台框架的事务来实现。

相关 API

// 平台事务管理器
public interface PlatformTransactionManager {
    // 获取事务状态
    TransactionStatus getTransaction(TransactionDefinition definition);
    
    // 回滚事务
    void rollback(TransactionStatus status);
    
    // 提交事务
    void commit(TransactionStatus status);
}

// 事务定义
public interface TransactionDefinition {
	// 事务的隔离级别
    ISOLATION_XXX
        
    // 事务的传播行为
    PROPAGATION_XXX
        
    // 过期时间
    int TIMEOUT_DEFAULT = -1;
}
        
// 事务状态
public interface TransactionStatus {
	// 是否有保存点
    boolean hasSavepoint();
    
    // 是否是一个新的事务【子类】
    public boolean isNewTransaction();
}

【注意】PlatformTransactionManager 通过 TransactionDefinition 设置事务相关信息管理事务,管理事务过程中,产生一些事务状态,状态由 TransactionStatus 记录。

PlatformTransactionManager

Spring 为不同的持久化框架提供了不同 PlatformTransactionManager 接口实现

描述
DataSourceTransactionManager使用Spring JDBC或 iBatis 进行持久化数据时使用
HibernateTransactionManager使用Hibernate进行持久化数据时使用
jpa.JpaTransactionManager使用JPA进行持久化时使用
JdoTransactionManager当持久化机制是Jdo时使用
JtaTransactionManager使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用

TransactionDefinition 事务的隔离级别【重点】

Field描述
ISOLATION_DEFAULTmysql 中对应 repeatable_read,Oracle 对应 read_committed
ISOLATION_READ_UNCOMMITTED读未提交
ISOLATION_READ_COMMITTED读已提交
ISOLATION_REPEATABLE_READ可重复读
ISOLATION_SERIALIZABLE可串行化(可序列化)

事务的传播行为

【作用】解决业务层之间调用的事务的关系

Field作用描述
PROPAGATION_REQUIRED支持当前事务,如果不存在就新建一个A,B 如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A,B是在一个事务中)
PROPAGATION_SUPPORTS支持当前事务,如果不存在,就不使用事务A,B 如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务
PROPAGATION_MANDATORY支持当前事务,如果不存在,抛出异常A,B 如果A有事务,B使用A的事务,如果A没有事务,抛出异常
PROPAGATION_REQUIRES_NEW如果有事务存在,挂起当前事务,创建一个新的事务A,B 如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中.事务互不影响)
PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果有事务存在,挂起当前事务A,B 非事务的方式运行,A有事务,就会挂起当前的事务
PROPAGATION_NEVER以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED如果当前事务存在,则嵌套事务执行基于SavePoint技术 A,B A有事务,A执行之后,将A事务执行之后的内容保存到SavePoint.B事务有异常的话,用户需要自己设置事务提交还是回滚

【重点】

PROPAGATION_REQUIRED PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED

事务环境搭建

准备数据库并插入数据

create table account(id int primary key auto_increment, name varchar(20) not null unique, money decimal(11, 2) default 0.00);
​
insert into account(name, money) values('玉田', 10000);
insert into account(name, money) values('刘英', 10000);

pom.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>com.fc</groupId>
    <artifactId>04_Spring_06_Transaction</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
​
    <dependencies>
        <!--Spring核心-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.3</version>
        </dependency>
​
        <!--Spring事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.3</version>
        </dependency>
​
        <!--AOP-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>
​
        <!--Spring JDBC-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.3</version>
        </dependency>
        
        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
​
        <!--Druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.4</version>
        </dependency>
​
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
​
</project>

声明 Account 实体类

public class Account {
    private int id;
    private String name;
    private BigDecimal money;

    // Constructor、Getters、Setters
}

Dao 层接口

public interface AccountDao {
    // 加钱
    void increaseMoney(Integer id, BigDecimal money);

    // 减钱
    void decreaseMoney(Integer id, BigDecimal money);
}

Dao 层接口实现类

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
    @Override
    public void increaseMoney(Integer id, BigDecimal money) {
        getJdbcTemplate().update("update account set money = money + ? where id = ?", money, id);

        System.out.println("加钱成功");
    }

    @Override
    public void decreaseMoney(Integer id, BigDecimal money) {
        getJdbcTemplate().update("update account set money = money - ? where id = ?", money, id);

        System.out.println("减钱成功");;
    }
}

业务层接口

public interface AccountService {
    /**
     * 转账
     *
     * @param from 从哪里转
     * @param to 转到哪里去
     * @param money 转账金额
     */
    void transfer(Integer from, Integer to, BigDecimal money);
}

业务层接口实现类

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    @Override
    public void transfer(Integer from, Integer to, BigDecimal money) {
        // 减钱
        accountDao.decreaseMoney(to, money);

        System.out.println("发生了异常");
        int num = 1 / 0;
        
        // 加钱
        accountDao.increaseMoney(from, money);
    }

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}

applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd ">

    <!--引入外部资源文件-->
    <context:property-placeholder location="jdbc.properties"/>

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

    <!--依赖注入-->
    <bean name="accountDao" class="com.fc.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean name="accountService" class="com.fc.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

</beans>

测试类

public class AccountTest {

    @Test
    public void testTransfer() {
        // 获取IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从Ioc容器中获取业务层对象
        AccountService accountService = applicationContext.getBean("accountService", AccountServiceImpl.class);

        // 执行转账方法
        accountService.transfer(1, 2, BigDecimal.valueOf(100.00));
    }
}

上述测试中,如果在转账方法中出现异常后,数据前后会产生不一致,此时,我们需要用Spring的事务管理来解决这一问题。

编程式事务【垃圾】

代码量增加,代码有侵入性

业务层接口实现类

public class ProgrammingServiceImpl implements AccountService {
​
    private AccountDao accountDao;
​
    // 声明一个事务模板对象
    private TransactionTemplate transactionTemplate;
​
    @Override
    public void transfer(final Integer from, final Integer to, final BigDecimal money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                // 减钱
                accountDao.decreaseMoney(from, money);
​
                int i = 1 / 0;// 如果发生异常数据(钱)不会丢失
​
                // 加钱
                accountDao.increaseMoney(to, money);
            }
        });
    }
​
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
​
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }
}

applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
​
    <!--引入外部资源文件-->
    <context:property-placeholder location="jdbc.properties"/>
​
    <!--配置数据源-->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
​
    <!--声明事务管理器,封装了事务相关的所有操作,必须依赖于连接池-->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
​
    <!--声明事务模板对象-->
    <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
​
    <!--依赖注入-->
    <bean name="accountDao" class="com.fc.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>
​
    <bean name="programmingService" class="com.fc.service.impl.ProgrammingServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>
​
</beans>

测试类

public class AccountTest {
	// 测试编程式事务
    @Test
    public void testProgramming() {
        // 获取IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 从Ioc容器中获取业务层对象
        AccountService accountService = applicationContext.getBean("programmingService", ProgrammingServiceImpl.class);

        // 执行转账方法
        accountService.transfer(1, 2, BigDecimal.valueOf(100.00));
    }
}

声明式事务【重点】

业务层接口实现类

public class StatementServiceImpl implements AccountService {
    private AccountDao accountDao;

    @Override
    public void transfer(Integer from, Integer to, BigDecimal money) {
        // 减钱
        accountDao.decreaseMoney(to, money);

        System.out.println("发生了异常");
        int num = 1 / 0;

        // 加钱
        accountDao.increaseMoney(from, money);
    }

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}

applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
​
    <!--引入外部资源文件-->
    <context:property-placeholder location="jdbc.properties"/>
​
    <!--配置数据源-->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
​
    <!--声明事务管理器,封装了事务相关的所有操作,必须依赖于连接池-->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
​
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--声明指定的方法名以及事务的隔离级别,传播行为,是否只读-->
            <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
        </tx:attributes>
    </tx:advice>
​
    <!--配置AOP-->
    <aop:config proxy-target-class="true">
        <!--配置切点-->
        <aop:pointcut id="pointcut" expression="execution(* com.fc.service.impl.StatementServiceImpl.*(..))"/>
​
        <!--配置切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
​
    <!--依赖注入-->
    <bean name="accountDao" class="com.fc.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>
​
    <bean name="statementService" class="com.fc.service.impl.StatementServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
</beans>

测试类

public class AccountTest {
    // 测试声明式事务
    @Test
    public void testStatement() {
        // 获取IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 从Ioc容器中获取业务层对象
        AccountService accountService = applicationContext.getBean("statementService", StatementServiceImpl.class);
​
        // 执行转账方法
        accountService.transfer(1, 2, BigDecimal.valueOf(100.00));
    }
}

注解式事务【重点】

业务层接口实现类

// 使用注解声明该类中的所有方法都支持事务,此注解也可以配置在方法上
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, readOnly = false)
public class AnnotationServiceImpl implements AccountService {
    private AccountDao accountDao;

    @Override
    public void transfer(Integer from, Integer to, BigDecimal money) {
        // 减钱
        accountDao.decreaseMoney(to, money);

        System.out.println("发生了异常");
        int num = 1 / 0;

        // 加钱
        accountDao.increaseMoney(from, money);
    }

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
}

applicationContext.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
​
    <!--引入外部资源文件-->
    <context:property-placeholder location="jdbc.properties"/>
​
    <!--配置数据源-->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
​
    <!--声明事务管理器,封装了事务相关的所有操作,必须依赖于连接池-->
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!--开启注解式事务支持-->
    <tx:annotation-driven/>
​
    <!--依赖注入-->
    <bean name="accountDao" class="com.fc.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <bean name="annotationService" class="com.fc.service.impl.AnnotationServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
</beans>

测试类

public class AccountTest {
    // 测试注解式事务
    @Test
    public void testAnnotation() {
        // 获取IOC容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
​
        // 从Ioc容器中获取业务层对象
        AccountService accountService = applicationContext.getBean("annotationService", AccountService.class);
​
        // 执行转账方法
        accountService.transfer(1, 2, BigDecimal.valueOf(100.00));
    }
}

Spring 整合 Junit

概述

编写测试类时每次都要创建 Spring 容器,Spring 框架提供了一个运行器,通过读取配置文件或者注解的方式创建 Spring 容器。可以使用这个运行器替换掉 Junit 中自带的运行器来完成手动创建的工作。

相关注解

注解描述
@RunWith用于指定 junit 运行环境,是 junit 提供给其他框架测试环境接口扩展
@ContextConfiguration指定创建Spring容器的方式,常用属性为locations = "classpath:applicationContext.xml",或者classes = SpringConfig.class
@Transactional事务相关必须加上这个注解

案例代码

1、导入 pom.xml 中的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
​
    <groupId>com.fc</groupId>
    <artifactId>04_Spring_09_Junit</artifactId>
    <version>1.0-SNAPSHOT</version>
​
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
​
    <dependencies>
        <!--Spring核心依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.5</version>
        </dependency>
​
        <!--Spring-test-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.5</version>
        </dependency>
​
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
    </dependencies>
​
</project>

2、声明一个类并添加对应的注解

@Repository
public class UserDaoImpl {
    public void getUser() {
        System.out.println("获取一个学生对象");
    }
}

通过配置文件的方式

3、声明 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 http://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解扫描-->
    <context:component-scan base-package="com.fc"/>
</beans>

4、编写测试类

// 使用Spring的运行器替换Junit自带运行器,可以自动创建Spring容器对象
@RunWith(SpringJUnit4ClassRunner.class)
// 指定通过配置文件的方式创建Spring容器
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class XMLTest {
    // 依赖注入
    @Autowired
    private UserDaoImpl userDao;

    // 单元测试
    @Test
    public void test() {
        // 执行方法
        userDao.getUser();
    }
}

通过注解的方式

3、声明一个配置类

// 扫描指定包下的注解
@ComponentScan("com.fc")
// 声明配置类
@Configuration
public class SpringConfig {
}

4、编写测试类

// 使用Spring的运行器替换Junit自带运行器,可以自动创建Spring容器对象
@RunWith(SpringJUnit4ClassRunner.class)
// 指定通过配置类的方式创建Spring容器
@ContextConfiguration(classes = SpringConfig.class)
public class AnnotationTest {
    // 依赖注入
    @Autowired
    private UserDaoImpl userDao;
​
    // 单元测试
    @Test
    public void test() {
        userDao.getUser();
    }
}

补充:Spring 各 jar 包说明

jar描述
spring-aspectsSpring提供的对 AspectJ 框架的整合,内部使用的还是 aspectjweaver
spring-beansSpring IOC的基础实现,包含访问配置文件、创建和管理bean等
spring-context在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持,有邮件 服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持
spring-context-supportSpring context的扩展支持,用于MVC方面
spring-coreSpring的核心工具包
spring-expressionSpring表达式语言
spring-framework-bom统一各个 jar 包的版本,包含了所有的 Spring jar
spring-instrumentSpring 对服务器的代理接口
spring-jcl日志框架
spring-jdbc对 JDBC 的简单封装,操作数据库必须导入此依赖
spring-jms为简化 jms api 的使用而做的简单封装
spring-messaging为集成messaging api和消息协议提供支持
spring-orm整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
spring-oxmSpring 对于 object/xml 映射的支持,可以让JAVA与XML之间来回切换
spring-test对 JUNIT 等测试框架的简单封装
spring-tx为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理
spring-web包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类
spring-webmvc包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类
spring-websocket封装好的 WebSocket 框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值