Spring
1、简介
-
官网 : http://spring.io/
-
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
-
GitHub : https://github.com/spring-projects
-
Spring理念 : 使现有技术更加实用 ,本身就是一个大杂烩 , 整合现有的框架技术
-
Spring优点:是一个轻量级的**控制反转(IoC)和面向切面(AOP)**的容器(框架)
-
Spring七大模块
-
Spring Core:Spring核心模块,核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
-
Spring Context:Spring 上下文,是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
-
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
-
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
-
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
-
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
-
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
-
拓展:Spring Boot --> Spring Cloud --> Spring Cloud Data Flow
- Spring Boot
- 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务
- 专注于快速、方便集成的单个微服务个体
- 使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置
- Spring Boot可以离开Spring Cloud独立使用开发项目
- Spring Cloud
- 是基于Spring Boot实现的
- 关注全局的服务治理框架
- Spring Cloud离不开Spring Boot,属于依赖的关系
- Spring Boot
2、IOC控制反转
2.1、IOC原型
举个例子:当存在多个userDao对象时,需要使用哪个对象要在UserServiceImpl中创建,这种方式需要大量修改代码,耦合性高(UserServiceImpl1)。于是,我们可以在UserServiceImpl 中不去实现它 , 而是利用set留一个接口,业务层专注于业务的实现,不管理对象的创建,由调用者自行创建,耦合性大大降低 ,这也就是IOC的原型(UserServiceImpl2)。
- UserDao
public interface UserDao {
public void getUser();
}
- UserDaoImpl1
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
- UserDaoImpl2
public class UserDaoImpl2 implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
- UserService
public interface UserService {
public void getUser();
}
- UserServiceImpl1,直接创建userDao对象
public class UserServiceImpl implements UserService {
//直接创建
private UserDao userDao = new UserDaoImpl1();
@Override
public void getUser() {
userDao.getUser();
}
}
- UserServiceImpl2,利用set留一个接口,提供给调用者自行创建
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set实现
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
2.2、IOC本质
-
IOC是一种设计思想,DI(依赖注入)是实现IoC的一种方法
-
IoC是Spring框架的核心内容,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC
-
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象
-
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的
-
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)
-
所谓控制反转就是获得依赖对象的方式反转
3、第一个Spring程序
- pom.xml依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
- Hello实体类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
- spring配置文件,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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用Spring创建对象,在Spring中这些称为Bean
id:变量名
class:new的对象
property:给对象的属性设置值
-->
<bean id="hello" class="com.leijiao.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
- 测试类
@Test
public void test(){
//获取Spring的上下文对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
getBean : 参数即为spring配置文件中bean的id
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello);
}
- 分析
- Hello对象是由Spring创建的
- Hello对象属性是由Spring设置的
- 这个过程就叫控制反转
- 控制 : 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
- 反转 : 程序本身不创建对象 , 而变成被动的接收对象
- 依赖注入 : 就是利用set方法来进行注入的
- IOC是一种编程思想,由主动的编程变成被动的接收
- IOC就是对象由Spring 来创建 , 管理 , 装配
4、使用Spring修改2.1的案例
<?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="MysqlImpl" class="com.leijiao.dao.impl.UserDaoImpl1"/>
<bean id="OracleImpl" class="com.leijiao.dao.impl.UserDaoImpl2"/>
<bean id="UserServiceImpl" class="com.leijiao.service.impl.UserServiceImpl2">
<!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
<!--引用另外一个bean , 不是用value 而是用 ref-->
<property name="userDao" ref="MysqlImpl"/>
</bean>
</beans>
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
serviceImpl.getUser();
}
4、IOC创建对象方式
4.1、通过无参构造创建
- Hello实体类
public class Hello {
private String name;
public Hello() {
System.out.println("无参构造,测试该对象何时被创建");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
- 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用Spring创建对象,在Spring中这些称为Bean
id:变量名
class:new的对象
property:给对象的属性设置值
-->
<bean id="hello" class="com.leijiao.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
- 测试
@Test
public void test(){
//获取Spring的上下文对象
System.out.println("获取上下文对象");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//getBean : 参数即为spring配置文件中bean的id
System.out.println("getBean");
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello);
}
- 打印结果分析
- 从打印结果得出,在getBean之前Hello对象已经通过无参构造初始化
获取上下文对象
无参构造,测试该对象何时被创建
getBean
Hello{name='Spring'}
4.2、通过有参构造创建
- hello实体类
public class Hello {
private String name;
public Hello(String name) {
this.name = name;
System.out.println("有参构造,测试该对象何时被创建");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
- applicationContext.xml
- 有三方方法,选择其中一种
<!-- 第一种根据index参数下标设置 -->
<bean id="hello1" class="com.leijiao.pojo.Hello">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="method:index"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="hello2" class="com.leijiao.pojo.Hello">
<!-- name指参数名 -->
<constructor-arg name="name" value="name:vlue"/>
</bean>
<!-- 第三种根据参数类型设置(不建议使用) -->
<bean id="hello3" class="com.leijiao.pojo.Hello">
<constructor-arg type="java.lang.String" value="type:value"/>
</bean>
- 测试
@Test
public void test(){
//获取Spring的上下文对象
System.out.println("获取上下文对象");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//getBean : 参数即为spring配置文件中bean的id
System.out.println("getBean");
Hello hello = (Hello)context.getBean("hello1");
System.out.println(hello);
}
- 打印结果分析
- 从打印结果得出,在getBean之前Hello对象已经通过有参构造初始化
获取上下文对象
有参构造,测试该对象何时被创建
getBean
Hello{name='type:value'}
5、Spring配置
5.1、别名alias
- 设置别名:在获取Bean的时候可以使用别名获取
<alias name="hello2" alias="hello"></alias>
5.2、Bean
- bean就是java对象,由Spring创建和管理
- id 是bean的标识符,要唯一;name是 标识符或者别名
- 如果没有配置id,name就是默认标识符
- 如果配置id,又配置了name,那么name是别名
- name可以设置多个别名,可以用逗号、分号、空格隔开
- 如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象
- class是bean的全限定名=包名+类名
<bean id="hello" name="hello1,hello2,hello3" class="com.leijiao.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
5.3、import
团队的合作通过import来实现,可以将多个配置文件导入合并为1个
<import resource="{path}/beans1.xml"/>
<import resource="{path}/beans2.xml"/>
<import resource="{path}/beans3.xml"/>
6、DI依赖注入
- 依赖 : 指Bean对象的创建依赖于容器 ,Bean对象的依赖资源
- 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配
6.1、构造器注入
内容在章节4
6.2、set注入(重点)
6.2.1、环境准备
- Address实体类
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
- Student实体类
import java.util.*;
public class Student {
//覆盖多种类型属性
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
//此处是getter、setter
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
6.2.2、注入
常量注入、Bean注入、数组注入、List注入、Map注入、Set注入、null注入、Properties注入
- applicationContext.xml
<bean id="address" class="com.leijiao.pojo.Address"></bean>
<bean id="student" class="com.leijiao.pojo.Student">
<!--常量注入-->
<property name="name" value="leijiao"></property>
<!--Bean注入-->
<property name="address" ref="address"></property>
<!--数组注入-->
<property name="books">
<array>
<value>书名一</value>
<value>书名二</value>
<value>书名三</value>
</array>
</property>
<!--List注入-->
<property name="hobbys">
<list>
<value>兴趣1</value>
<value>兴趣2</value>
<value>兴趣3</value>
</list>
</property>
<!--Map注入-->
<property name="card">
<map>
<entry key="身份证" value="123456789"></entry>
<entry key="社保卡" value="987654321"></entry>
</map>
</property>
<!--Set注入-->
<property name="games">
<set>
<value>游戏1</value>
<value>游戏2</value>
<value>游戏3</value>
</set>
</property>
<!--null注入-->
<property name="wife">
<null/>
</property>
<!--Properties注入-->
<property name="info">
<props>
<prop key="学号">20210914</prop>
<prop key="性别">女</prop>
<prop key="姓名">leijiao</prop>
</props>
</property>
</bean>
- 测试
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
}
- 测试结果
Student{name='leijiao', address=com.leijiao.pojo.Address@17baae6e, books=[书名一, 书名二, 书名三], hobbys=[兴趣1, 兴趣2, 兴趣3], card={身份证=123456789, 社保卡=987654321}, games=[游戏1, 游戏2, 游戏3], wife='null', info={学号=20210914, 性别=女, 姓名=leijiao}}
6.3、p、c命名空间注入
6.3.1、P命名空间注入
- User实体类
public class User {
private String name;
private int age;
//此处是setter和getter
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- applicationContext.xml
<!--需要导入约束 : xmlns:p="http://www.springframework.org/schema/p"-->
<!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.leijiao.pojo.User" p:name="p命名空间注入" p:age="18"></bean>
6.3.2、c命名空间注入
c命名空间注入其实就是构造器注入!
- User实体类
public class User {
private String name;
private int age;
//c命名空间注入需要有参构造
public User(String name, int age) {
this.name = name;
this.age = age;
}
//此处是setter和getter
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- applicationContext.xml
<!--导入约束 : xmlns:c="http://www.springframework.org/schema/c"-->
<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.leijiao.pojo.User" c:name="c命名空间注入" c:age="18"></bean>
6.4、Bean作用域
<!--scope参数表示Bean的作用域,singleton,Prototype...-->
<bean id="user" class="com.leijiao.pojo.User" c:name="c命名空间注入" c:age="18" scope="singleton"></bean>
- singleton:单例模式,是Spring的默认机制。Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例
- prototype:原型模式,每次从容器getBean()时都会产生一个bean对象
- request、session、application只能在web开发中使用到
7、Bean的自动装配
- 自动装配是使用spring满足bean依赖的一种方法
- spring会在应用上下文中为某个bean寻找其依赖的bean
- spring三种装配方式
- xml显示配置(前几章节用到的都是这种)
- java显示配置
- 隐式的bean发现机制和自动装配
- 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean
- 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI
7.1、环境准备
- Cat实体类
public class Cat {
public void shout() {
System.out.println("喵喵喵");
}
}
- Dog实体类
public class Dog {
public void shout() {
System.out.println("汪汪汪");
}
}
- People实体类
public class People {
private Cat cat;
private Dog dog;
private String name;
//此处是getter和setter
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
- applicationContext.xml
<bean id="cat" class="com.leijiao.pojo.Cat"></bean>
<bean id="dog" class="com.leijiao.pojo.Dog"></bean>
<!--普通方法-->
<bean id="people" class="com.leijiao.pojo.People">
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
<property name="name" value="leijiao"></property>
</bean>
</bean>
- 测试
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
People people = (People)context.getBean("people");
people.getCat().shout();
people.getDog().shout();
}
7.1、xml的byName自动装配
autowire=“byName”:按名称自动装配
需要保证bean的id是唯一的,并且这个bean要和自动注入的对象属性的set方法的值一致!
<bean id="cat" class="com.leijiao.pojo.Cat"></bean>
<bean id="dog" class="com.leijiao.pojo.Dog"></bean>
<!--byName自动装配
会自动在容器上下文查找和自己对象set方法后面的值相同的Bean,如果有就取出注入,如果没有就报空指针异常
-->
<bean id="people" class="com.leijiao.pojo.People" autowire="byName">
<property name="name" value="leijiao"></property>
</bean>
7.2、xml的byType自动装配
autowire=“byType”:按类型自动装配
需要保证所有bean的class是唯一的,并且这个bean需要和自动注入的属性类型一致!
<bean id="cat" class="com.leijiao.pojo.Cat"></bean>
<bean id="dog" class="com.leijiao.pojo.Dog"></bean>
<!--byType自动装配
会自动在容器上下文查找和自己对象属性类型相同的Bean,如果有对应的就取出注入,如果没有就报空指针异常
-->
<bean id="people" class="com.leijiao.pojo.People" autowire="byType">
<property name="name" value="leijiao"></property>
</bean>
7.3、注解自动装配
前提:导入context约束,开启属性注解支持
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
7.3.1、@Autowired
@Autowired是按类型自动装配的,不支持id匹配。
- 修改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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!--这里不需要注入了-->
<bean id="cat" class="com.leijiao.pojo.Cat"></bean>
<bean id="dog" class="com.leijiao.pojo.Dog"></bean>
<bean id="people" class="com.leijiao.pojo.People"></bean>
</beans>
- 修改People实体类:set方法去掉,使用@Autowired注解
import org.springframework.beans.factory.annotation.Autowired;
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
//使用注解自动装配的方式,此处可以不需要setter了
//此处是getter和setter
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
7.3.2、@Qualifier
@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配,但是@Qualifier不能单独使用
- 修改applicationContext.xml:保证类型存在对象,且名字不为类的默认名字
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
- People实体类不加@Qualifier直接测试,会报错
- People实体类加上@Qualifier,测试通过
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class People {
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
private String name;
//使用注解自动装配的方式,此处可以不需要setter了
//此处是getter和setter
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
7.3.3、@Resource
@Resource如有指定的name属性,先按该属性进行byName方式查找装配。其次再进行默认的byName方式进行装配;如果以上都不成功,则按byType的方式自动装配。若都不成功,则报异常。
- 修改applicationContext.xml:
<bean id="dog" class="com.leijiao.pojo.Dog"></bean>
<bean id="cat1" class="com.leijiao.pojo.Cat"/>
<bean id="cat2" class="com.leijiao.pojo.Cat"/>
<bean id="people" class="com.leijiao.pojo.People"></bean>
- 修改People实体类:使用@Resource
import javax.annotation.Resource;
public class People {
//@Resource如有指定的name属性,先按该属性进行byName方式查找装配
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String name;
//使用注解自动装配的方式,此处可以不需要setter了
//此处是getter和setter
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
8、使用注解开发
若是发现注解无法使用,需要手动引入aop的包(spring-webmvc有的低版本不包含aop的包)
配置文件需要导入context约束,参考7.3
8.1、Bean的实现@Component
- 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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!-- 指定注解扫描包 -->
<context:component-scan base-package="com.leijiao.pojo"></context:component-scan>
</beans>
- User实体类:使用@Component注解
import org.springframework.stereotype.Component;
@Component("user")
public class User {
public String name = "leijiao";
}
- 测试
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User)context.getBean("user");
System.out.println(user.name);
}
8.2、属性值注入@Value
- 实体类没有set方法,直接在属性名上添加@value(“值”)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("user")
public class User {
@Value("leijiao")
public String name;
}
- 实体类有set方法,在set方法上添加@value(“值”)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("user")
public class User {
public String name;
@Value("leijiao")
public void setName(String name) {
this.name = name;
}
}
8.3、衍生注解
@Component有三个衍生注解,为了更好的进行分层,Spring可以使用其它三个注解,功能一样,写上这些注解,就相当于将这个类交给Spring管理装配
- @Controller:web层
- @Service:service层
- @Repository:dao层
8.4、自动装配注解
参考章节7.3
8.5、作用域@scope
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
@Controller("user")
@Scope("prototype")
public class User {
@Value("leijiao")
public String name;
}
8.4、xml和注解小结
- xml:更加万能,适用于任何场合,维护简单方便
- 注解:不是自己的类无法使用,维护相对复杂
- xml和注解整合开发:xml管理bean;注解完成属性注入;使用过程中, 可以不用扫描,扫描是为了类上的注解
9、使用JavaConfig配置Spring
使用JavaConfig配置Spring在spring boot中常用
9.1、例子
- User实体类
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component //将这个类标注为Spring的一个组件,放到容器中
public class User {
private String name;
public String getName() {
return name;
}
@Value("leijiao")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- JavaConfig配置类MyConfig
import com.leijiao.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//配置类
@Configuration
public class MyConfig {
//通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id
@Bean
public User getUser(){
return new User();
}
}
- 测试
@Test
public void test(){
//如果完全使用配置类的方式,只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
//Bean的id就是方法名getUser
User user = (User)context.getBean("getUser");
//输出User{name='leijiao'}
System.out.println(user);
}
9.2、导入其他配置
- 新建另外一个配置Myconfig2
public class Myconfig2 {
}
- 在Myconfig中导入Myconfig2
import com.leijiao.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//配置类
@Configuration
//导入其他配置
@Import(Myconfig2.class)
public class MyConfig {
//通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id
@Bean
public User getUser(){
return new User();
}
}
10、代理模式
10.1、静态代理
10.1.1、角色分析
角色分析
- 抽象角色 :一般使用接口或者抽象类来实现
- 真实角色:被代理的角色
- 代理角色:代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作
- 客户 : 使用代理角色来进行一些操作
10.1.2、例子1
房东要出租房子,交给中介来做,客户中介去找中介租房子。
- 抽象角色
//抽象角色:租房接口
public interface Abstract {
public void rent();
}
- 真实角色
//真实角色:房东,房东要出租房子
public class Host implements Rent{
@Override
public void rent() {
System.out.println("真实角色:房东,房东要出租房子");
}
}
- 代理角色
//代理角色:中介
public class Proxy {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
//租房
public void rent(){
seeHouse();
host.rent();
fare();
}
//看房
public void seeHouse(){
System.out.println("代理角色:中介,带房客看房");
}
//收中介费
public void fare(){
System.out.println("代理角色:中介,收中介费");
}
}
- 客户
//客户类,一般客户都会去找代理!
public class Client {
public static void main(String[] args) {
//房东要租房
Host host = new Host();
//中介帮助房东
Proxy proxy = new Proxy(host);
//你去找中介!
proxy.rent();
}
}
10.1.3、例子2
用户业务接口(增删改查)、用户实现接口业务、代理新增日志功能(在不改变原来的代码的情况下,实现了对原有功能的增强,即AOP的核心思想)
- 抽象角色
//抽象角色:用户业务接口,增删改查
public interface UserService {
void add();
void delete();
void update();
void query();
}
- 真实角色
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
- 代理角色
//代理角色,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
- 客户
//客户类
public class Client {
public static void main(String[] args) {
//真实业务
UserServiceImpl userService = new UserServiceImpl();
//代理类
UserServiceProxy proxy = new UserServiceProxy();
//使用代理类实现日志功能!
proxy.setUserService(userService);
proxy.add();
}
}
10.1.4、优缺点
静态代理的优点
- 可以使得我们的真实角色更加纯粹 ,不再去关注一些公共的业务
- 公共的业务由代理来完成 ,实现了业务的分工
- 公共业务发生扩展时,方便集中管理
静态代理的缺点
- 一个真实角色就会产生一个代理角色,代码量会大,开发效率变低(使用动态代理解决)
10.2、动态代理
在不改变原来的代码的情况下,实现了对原有功能的增强是AOP的核心思想
核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口
-
动态代理的角色和静态代理的一样
-
动态代理的代理类是动态生成的,静态代理的代理类是我们提前写好的
-
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK
- 基于类的动态代理----cglib
- 现在用的比较多的是 javasist 来生成动态代理
以下的例子是JDK接口动态代理,需要了解两个类(jdk帮助文档)
- InvocationHandler:调用处理程序
- Proxy :代理
10.2.1、例子1(改造10.1.2)
- 抽象角色(不变)
//抽象角色:租房
public interface Rent {
public void rent();
}
- 真实角色(不变)
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
- 代理角色(变化)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//使用这个类,自动生成一个代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
/**
* 生成代理类
* @return
*/
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);
}
/**
* 处理代理实例并返回结果
* @param proxy 代理类
* @param method 代理类的调用处理程序的方法对象
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
- 客户
//客户
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象
pih.setRent(host);
//动态生成代理类
Rent proxy = (Rent)pih.getProxy();
proxy.rent();
10.2.2、例子2(改造10.1.2)
- 抽象角色(不变)
- 真实角色(不变)
- 代理角色(变化)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
//写一个通用的动态代理实现的类!所有的代理对象设置为Object即可
private Object obj;
public void setObj(Object obj) {
this.obj = obj;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.log(method.getName());
Object invoke = method.invoke(obj, args);
return invoke;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
- 客户
//客户
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理实例的调用程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象
pih.setObj(userService);
//动态生成代理类
UserService proxy = (UserService)pih.getProxy();
proxy.add();
}
}
10.2.3、优点
- 可以使得我们的真实角色更加纯粹,不再去关注一些公共的事情 (同静态代理)
- 公共的业务由代理来完成 ,实现了业务的分工 (同静态代理)
- 公共业务发生扩展时,方便集中管理(同静态代理)
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,代理的是接口
11、AOP面向切面
11.1、概念
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
11.2、在Spring中的作用
提供声明式事务;允许用户自定义切面
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
-
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
-
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- Spring中支持5种类型的Advice
-
目标(Target):被通知对象。
-
代理(Proxy):向目标对象应用通知之后创建的对象。
-
切入点(PointCut):切面通知 执行的 “地点”的定义。
-
连接点(JointPoint):与切入点匹配的执行点。
11.3、在Spring中实现AOP
pox.xml依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.M1</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
11.3.1、方式一(Spring API)
通过 Spring API 实现
- 接口
public interface UserService {
void add();
void delete();
void update();
void query();
}
- 接口实现类
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
- 前置增强接口实现类
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
/**
* 前置增强
* @param method 要执行的目标对象的方法
* @param objects 目标对象的方法参数
* @param o 目标对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"方法被执行了!");
}
}
- 后置增强接口实现类
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
/**
* 后置增强
* @param o 返回值
* @param method 被调用的方法
* @param objects 被调用的方法的对象的参数
* @param o1 被调用的目标对象
* @throws Throwable
*/
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回值是"+o+"!");
}
}
- 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean -->
<bean id="userService" class="com.leijiao.service.UserServiceImpl"></bean>
<bean id="beforeLog" class="com.leijiao.log.BeforeLog"></bean>
<bean id="afterLog" class="com.leijiao.log.AfterLog"></bean>
<!-- 方式一 -->
<!-- 配置aop,需要导入约束 -->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.leijiao.service.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
- 测试
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//getBean("userService", UserService.class)这样就不需要强转类型
//动态代理,这边需要getBean的是接口userService,不是UserServiceImpl
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
11.3.2、方式二(自定义切面类)
自定义类来实现Aop
- 不需要前置增强和后置增强,直接自定义切入类
//自定义切入类
public class DiyPointcut {
public void before(){
System.out.println("---------方法执行前---------");
}
public void after(){
System.out.println("---------方法执行后---------");
}
}
- applicationContext.xml,自定义切面—>设置切入点—>通知什么时候执行
<!-- 注册bean -->
<bean id="userService" class="com.leijiao.service.UserServiceImpl"></bean>
<bean id="beforeLog" class="com.leijiao.log.BeforeLog"></bean>
<bean id="afterLog" class="com.leijiao.log.AfterLog"></bean>
<bean id="diyPointcut" class="com.leijiao.diy.DiyPointcut"></bean>
<!-- 方式二 -->
<!-- 配置aop,需要导入约束 -->
<aop:config>
<!-- 自定义切面,ref=要引用的类 -->
<aop:aspect ref="diyPointcut">
<!-- 切入点 -->
<aop:pointcut id="point" expression="execution(* com.leijiao.service.UserServiceImpl.*(..))"/>
<!-- 通知 -->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
11.3.3、方式三(注解)
使用注解实现
- 自定义注解切面
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//使用注解标记这是一个切面类
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.leijiao.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前---------");
}
@After("execution(* com.leijiao.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
//在环绕增强中,可以给定一个参数,代表我们要获取切入的点
@Around("execution(* com.leijiao.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("---------环绕前---------");
//签名就是方法
System.out.println("签名:"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("---------环绕后---------");
System.out.println(proceed);
}
}
- applicationContext.xml,注册bean,开启注解支持即可
<!-- 方式三 -->
<bean id="userService" class="com.leijiao.service.UserServiceImpl"></bean>
<bean id="annotationPointcut" class="com.leijiao.diy.AnnotationPointcut"></bean>
<!-- 开启注解支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
12、整合Mybatis
12.1、依赖
- pom.xml依赖
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- mysql -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- spring相关 -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- aspectJ AOP 织入器 -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8.M1</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
<!-- mybatis-spring整合包 -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
12.2、方式一
- mybatis-config.xml(mybatis核心配置)
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 数据源参数在spring配置文件中写 -->
</dataSource>
</environment>
</environments>
<mappers>
<!--注册mapper,在spring配置文件中写-->
</mappers>
</configuration>
- applicationContext.xml(spring配置)
<?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 id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--关联Mybatis-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/leijiao/mapper/*.xml"/>
</bean>
<!-- 注册sqlSessionTemplate,关联sqlSessionFactory -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--利用构造器注入-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
- pojo实体类User
//user表的实体类
public class User {
private int id; //id
private String name; //姓名
private String password; //密码
//构造器
public User(int id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
//此处是get set
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
- UserMapper接口
import com.leijiao.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
}
- UserMapper.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.leijiao.mapper.UserMapper">
<select id="selectUser" resultType="com.leijiao.pojo.User">
select * from user
</select>
</mapper>
- UserMapperImpl接口实现类
import com.leijiao.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//sqlSession不用我们自己创建了,Spring来管理
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
- 到spring配置中注册bean
<!-- 注册bean -->
<bean id="userMapper" class="com.leijiao.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
- 测试
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> users = userMapper.selectUser();
for (User user : users) {
System.out.println(user);
}
}
12.3、方式二
接口实现类继承SqlSessionDaoSupport类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory。比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好
- 新增UserMapperImpl2接口实现类
import com.leijiao.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
//接口实现类继承SqlSessionDaoSupport
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
//不需要管理SqlSessionTemplate,直接getSqlSession()获得
@Override
public List<User> selectUser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.selectUser();
}
}
- 到spring配置中注册bean
<bean id="userMapper2" class="com.leijiao.mapper.UserMapperImpl2">
<!--不需要注入sqlSession,只要注入sqlSessionFactory即可-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
- 测试
@Test
public void test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
List<User> users = userMapper.selectUser();
for (User user : users) {
System.out.println(user);
}
}
13、声明式事务
13.1、ACID原则
事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用
事务四个属性ACID
-
原子性(atomicity):事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
-
一致性(consistency):一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
-
隔离性(isolation):可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
-
持久性(durability):事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
13.2、Spring中的事务管理
13.2.1、编程式事务管理
-
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
-
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
13.2.2、声明式事务管理
-
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
-
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理
-
使用方法
- spring配置导入约束
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
- spring配置事务
<!--配置声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!--结合AOP实现事务的织入--> <!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--配置哪些方法使用什么样的事务,配置事务的传播特性propagation--> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置aop织入事务--> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.leijiao.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>
l
- 测试
```java
@Test
public void test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
List<User> users = userMapper.selectUser();
for (User user : users) {
System.out.println(user);
}
}
13、声明式事务
13.1、ACID原则
事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用
事务四个属性ACID
-
原子性(atomicity):事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
-
一致性(consistency):一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
-
隔离性(isolation):可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
-
持久性(durability):事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
13.2、Spring中的事务管理
13.2.1、编程式事务管理
-
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
-
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
13.2.2、声明式事务管理
-
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
-
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理
-
使用方法
- spring配置导入约束
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
- spring配置事务
<!--配置声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!--结合AOP实现事务的织入--> <!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--配置哪些方法使用什么样的事务,配置事务的传播特性propagation--> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置aop织入事务--> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* com.leijiao.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>