历史:
介绍:
资源下载地址:
Maven项目需要导入的依赖:
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
官网介绍:现代化的java开发,也就是基于Spring的开发
SpringBoot:
SpringCloud:
但是要学好SpringBoot,Spring和SpringMVC是前提!SpringBoot承上启下!
弊端:发展太久,违背原来的理念,配置十分繁琐!
控制反转(IOC),它其实是一种设计思想;而实现这种思想的方式有很多!
总结:如果按照原来的模式,用户需求一旦发生改变,程序员就需要在业务层实现类里面新创建实例对象;如果代码量大会很麻烦,成本昂贵!
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.0.RELEASEversion>
dependency>
package com.my.dao;
public interface UserDao {
void getUser();
package com.my.dao;
public class UserDaoImpl implements UserDao{
//重写接口中的方法!
/*
* 重写:方法名、参数类型、参数个数之类的都要相同
* 重载:只要求方法名相同,参数类型和参数个数等可以不同
* */
public void getUser() {
System.out.println("默认获取用户数据!");
}
}
package com.my.service;
public interface UserService {
//在该接口中也定义了一个和Dao层一样的方法,用来使我们明白这是一种业务的实现过程
void getUser();
}
package com.my.service;
import com.my.dao.UserDao;
import com.my.dao.UserDaoImpl;
import com.my.dao.UserDaoMysqlImpl;
import com.my.dao.UserDaoOracleImpl;
public class UserServiceImpl implements UserService{
// private UserDao userDao = new UserDaoImpl();
// private UserDao userDao = new UserDaoMysqlImpl();
private UserDao userDao = new UserDaoOracleImpl();
public void getUser(){
userDao.getUser();
}
}
import com.my.dao.UserDaoOracleImpl;
import com.my.service.UserService;
import com.my.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际上调用的是业务层,dao层用户不需要接触
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
// private UserDao userDao = new UserDaoImpl();
// private UserDao userDao = new UserDaoMysqlImpl();
// private UserDao userDao = new UserDaoOracleImpl();
我们在业务层构建一个set方法,发生了革命性的改变:
测试代码:
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set实现
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
测试
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao( new UserDaoMySqlImpl() );
service.getUser();
//那我们现在又想用Oracle去实现呢
service.setUserDao( new UserDaoOracleImpl() ); service.getUser();
}
总结:
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.10.RELEASEversion>
dependency>
package org.example.pojo;
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 + '\'' +
'}';
}
}
<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">
<bean id="hello" class="org.example.pojo.Hello">
<property name="name" value="Spring !">property>
bean>
beans>
import org.example.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文对象(可以同时加载多个配置文件)
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象都在Spring中,我们要使用直接从里面取出来就行
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello.toString());
}
}
控制:谁来控制对象的创建?原来是程序本身,使用spring后,由spring创建
反转:程序本身不主动创建对象,而变成被动的接收对象
依赖注入:利用set方法注入
IOC:是一种编程思想,由主动的编程变成被动的接收
OK,到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配!
我们在案例一中, 新增一个Spring配置文件beans.xml
<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.kuang.dao.impl.UserDaoMySqlImpl"/>
<bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/>
<bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl">
<property name="userDao" ref="OracleImpl"/>
bean>
beans>
测试!
@Test
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean( "ServiceImpl" );
serviceImpl.getUser();
}
OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改
, 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
<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.kuang.pojo.User">
<property name="name" value="kuangshen"/>
bean>
beans>
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
//在执行getBean的时候, user已经创建好了 , 通过无参构造
User user = (User) context.getBean( "user" );
//调用对象的方法 .
user.show();
结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!
public class UserT {
private String name;
public UserT(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg index="0" value="kuangshen2"/>
bean>
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg name="name" value="kuangshen2"/>
bean>
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="kuangshen3"/>
bean>
@Test
public void testT() {
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
UserT user = (UserT) context.getBean( "userT" );
user.show();
}
结论:在配置文件加载的时候。其中管理的对象都已经初始化了!
alias 设置别名 , 为bean设置别名 , 可以设置多个别名
<alias name="userT" alias="userNew"/>
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
bean>
团队的合作通过import来实现 .
<import resource="{path}/beans.xml"/>
第四节 我们在之前的已经详细讲过了
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型, 没有set方法 , 是 is .
测试pojo类 : Address.java
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Student.java
package org.example.pojo;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
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;
public void setName(String name) {
this.name = name;
}
public void setAddress(Address address) {
this.address = address;
}
public void setBooks(String[] books) {
this.books = books;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public void setGames(Set<String> games) {
this.games = games;
}
public void setWife(String wife) {
this.wife = wife;
}
public void setInfo(Properties info) {
this.info = info;
}
public void show() {
System.out.println( "name=" + name
+ ",address=" + address.getAddress()
+ ",books="
);
for (String book : books) {
System.out.print( "<<" + book + ">>\t" );
}
System.out.println( "\n爱好:" + hobbys );
System.out.println( "card:" + card );
System.out.println( "games:" + games );
System.out.println( "wife:" + wife );
System.out.println( "info:" + info );
}
}
普通常量注入
<bean id="student" class="org.example.pojo.Student">
<property name="name" value="Martin"/>
bean>
测试:
@Test
public void test01() {
ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" );
Student student = (Student) context.getBean( "student" );
System.out.println( student.getName() );
}
<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">
<bean id="addr" class="org.example.pojo.Address">
<property name="address" value="重庆"/>
bean>
<bean id="student" class="org.example.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>西游记value>
<value>红楼梦value>
<value>水浒传value>
array>
property>
<property name="hobbys">
<list>
<value>听歌value>
<value>敲代码value>
<value>看抖音value>
list>
property>
<property name="card">
<map>
<entry key="身份证" value="123"/>
<entry key="银行卡" value="456"/>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>CFvalue>
set>
property>
<property name="wife">
<null>null>
property>
<property name="info">
<props>
<prop key="学号">789prop>
<prop key="性别">男prop>
props>
property>
bean>
beans>
测试:
public class MyTest {
@Test
public void test01() {
ApplicationContext context = new ClassPathXmlApplicationContext( "beans.xml" );
Student student = (Student) context.getBean( "student" );
student.show();
}
}
User.java : 【注意:这里没有有参构造器!】
public class User {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1、P命名空间注入 : 需要在头文件中假如约束文件
导入约束 : xmlns:p="http://www.springframework.org/schema/p"
<bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
2、c 命名空间注入 : 需要在头文件中假如约束文件
导入约束 : xmlns:c="http://www.springframework.org/schema/c"
"user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
发现问题:爆红了,刚才我们没有写有参构造!
解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!
测试代码:
@Test
public void test02() {
ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" );
User user = (User) context.getBean( "user" );
System.out.println( user );
}
在Spring中,那些组成应用程序的主体及由Spring IOC容器所管理的对象,被称之为bean。简单地讲, bean就是由IOC容器初始化、装配及管理的对象 .
几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web 应用框架),只能用在基于web的Spring ApplicationContext环境。
**单例模式:**当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是 在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象 都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
测试:
@Test
public void test03() {
ApplicationContext context = new
ClassPathXmlApplicationContext( "applicationContext.xml" );
User user = (User) context.getBean( "user" );
User user2 = (User) context.getBean( "user" );
System.out.println( user == user2 );//true
}
**原型模式:**当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法) 时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是 当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经 验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
测试:
@Test
public void test03() {
ApplicationContext context = new
ClassPathXmlApplicationContext( "applicationContext.xml" );
User user = (User) context.getBean( "user" );
User user2 = (User) context.getBean( "user" );
System.out.println( user == user2 );//false
}
当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP 请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。
当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session 最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。
Spring中bean有三种装配机制,分别是:
这里我们主要讲第三种:自动化的装配bean。
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
组件扫描和自动装配组合发挥巨大威力,使的显示的配置降低到最少。
推荐不使用自动装配xml配置 , 而使用注解 .
package org.example.pojo;
public class Cat {
public void shout() {
System.out.println("miao~");
}
}
package org.example.pojo;
public class Dog {
public void shout() {
System.out.println("wang~");
}
}
package org.example.pojo;
public class User {
private Cat cat;
private Dog dog;
private String str;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "User{" +
"cat=" + cat +
", dog=" + dog +
", str='" + str + '\'' +
'}';
}
}
<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="org.example.pojo.Dog"/>
<bean id="cat" class="org.example.pojo.Cat"/>
<bean id="user" class="org.example.pojo.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="str" value="Martin"/>
bean>
beans>
import org.example.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = context.getBean("user", User.class);
user.getDog().shout();
user.getCat().shout();
}
}
结果正常输出,环境OK
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率 降低。
采用自动装配将避免这些错误,并且使配置简单化。测试:
<bean id="user" class="org.example.pojo.User" autowire="byName">
<property name="str" value="qinjiang"/>
bean>
当一个bean节点带有 autowire byName的属性时。
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
NoUniqueBeanDefinitionException
测试:
<bean id="dog" class="org.example.pojo.Dog"/>
<bean id="cat" class="org.example.pojo.Cat"/>
<bean id="cat2" class="org.example.pojo.Cat"/>
<bean id="user" class="org.example.pojo.User" autowire="byType">
<property name="str" value="qinjiang"/>
bean>
这就是按照类型自动装配!
jdk1.5开始支持注解,spring2.5开始全面支持注解。准备工作: 利用注解的方式注入属性。
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<context:annotation-config/>
<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"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/context/spring-aop.xsd">
beans>
测试:
public class User {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String str;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getStr() {
return str;
}
}
<context:annotation-config/>
<bean id="dog" class="org.example.pojo.Dog"/>
<bean id="cat" class="org.example.pojo.Cat"/>
<bean id="user" class="org.example.pojo.User"/>
【科普时间】
@Autowired(required=false) 说明: false,对象可以为null;true,对象必须存对象,不能为null。
//如果允许对象为null,设置required = false, 默认为true
@Autowired(required = false)
private Cat cat;
@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配@Qualifier不能单独使用。
测试实验步骤:
<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"/>
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
实体类:
public class User {
//如果允许对象为null,设置required = false,默认为true
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String str;
}
beans.xml
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
测试:结果OK
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
配置文件2:beans.xml , 删掉cat2
@Resource
private Cat cat;
@Resource
private Dog dog;
实体类上只保留注解
结果:OK
结论:先进行byName查找,失败;再进行byType查找,成功。
@Autowired与@Resource异同:
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先
byName。
在spring4之后,想要使用注解形式,必须得要引入aop的包
在配置文件当中,还得要引入一个context约束
<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">
<
beans>
我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!
<context:component-scan base-package="org.example.pojo"/>
@Component("user")
// 相当于配置文件中
public class User {
public String name = "秦疆";
}
public class MyTest {
@Test
public void test(){
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml");
User user = (User)applicationContext.getBean("user");
System.out.println(user.name);
}
}
使用注解注入属性
@Component("user")
// 相当于配置文件中
public class User {
@Value("秦疆")
// 相当于配置文件中
public String name;
}
@Component("user")
public class User {
public String name;
@Value("秦疆")
public void setName(String name) {
this.name = name;
}
}
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
写上这些注解,就相当于将这个类交给Spring管理装配了!
在Bean的自动装配已经讲过了,可以回顾!
@Autowired
@Nullable
@Resource
@scope
@Controller("user")
@Scope("prototype")
public class User {
@Value("秦疆")
public String name;
}
<context:annotation-config/>
作用:
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。
测试:
@Component //将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
public String name = "dog";
}
@Configuration //代表这是一个配置类
public class MyConfig {
@Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
public Dog dog(){
return new Dog();
}
}
@Test
public void test2(){
ApplicationContext applicationContext =new AnnotationConfigApplicationContext(MyConfig.class);
Dog dog = (Dog) applicationContext.getBean("dog"); //方法名
System.out.println(dog.name);
}
@Configuration //代表这是一个配置类
public class MyConfig2 {
}
@Configuration
@Import(MyConfig2.class)//导入合并其他配置类,类似于配置文件中的 inculde 标签
public class MyConfig {
@Bean
public Dog dog(){
return new Dog();
}
}
关于这种Java类的配置方式,我们在之后的SpringBoot 和 SpringCloud中还会大量看到,我们需要知道这些注解的作用即可!
为什么要学习代理模式,因为AOP的底层机制就是动态代理!
代理模式:
Rent . java 即抽象角色
//抽象角色:租房
public interface Rent {
public void rent();
}
Host . java 即真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("我是房东,房屋出租");
}
}
Proxy . java 即代理角色
public class Proxy implements Rent{
private Host host;
public Proxy(){ }
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
fare();
}
//看房
public void seeHouse(){
System.out.println("中介带房客看房");
}
//收中介费
public void fare(){
System.out.println("中介收中介费");
}
}
Client . java 即客户
// 客户
public class Client {
public static void main(String[] args) {
//房东要租房
Host host = new Host();
//中介帮助房东
Proxy proxy = new Proxy(host);
// 你去找中介!
proxy.rent();
}
}
分析: 在这个过程中,你直接接触的就是中介,中介可以完成房东不能做的事,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更 加抽象的看待生活中发生的事情。
缺点 :
我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !
同学们练习完毕后,我们再来举一个例子,巩固大家的学习! 练习步骤:
//抽象角色:增删改查业务
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();
}
}
OK,到了现在代理模式大家应该都没有什么问题了,重点大家需要理解其中的思想;
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
【聊聊AOP:纵向开发,横向开发】
JDK的动态代理需要了解两个类
核心 : InvocationHandler调用处理程序 和 Proxy代理 , 打开JDK帮助文档看看
【InvocationHandler:调用处理程序】
Object invoke(Object proxy, 方法 method, Object[] args);
//参数
//proxy - 调用该方法的代理实例
//method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
抽象角色和真实角色和之前的一样!
Rent . java 即抽象角色
//抽象角色:租房
public interface Rent {
public void rent();
}
Host . java 即真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent {
public void rent() {
System.out.println("我是房东,房屋出租");
}
}
ProxyInvocationHandler. java 即代理角色
// 用这个类,自动生产代理
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),
this);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@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("收中介费");
}
}
Client . java
//租客
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();
}
}
核心:一个动态代理,一般代理某一类业务,一个动态代理可以代理多个类,代理的是接口!、
我们来使用动态代理实现代理我们后面写的UserService!
我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
// proxy : 代理类
// method : 代理类的调用处理程序的方法对象.
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("执行了"+methodName+"方法");
}
}
测试!
public class Test {
public static void main(String[] args) {
//真实对象
UserServiceImpl userService = new UserServiceImpl();
//代理对象的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setTarget(userService); //设置要代理的对象
UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
proxy.delete();
}
}
【测试,增删改查,查看结果】
静态代理有的它都有,静态代理没有的,它也有!
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的 一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使 得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
提供声明式事务;允许用户自定义切面
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .
【重点】使用AOP织入,需要导入一个依赖包!
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
首先编写我们的业务接口和实现类
public interface UserService {
public void add();
public void delete();
public void update();
public void search();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
@Override
public void search() {
System.out.println("查询用户");
}
}
然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强
public class Log implements MethodBeforeAdvice {
//method : 要执行的目标对象的方法
//objects : 被调用的方法的参数
//Object : 目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
//method被调用的方法
//args 被调用的方法的对象的参数
//target 被调用的目标对象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + target.getClass().getName() +"的"+method.getName()+"方法," +"返回值:"+returnValue);
}
}
最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
<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 id="userService" class="org.example.service.UserServiceImpl"/>
<bean id="log" class="org.example.log.Log"/>
<bean id="afterLog" class="org.example.log.AfterLog"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* org.example.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
aop:config>
beans>
测试
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 注意点,代理的是接口
UserService userService = (UserService) context.getBean("userService");
userService.search();
}
}
Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .
Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 .
目标业务类不变依旧是userServiceImpl
第一步 : 写我们自己的一个切入类
public class DiyPointcut {
public void before(){
System.out.println("---------方法执行前 ");
}
public void after(){
System.out.println("---------方法执行后 ");
}
}
去spring中配置
<bean id="diy" class="com.kuang.config.DiyPointcut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before pointcut-ref="diyPonitcut" method="before"/>
<aop:after pointcut-ref="diyPonitcut" method="after"/>
aop:aspect>
aop:config>
测试:
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
第一步:编写一个注解实现的增强类
package com.kuang.config;
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.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法执行前 ");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法执行后 ");
}
@Around("execution(* com.kuang.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);
}
}
// 环绕前->执行方法前->执行方法->环绕后->执行方法后
第二步:在Spring配置文件中,注册bean,并增加支持注解的配置
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
aop:aspectj-autoproxy:说明
通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面
的bean创建代理,织入切面。当然,spring 在内部依旧采用
AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被
<aop:aspectj-autoproxy />隐藏起来了
<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态
代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用
CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接
口,则spring将自动使用CGLib动态代理。
步骤:
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
package com.kuang.pojo;
@Data
public class User {
private int id; //id
private String name;//姓名
private String pwd;//密码
}
实现mybatis的配置文件
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="org.example.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
configuration>
public interface UserMapper {
public List<User> selectUser();
}
接口对应的Mapper映射文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from user
select>
mapper>
测试类
public class MyTest {
@Test
public void selectUser() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream( resource );
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper( UserMapper.class );
List<User> userList = mapper.selectUser();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
引入Spring之前需要了解mybatis-spring包中的一些重要类;
http://www.mybatis.org/spring/zh/index.html
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。
在开始使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语。这很重要
MyBatis-Spring 需要以下版本:
MyBatis-Spring | MyBatis | Spring框架 | Spring Batch | Java |
---|---|---|---|---|
2.0 | 3.5+ | 5.0+ | 4.0+ | Java 8+ |
1.3 | 3.4+ | 3.2.2+ | 2.1+ | Java 6+ |
如果使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.2version>
dependency>
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个SqlSessionFactory和至少一个数据映射器类。
Spring 的 XML 配置文件中:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
bean>
注意: SqlSessionFactory需要一个DataSource(数据源)。 这可以是任意的DataSource,只需要和配置其它 Spring 数据库连接一样 配置它就可以了。
SqlSessionFactoryBean来创建。
需要注意的是,这个配置文件并不需要是一个完整的 MyBatis 配置。确切地说,任何环境配置 ( ),数据源 ( )和 MyBatis 的事务管理器( )都会被忽略。SqlSessionFactoryBean会创建它自有 的 MyBatis环境配置( Environment ),并按要求设置自定义环境的值。
可以使用 SqlSessionFactory作为构造方法的参数来创建SqlsessionTemplate对象。
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
bean>
现在,这个 bean 就可以直接注入到你的 DAO bean 中了。你需要在你的 bean 中添加一个 SqlSession
属性,就像下面这样:
public class UserDaoImpl implements UserDao {
private SqlSession sqlSession;
public void setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public User getUser(String userId) {
return sqlSession.getMapper...;
}
}
按下面这样,注入 SqlsessionTemplate:
<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
<property name="sqlSession" ref="sqlSession" />
bean>
<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">
beans>
<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?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations"
value="classpath:org/example/mapper/*.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
public class UserMapperImpl implements UserMapper {
//sqlSession不用我们自己创建了,Spring来管理
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
<bean id="userMapper" class="org.example.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
UserMapper mapper = (UserMapper) context.getBean("userMapper");
List<User> user = mapper.selectUser();
System.out.println(user);
}
结果成功输出!现在我们的Mybatis配置文件的状态!发现都可以被Spring整合!
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="org.example.pojo"/>
typeAliases>
configuration>
mybatis-spring1.2.3版以上的才有这个 .
官方文档截图 :
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看
测试:
public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
public List<User> selectUser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.selectUser();
}
}
<bean id="userDao" class="com.kuang.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
@Test
public void test2() {
ApplicationContext context = new
ClassPathXmlApplicationContext( "beans.xml" );
UserMapper mapper = (UserMapper) context.getBean( "userDao" );
List<User> user = mapper.selectUser();
System.out.println( user );
}
总结 : 整合到spring中以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等我们后面学习SpringBoot的时候还会测试整合!
事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
将上面的代码拷贝到一个新项目中
在之前的案例中,我们给userDao接口新增两个方法,删除和增加用户;
//添加一个用户
int addUser(User user);
//根据id删除用户
int deleteUser(int id);
mapper文件,我们故意把 deletes 写错,测试!
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
insert>
<delete id="deleteUser" parameterType="int">
deletes from user where id = #{id}
delete>
编写接口的实现类,在实现类中,我们去操作一波
public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper
{
//增加一些操作
public List<User> selectUser() {
User user = new User(4,"小明","123456");
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.addUser(user);
mapper.deleteUser(4);
return mapper.selectUser();
}
//新增
public int addUser(User user) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.addUser(user);
}
//删除
public int deleteUser(int id) {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.deleteUser(id);
}
}
测试
@Test
public void test2() {
ApplicationContext context = new
ClassPathXmlApplicationContext( "beans.xml" );
UserMapper mapper = (UserMapper) context.getBean( "userDao" );
List<User> user = mapper.selectUser();
System.out.println( user );
}
报错:sql异常,delete写错了结果 :插入成功!
没有进行事务的管理;我们想让他们都成功才成功,有一个失败,就都失败,我们就应该需要事务! 以前我们都需要自己手动管理事务,十分麻烦!
但是Spring给我们提供了事务管理,我们只需要配置即可;
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以 使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
使用Spring管理事务,注意头文件的约束导入 : tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="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="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行 为:
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。
假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。
就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!
导入aop的头文件!
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.* (..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
aop:config>
删掉刚才插入的数据,再次测试!
@Test
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserMapper mapper = (UserMapper) context.getBean("userDao");
List<User> user = mapper.selectUser();
System.out.println(user);
}