一、Spring简介
1、简介
2002年,首次推出Spring框架的雏形:interface21框架
Spring框架是以interface21框架为基础,经过重新设计、不断丰富内涵,于2004年3月24日发布了1.0正式版
Spring理念:使现有技术更加容易使用,整合了现有的技术框架
SSH:Struct2 + Spring + Hibernate
SSM:SpringMVC + Spring + Mybatis
Maven依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
2、优点
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级、非入侵式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
总结:==Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架==
3、组成
-
Spring---七大核心模块
image
4、拓展
-
Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速开发单个微服务
- 约定大于配置
-
Spring Cloud
- SpringCloud是基于SpringBoot实现
Spring弊端:配置繁琐
二、IOC理论
1、 IOC原型
- 以往的实现步骤
- XXX Dao
- XXX DaoImpl
- XXX Service
- XXX ServiceImpl
- XXX Servlet
存在问题
(1)当Service层调用Dao层时,Dao层会有许多不同的实现类,是根据不同业务而实现的,那么Service层会在调用时出现:选择实现类的问题。
(2)假如Service的实现类,来选择某一个Dao层实现类,由ServiceImpl来创建对应的DaoImpl实例对象,那么ServiceImpl就只能有一个具体的Dao层实现类。
(3)可是当需要使用其他Dao层实现类,我们需要去改变ServiceImpl中的DaoImpl对象
(4)这样程序的耦合性高
控制反转(思想)
假如我们Service层不再实例化一个具体的DaoImpl对象,即程序员不用根据不同的需求而跑到Service层选择不同的DaoImpl类而创建对象
将对象的创建交给更上一层,调用Service层的 Servlet层去确定要使用哪一个DaoImpl类,直接创建并且传入给Service层即可
程序对象创建的主动权,交给了用户。至此,程序员不用管理对象的创建,系统的耦合性降低
-
左边为:业务层决定调用的对象;右边为:用户层决定让业务层去调用某个对象
image
- 控制反转(思想)代码演示:
- 通过Set注入一个UserDao对象,程序不再具有主动性,而是变成被动的接收对象
public class UserServiceImpl implements UserService {
//引入Dao层
private UserDao userDao = null;
//由创建该对象的实例对象决定使用那一个UserDao
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
//通过Set注入一个UserDao对象,程序不再具有主动性,而是变成被动的接收对象
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
2、IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法。
- 没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制
- 控制反转后,将对象的创建转移给第三方:获得依赖对象的方式反转了
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)
3、HelloSpring
- Hello.java
- 注意:要有无参的构造方法以及参数的set方法
public class Hello {
String str = null;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
- beans.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">
<!--
类型 变量名 = new 类型();
Hello hello = new Hello();
id = 变量名
class = 全类名
property 相当于给对象中的属性设置一个值
-->
<!--使用Spring来创建对象,在Spring这些都称为Bean-->
<bean id="hello" class="com.vigil.pojo.Hello">
<property name="str" value="Spring"></property>
</bean>
</beans>
- Test.java
import com.vigil.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
//获取Spring的上下文对象,解析beans.xml文件,生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//对象都由Spring管理,使用的时候直接取出来使用
//getBean:参数即为spring配置文件中的bean的id
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
这一系列的过程就叫控制反转
-
控制:控制对象的创建
- 传统应用程序的对象是由程序本身控制创建
- 使用Spring后,对象是由Spring来创建
反转:程序本身不创建对象,而变为被动的接收对象
依赖注入:利用set方法来进行注入
IOC是一种编程思想,是由主动的编程编程被动的接收
利用Spring,不用在程序中去改动,要实现不同的操作,只需要在xml配置文件中进行修改,所谓IoC:对象由Spring创建、管理、装配
4、对User实现的修改
- UserServiceImpl
public class UserServiceImpl implements UserService {
//引入Dao层
private UserDao userDao = null;
// public UserServiceImpl(UserDao userDao) {
// this.userDao = userDao;
// }
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
- beans.xml(ApplicationContext)
<?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="Mysql" class="com.vigil.dao.UserDaoMysqlImpl"></bean>
<bean id="SqlServer" class="com.vigil.dao.UserDaoSqlServerImpl"></bean>
<!--
ref:引用Spring容器中创建好的对象
value:具体的值,是基本数据类型
-->
<bean id="UserService" class="com.vigil.service.UserServiceImpl">
<property name="userDao" ref="Mysql"></property>
</bean>
</beans>
- Test.java
public class Test {
public static void main(String[] args) {
// UserService userService = new UserServiceImpl(new UserDaoSqlServerImpl());
// userService.getUser();
//获取ApplicationContext:拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//利用容器获得对象
UserService userService = (UserService) context.getBean("UserService");
userService.getUser();
}
}
三、IOC创建对象的方式
- 使用无参构造创建对象,这是默认的!
- 使用有参构造创建对象
1、第一种方式:下标赋值
2、通过类型创建,但不建议使用,影响多态的实现
3、第三种方式:直接通过参数名来设置
- 注意:bean的id不可重复
<?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="User" class="com.vigil.pojo.User">
<property name="name" value="你好测试"></property>
</bean>
<!--有参构造
第一种方式:下标赋值-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg index="0" value="测试一"></constructor-arg>
</bean>
<!--第二种方式:通过类型创建,但不建议使用,影响多态的实现-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg type="java.lang.String" value="测试二"></constructor-arg>
</bean>
<!--第三种方式:直接通过参数名来设置-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg name="name" value="测试三"></constructor-arg>
</bean>
</beans>
- 总结:
在配置文件加载的时候,容器中管理的对象就已经初始化了
四、Spring配置
1、别名
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg name="name" value="测试三"></constructor-arg>
</bean>
<!--别名,如果添加了别名,我们也可以使用别名获取到这个对象-->
<!--这里的name指向id是这个值的bean-->
<alias name="User" alias="userName"></alias>
2、Bean配置
- 在 bean 定义本身中,可以使用id属性指定的最多一个名称和name属性中任意数量的其他名称的组合来为 bean 提供多个名称。
<!--
id:bean 的唯一标识符,也就是相当于对象名
class:bean 对象所对应的全限定名:包名加类名
name:别名,而且name可以同时取多个别名
-->
<bean id="User" class="com.vigil.pojo.User" name="user,u1,userUser">
<constructor-arg name="name" value="测试三"></constructor-arg>
</bean>
3、import
- 将多个配置文件导入合并为一个
<?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">
<import resource="beans.xml"></import>
<import resource="beans2.xml"></import>
</beans>
五、依赖注入
1、构造器注入
(1) 使用无参构造创建对象,这是默认的!
<!--默认的无参构造-->
<bean id="User" class="com.vigil.pojo.User">
<property name="name" value="你好测试"></property>
</bean>
(2) 使用有参构造创建对象
- 1)第一种方式:下标赋值
<!--有参构造
第一种方式:下标赋值-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg index="0" value="测试一"></constructor-arg>
</bean>
- 2)通过类型创建,但不建议使用,影响多态的实现
<!--第二种方式:通过类型创建,但不建议使用,影响多态的实现-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg type="java.lang.String" value="测试二"></constructor-arg>
</bean>
- 3)第三种方式:直接通过参数名来设置
<!--第三种方式:直接通过参数名来设置-->
<bean id="User" class="com.vigil.pojo.User">
<constructor-arg name="name" value="测试三"></constructor-arg>
</bean>
2、Set方式注入
- 依赖注入:Set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中所有的属性,都由容器来注入
【环境搭建】
- 复杂类型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
- 真实对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String,String> care;
private Set<String> games;
private String wife;
private Properties info;
}
- beans.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">
<!--第一种,普通类型值的注入,value-->
<bean id="student" class="com.vigil.pojo.Student" name="Student">
<property name="name" value="测试"></property>
</bean>
</beans>
- 测试类
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
}
}
- 完善
<?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="address" class="com.vigil.pojo.Address">
<property name="address" value="东百坡"></property>
</bean>
<bean id="student" class="com.vigil.pojo.Student" name="Student">
<!--第一种,普通类型值的注入,value-->
<property name="name" value="测试"></property>
<!--第二种,Bean注入,ref-->
<property name="address" ref="address"></property>
<!--数组-->
<property name="books">
<array>
<value>三国演义</value>
<value>红楼梦</value>
<value>西游记</value>
<value>红楼梦</value>
</array>
</property>
<!--List-->
<property name="hobbies">
<list>
<value>听歌</value>
<value>看电影</value>
<value>敲代码</value>
<value>玩游戏</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="12345678"></entry>
<entry key="银行卡" value="3232121"></entry>
</map>
</property>
<!--Set-->
<property name="games">
<set>
<value>API</value>
<value>LOL</value>
<value>COC</value>
</set>
</property>
<!--null-->
<property name="wife">
<null></null>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="学号">19120501</prop>
<prop key="性别">男</prop>
<prop key="姓名">楚名</prop>
</props>
</property>
</bean>
</beans>
3、拓展注入
(1) p-namespace :
使用bean元素的属性(而不是嵌套的<property/>元素)来描述协作 Bean 的属性值,或同时使用这两者,相当于set注入
(2) c-namespace
c:
命名空间执行与基于构造函数的依赖注入相同的操作,相当于构造器注入
- 代码实现
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.vigil.pojo.User" p:name="你好User" p:age="12"></bean>
<!--c命名空间注入,通过构造器注入:construct-args-->
<bean id="userConstructor" class="com.vigil.pojo.User" c:name="HelloUsesr" c:age="23"></bean>
</beans>
- 测试代码
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = (User) context.getBean("userConstructor");
System.out.println(user.toString());
- 注意:
要加入的一段代码:xml约束
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
4、Bean的作用域
Scope | Description |
---|---|
singleton | (默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。 |
prototype | 将单个 bean 定义的作用域限定为任意数量的对象实例。 |
request | 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在web的 Spring ApplicationContext 中有效。 |
session | 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在web的 Spring ApplicationContext 上下文中有效。 |
application | 将单个 bean 定义的范围限定为ServletContext 的生命周期。仅在web的 Spring ApplicationContext 上下文中有效。 |
websocket | 将单个 bean 定义的范围限定为WebSocket 的生命周期。仅在web的 Spring ApplicationContext 上下文中有效。 |
- 单例模式(Spring默认机制)
<bean id="user" class="com.vigil.pojo.User" p:name="你好User" p:age="12" scope="singleton"></bean>
- 原型模式:每次都从容器中get的时候,都会产生一个新的对象
<bean id="userConstructor" class="com.vigil.pojo.User" c:name="HelloUsesr" c:age="23" scope="prototype"></bean>
- 其余的 request、session、application、websocket,这些只能在web开发中使用到
六、Bean的自动装配
自动装配模式
Mode | Explanation |
---|---|
no | (默认)无自动装配。 Bean 引用必须由ref元素定义。对于大型部署,建议不要更改默认设置,因为明确指定协作者可以提供更好的控制和清晰度。在某种程度上,它记录了系统的结构。 |
byName | 按属性名称自动布线。 Spring 寻找与需要自动装配的属性同名的 bean。例如,如果一个 bean 定义被设置为按名称自动装配,并且包含一个master属性(即,它具有setMaster(..)方法),那么 Spring 将查找一个名为master的 bean 定义并使用它来设置属性。 |
byType | 如果容器中恰好存在一个该属性类型的 bean,则使该属性自动装配。如果存在多个错误,则会引发致命异常,这表明您可能不对该 bean 使用byType自动装配。如果没有匹配的 bean,则什么也不会发生(未设置该属性)。 |
constructor | 类似于byType,但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个 bean,则将引发致命错误。 |
- 自动装配:Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
- 在xml中显式的配置
- 在Java中显式配置
- 隐式 的自动装配bean【重要】
1、测试
(1) 环境搭配: 一个人有两个宠物
- Cat.java
public class Cat {
public void show() {
System.out.println("mao~");
}
}
- Dog.java
public class Dog {
public void show() {
System.out.println("hu~");
}
}
- Person.java
public class Person {
private Cat cat;
private Dog dog;
private String name;
}
- beans.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="dog" class="com.vigil.pojo.Dog"></bean>
<bean id="cat" class="com.vigil.pojo.Cat"></bean>
<bean id="person" class="com.vigil.pojo.Person">
<property name="name" value="鱼佬"></property>
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
</beans>
- Test.java
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person.getName());
person.getDog().show();
person.getCat().show();
}
}
2、ByName自动装配
<bean id="dog" class="com.vigil.pojo.Dog"></bean>
<bean id="cat" class="com.vigil.pojo.Cat"></bean>
<!--byName:会自动在容器上下文中查找,和该对象set方法后面的值所对应的 beanid
经检验,确实是SET后面的字符串,和形参、类型都没关系-->
<bean id="person" class="com.vigil.pojo.Person" autowire="byName">
<property name="name" value="鱼佬"></property>
</bean>
3、ByType自动装配
<bean class="com.vigil.pojo.Dog"></bean>
<bean class="com.vigil.pojo.Cat"></bean>
<!--byType:会自动在容器上下文中查找,和该对象属性类型相同的bean
所以上下文中要保证该类型全局唯一-->
<bean id="person" class="com.vigil.pojo.Person" autowire="byType">
<property name="name" value="鱼佬"></property>
</bean>
- 小结
- 使用byName:需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
- 使用byType:需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
4、使用注解实现自动装配
- 导入约束:context
- 配置注解的 支持: <context:annotation-config/>
<?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:annotation-config/>
</beans>
1)@Autowired
public @interface Autowired {
boolean required() default true;
}
直接在属性上使用即可,也可以在set方式上使用
使用 Autowired ,则可以不用编写set方法,前提是:这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname
2)@Qualifier
public @interface Qualifier {
String value() default "";
}
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,可以使用@Qualifier (value = "xxx") 去配合@Autowired的使用,指定唯一的bean对象注入(value是beanid)
3)@Resource
@Resource和@Autowired的区别
- 都是用来自动装配的,都可以放到属性字段上
- @Autowired 通过byType的方式实现,而且必须要求这个对象存在,常用
- @Resource 默认通过byName的方式实现,如果找不到名字,则通过byType实现。如果两种方式都无法找到,会报错
- 执行顺序不同:@Autowired 通过byType的方式实现;@Resource 通过byName方式实现
- Test
- beans.xml
<bean id="cat" class="com.vigil.pojo.Cat"></bean>
<bean id="cat2" class="com.vigil.pojo.Cat"></bean>
<bean id="dog" class="com.vigil.pojo.Dog"></bean>
<bean id="dog23" class="com.vigil.pojo.Dog"></bean>
<bean id="person" class="com.vigil.pojo.Person"></bean>
- Person.java
public class Person {
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Resource(name = "dog")
private Dog dog;
private String name;
}
七、使用注解开发
在Spring4后,要使用注解开发,必须要保证 aop包的导入
使用注解还需要导入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
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:annotation-config/>
</beans>
bean
属性如何注入
//等价于: <bean id="user" class="com.vigil.pojo.User"></bean>
//@Component组件:放在类上,说明这个类被Spring管理了,bean
@Component
public class User {
private String name = "默认测试";
public String getName() {
return name;
}
//相当于<property name="name" value="鱼佬"></property>
@Value("鱼佬")
public void setName(String name) {
this.name = name;
}
}
- 衍生的注解
@Component有几个衍生作用域,按照mvc分层
- dao【@Repository】
- service【@Service】
- controller【@Controller】
这四个注解功能一致,都是代表将某个类注册到Spring中,装配bean
-
自动装配
1)@Autowired
直接在属性上使用即可,也可以在set方式上使用
使用 Autowired ,则可以不用编写set方法,前提是:这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname2)@Qualifier
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,可以使用@Qualifier (value = "xxx") 去配合@Autowired的使用,指定唯一的bean对象注入(value是beanid)3)@Resource
@Resource 默认通过byName的方式实现,如果找不到名字,则通过byType实现。如果两种方式都无法找到,会报错 作用域
@Component
//@Scope("singleton")
@Scope("prototype")
public class User {
}
- 小结
- xml和注解:
- xml更加万能,适用于任何场合,维护简单方便
- 注解 维护相对复杂
- xml 与注解的最佳分配
- xml用来管理bean
- 注解只负责属性的注入
- 必须让注解生效,就需要开启注解的支持
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.vigil"></context:component-scan>
<context:annotation-config/>
八、使用JavaConfig实现配置
纯Java可以完成Spring的配置
JavaConfig 是Spring的子项目,在Spring 4 之后,他成为了核心功能
使用@Configuration 声明配置类时有两种方法来生成bean
方法一:在配置类中定义一个方法,并使用 @Bean 注解声明
方法二:在类上使用 @Component注解,并在配置类上声明 @ComponentScan("类的路径"),这样会自动扫描 @Component并生成bean
配置文件(配置类)
// 这个也会由Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration 代表这是一个配置类,相当于applicationContext.xml
@Configuration
@Component("com.vigil.pojo")
//将其他配置文件融合到当前的类中
@Import(com.vigil.config.VigilConfig.class)
public class VigilConfig {
//注册一个bean,就相当于 bean标签
//方法名,相当于bean标签中的id属性
//方法返回值,相当于bean标签的class属性
@Bean
public User getUser() {
return new User();//返回要注入的bean对象
}
}
- 实体类
public class User {
private String name;
public String getName() {
return name;
}
@Value("鱼佬")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- Test
public class Test {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,就只能通过 AnnotationConfig 上下文来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(VigilConfig.class);
User user = (User) context.getBean("getUser");
System.out.println(user.getName());
}
}
九、代理模式
代理模式是:SpringAOP的底层(面向切面编程)
- 代理分类 (核心:多态)
- 静态代理
- 动态代理
1、静态代理
1)角色分析
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,一般会有附属的操作
- 客户:访问代理对象的人
2)演示住房中介
代码步骤:
- 接口(出租者)
public interface Leaser {
public abstract void lease();
}
- 真实角色(房东)
public class Landlord implements Leaser {
public void lease() {
System.out.println("I have a room to lease");
}
}
- 代理角色(出租房屋中介)
public class RentalAgent implements Leaser {
private Leaser landlord;//中介聚合多个房东:Leaser[]
public RentalAgent() {
}
public RentalAgent(Leaser landlord) {
this.landlord = landlord;
}
public void setLandlord(Leaser landlord) {
this.landlord = landlord;
}
public void lease() {
//调用用户需要的房子,的房东
landlord.lease();
//帮助房东完成租房合同的签写
contract();
//帮助房东收取租金
rent();
}
// 签写租凭合同
public void contract() {
System.out.println("to sign a contract");
}
// 收取租金
public void rent() {
System.out.println("delivery of the rent");
}
}
- 客户(租房者):访问代理角色
public class Lessee {
public static void main(String[] args) {
//租房找中介
RentalAgent agent = new RentalAgent();
//看中了某个房子
//让中介去联系这个房东,是否能租房,不需要客户去联系,客户看房间就行
agent.setLandlord(new Landlord());
agent.lease();
}
}
静态代理模式的好处
- 可以使真实角色的操作更加纯粹,不用关心公共业务
- 公共业务就交给代理角色,实现业务分工
- 公共业务发生拓展时,方便集中管理
缺点
- 一个真实角色就会产生一个代理角色,代码量翻倍、开发效率变低
2、动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的
- 动态代理分为两大类:基于接口的动态代理、基于类的动态代理
- 基于接口 --- JDK动态代理
- 基于类:cgilb
- Java字节码实现:javasist
JDK动态代理 两个重要的两个类
- Proxy:代理
- InvocationHandler:调用处理程序
测试例子
1)角色分析
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,一般会有附属的操作
- 客户:访问代理对象的人
2)演示住房中介
动态代理的代码步骤:
- 出租者接口
public interface Leaser {
public abstract void lease();
}
- 出租者实例:房东
public class Landlord implements Leaser {
public void lease() {
System.out.println("I have a room to lease");
}
}
- 出租者代理:出租中介(与静态代理最不同的地方)
注意:实现了InvocationHandler 接口
要有要被代理的接口的注入
要有得到代理类的方法,也就是调用了Proxy.newProxyInstance() 得到一个代理类
因为继承了Invocation,所以invoke() 方法是要实现的
在invoke() 方法里,要调用传入的method对象的invoke() 方法
//自动生成代理类,要实现接口Invocation
public class ProxyInvocationHandler implements InvocationHandler {
// 1.被代理的接口
private Object target;
// 2.注入要代理的接口实现类实例对象
public void setTarget(Object target) {
this.target = target;
}
// 3.生成代理类:指定由指定的类装入器定义的代理类的指定调用处理程序的代理实例,并实现指定的接口
public Object getProxy() {
//Proxy创建动态代理类的实例提供了静态方法,也是所有动态代理类的父类的方法创建
// this.getClass().getClassLoader():loader的类装载器来定义代理类
// target.getClass().getInterfaces():interfaces -为代理类实现的接口列表
// this:InvocationHandler -调用处理程序调度方法调用
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
// 4.处理代理类实例,返回结果
// 在代理实例上处理方法调用,并返回结果。
// 当在与它关联的代理实例上调用方法时,该方法将在调用处理程序上调用此方法。
// 参数:
//proxy -代理实例,调用的方法
//对接口方法的调用相应的 method代理实例的 方法实例。声明类的 方法对象将接口的方法声明,这可能是一个超接口代理接口,代理类继承的方法。
//args -包含在方法上通过代理实例调用的实参的值对象的数组,或 null如果接口方法不需要参数。原始类型的实参是包裹在适当的原始包装类的实例,如 java.lang.Integer或 java.lang.Boolean。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,使用反射机制
Object result = method.invoke(target, args);
contract();
rent();
return null;
}
// 签写租凭合同
public void contract() {
System.out.println("to sign a contract");
}
// 收取租金
public void rent() {
System.out.println("delivery of the rent");
}
}
- 用户
注意:要有一个被代理的对象,然后注入给代理角色处理类,再得到一个被代理的代理实例,最后才能调用代理实例的方法
public class Lessee {
public static void main(String[] args) {
//真实角色
Leaser landlord = new Landlord();
//代理角色处理类
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色,来处理将要被调用的接口(被代理的接口)
pih.setTarget(landlord);//设置要代理的对象
Object obj;
if((obj = pih.getProxy()) instanceof Leaser) {
((Leaser)(obj)).lease();
}
}
}
动态代理模式的好处
- 可以使真实角色的操作更加纯粹,不用关心公共业务
- 公共业务就交给代理角色,实现业务分工
- 公共业务发生拓展时,方便集中管理
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务
十、AOP
1、什么是AOP
1)AOP (Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
2)AOP 是 OOP 的延续,是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
3)利用AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发的效率
image
2、AOP 在Spring中的作用
提供声明式事务;允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。即是:与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如:日志,安全,缓存,事务等
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。是一个类
- 通知(Advice):切面必须要完成的工作。是类中的方法
- 目标(Target):被统治的对象
- 代理(Proxy):向目标对象应用通知之后创建的对象
- 切入点(PointCut):切面通知 执行的”地点“的定义
- 连接点(JointPoint):与切入点匹配的执行点
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5中类型的Advice:
通知类型 | 连接点 | 实现接口 |
---|---|---|
前置通知 | 方法前 | org.springframework.aop.MethodBeforeAdvice |
后置通知 | 方法后 | org.springframework.aop.AfterReturningAdvice |
环绕通知 | 方法前后 | org.aopalliance.intercept.MethodInterceptor |
异常抛出通知 | 方法抛出异常 | org.springframework.aop.ThrowsAdvice |
引介通知 | 类中增加新的方法属性 | org.springframework.aop.IntroductionInterceptor |
即 AOP 在不改变原有代码的情况下,去增加新的功能
3、使用Spring实现AOP
【重点】使用AOP织入,需要导入一个依赖包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
(1) 使用Spring的API接口【主要SpringAPI接口实现】
- UserService
public interface UserService {
public void add();
public void update();
public void delete();
public void query();
}
- UserServiceImpl
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void update() {
System.out.println("修改了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
- Log 实现 MethodBeforeAdvice 接口
public class Log implements MethodBeforeAdvice {
//method: 要执行的目标对象的方法
//args: 参数
//target: 目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass() + "的" + method.getName() + "方法被执行了");
}
}
- AfterLog 实现 AfterReturningAdvice 接口
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + method.getName() + "方法,返回结果为:" + returnValue);
}
}
- 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
http://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.vigil.service.UserServiceImpl"></bean>
<bean id="log" class="com.vigil.log.Log"></bean>
<bean id="afterLog" class="com.vigil.log.AfterLog"></bean>
<!--方式一:使用原生的Spring API接口-->
<!--配置aop:导入aop的约束-->
<aop:config>
<!--切入点:expression:表达式,execution(要执行的位置! * * * * *)修饰词 返回值 列名 方法名 参数-->
<aop:pointcut id="pointcut" expression="execution(* com.vigil.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
- Test
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//十分注意的地方:动态代理----->代理接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
(2) 自定义类来实现AOP【主要切面定义】
- UserService
- UserServiceImpl
- MyLog
public class MyLog {
public void before() {
System.out.println("======方法执行前======");
}
public void after() {
System.out.println("======方法执行后======");
}
}
- applicationContext.xml
<!--方式二:自定义类-->
<bean id="myLog" class="com.vigil.diy.MyLog"></bean>
<aop:config>
<!--自定义切面,ref 要引用的类-->
<aop:aspect ref="myLog">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.vigil.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
- Test
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理:代理接口
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
- 两种方式小结
方式一:使用原生Spring API接口 配置文件里只说明用哪几个通知,根据类的定义(实现)去分配具体的功能(before/after)
方式二:自定义类 配置文件里说明切面类的某个方法是做什么的,这样就不用限制类本身性质了
十分注意的地方:动态代理----->代理接口,那么我们传入的是接口,得到是接口实现的实例化对象
(3) 使用注解实现AOP
- UserService
- UserServiceImpl
- AnnotationPointCut.java
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.vigil.service.UserServiceImpl.*(..))")
public void before() {
System.out.println("方法执行前");
}
@After("execution(* com.vigil.service.UserServiceImpl.*(..))")
public void after() {
System.out.println("方法执行后");
}
//在环绕增强中,可以给定一个参数,代表要获取处理切入的点
@Around("execution(* com.vigil.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("==环绕前==");
Signature signature = joinPoint.getSignature();//获得签名
System.out.println("signature" + signature);
//执行方法
Object proceed = joinPoint.proceed();
System.out.println("==环绕后==");
System.out.println(proceed);
}
}
- applicationContext.xml
<!--方式三:使用注解-->
<bean id="annotationPointCut" class="com.vigil.diy.AnnotationPointCut"></bean>
<!--开启注解支持-->
<!--JDK(默认 proxy-target-class="false")-->
<!--cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
- Test.java
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理:代理接口
UserService userService = (UserService) context.getBean("userService");
userService.update();
}
十一、Spring整合Mybatis
步骤:
- 导入相关的包
- junit
- mybatis
- mysql数据库
- spring相关
- aop织入
- mybatis-spring【new】
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring-jdbc:Spring操作数据库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--aop织入-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!---->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
- 编写配置文件
- 测试
1、回忆mybatis
- 编写实体类
- 编写核心配置文件
- 编写接口
- 编写接口对应的Mapper.xml
- 在核心配置文件中注册Mapper.xml
- 测试
2、整合Mybatis方式一
- 编写数据源配置
<!--DataSource:使用Spring的数据源替换MyBatis的配置 c3p0 dbcp druid
使用Spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="20201123"/>
</bean>
- sqlSessionFactory
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--绑定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/vigil/mapper/*.xml"></property>
</bean>
- sqlSessionTemplate
<!--SqlSessionTemplate:SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为该类没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
前三个配置在一个spring.xml 文件中(作为一个工具配置),实现获得数据源、sqlSessionFactory、sqlSession这三类资源的配置文件
- 需要给接口加实现类【】
public class UserMapperImpl implements UserMapper {
// 在原来所有的操作:都使用sqlSession来执行
// 而现在都使用SqlSessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> getUserList() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUserList();
}
}
- 将实现类注入Spring中
在Spring总配置文件applicationContext.xml 中 import 上面配置资源的xml,注入该实现类
<import resource="spring-dao.xml"></import>
<!---->
<bean id="userMapper" class="com.vigil.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
- 测试(获得Spring容器,获取bean,调用方法)
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper",UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
3、整合Mybatis方式二
- 实现类
继承SqlSessionDaoSupport,直接获取SqlSession的对象
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> getUserList() {
return getSqlSession().getMapper(UserMapper.class).getUserList();
}
}
- 注入spring
<bean id="userMapper2" class="com.vigil.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
- 测试
4、总结工具配置
<?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">
<!--DataSource:使用Spring的数据源替换MyBatis的配置 c3p0 dbcp druid
使用Spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="20201123"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--绑定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/vigil/mapper/*.xml"></property>
</bean>
<!--SqlSessionTemplate:SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为该类没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
</beans>
十二、声明式事务
1、事务
- 要么都成功要么都失败
- ACID原则:
- 原子性
- 一致性
- 隔离性
- 持久性
2、Spring中的事务管理
- 编程式事务:需要在代码中,进行事务的管理
- 声明式式事务:AOP
- 需要导入的包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring-jdbc:Spring操作数据库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!---->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
- 配置文件
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--DataSource:使用Spring的数据源替换MyBatis的配置 c3p0 dbcp druid
使用Spring提供的JDBC:org.springframework.jdbc.datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="20201123"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!--绑定MyBatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/vigil/mapper/*.xml"></property>
</bean>
<!--SqlSessionTemplate:SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为该类没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
<!--配置声明式事务-->
<bean id="transactionManage" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--结合AOP实现事务的织入-->
<tx:advice id="tsAdvice" transaction-manager="transactionManage">
<!--给那些方法配置事务-->
<!--配置事务的传播特性:propagation-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.vigil.mapper.*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="tsAdvice" pointcut-ref="txPointCut"></aop:advisor>
</aop:config>
</beans>