-
2002年 inteface21框架
-
2004.03.24 spring
-
Rod Johnson
spring理念
使现有的技术更加容易使用 本身整合了现有的技术框架
-
SSH: struct2 + Spring + HIbernate
-
SSM: SpringMvc + spring + MyBatis
-
导包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
优点
-
开源免费的框架
-
轻量级, 非入侵式框架(引入spring对原来的项目没有任何影响)
-
控制反转(IOC) 面向切面编程(AOP)
-
支持事务处理, 对框架整合支持
是一个轻量级的 控制反转(IOC), 面向切面(AOP)编程的 框架
缺点
-
太杂
-
项目大了后期配置繁琐
Spring Boot
-
快速开发的脚手架
-
快速开发单个微服务
-
约定大于配置
-
前提掌握SpringMvc 和 Spring
Spring Cloud
-
基于SpringBoot实现
IOC (推导)
-
UserDao接口
-
UserDaoimpl 实现类
-
UserService 业务接口
-
UserServiceImpl 业务实现类
package com.cyz.service;
import com.cyz.dao.UserDao;
import com.cyz.dao.UserDaoImpl;
import com.cyz.dao.UserDaoMysqlImpl;
import com.cyz.dao.UserDaoOracleImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();
public void getUser() {
userDao.getUser();
}
}
package com.cyz;
import com.cyz.service.UserService;
import com.cyz.service.UserServiceImpl;
public class UserTest {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
原先 多一个UserDao的实现类 就需要换 UserServiceImpl 里的实例对象
UserDaoImpl
UserDaoMysqlImpl
UserDaoOracleImpl
-
现在增加一个set方法
我们只需要在使用的时候set值即可 操作对象由需求决定而不需要改变源代码
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
package com.cyz.service;import com.cyz.dao.UserDao;
import com.cyz.dao.UserDaoImpl;
import com.cyz.dao.UserDaoMysqlImpl;
import com.cyz.dao.UserDaoOracleImpl;public class UserServiceImpl implements UserService{
private UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao = userDao; } public void getUser() { userDao.getUser(); }
}
package com.cyz;import com.cyz.dao.UserDaoImpl;
import com.cyz.dao.UserDaoMysqlImpl;
import com.cyz.dao.UserDaoOracleImpl;
import com.cyz.service.UserService;
import com.cyz.service.UserServiceImpl;public class UserTest {
public static void main(String[] args) { UserService userService = new UserServiceImpl(); ((UserServiceImpl)userService).setUserDao(new UserDaoOracleImpl()); userService.getUser(); }
}
-
不在去管理对象的创建, 系统耦合型性大大降低, 可以更加专门专注在业务上的实现 这就是IOC原型
IOC本质
-
控制反转 设计思想
-
DI(依赖注入) 是实现IOC的一种方法
-
没有之前: 对象创建完全依赖与对象本身 强耦合性
-
有之后: 解耦 将对象创建交于第三方
-
依赖对象的反转
-
控制反转是一种描述(XML或注解) 并通过第三方生产获取特定对象的方式 这在Spring中实现控制反转的是IOC容器 其实现方法是依赖注入
XML和注解
采用XML方式配置Bean的时候, Bean的定义信息是和实现分离, 而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中, 从而达到了零配置的目的
HelleSpring
-
pojo
package com.cyz.pojp;public class Hello {
private String str;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"> <!-- 使用Spring来创建对象 在Spring中称为Bean类型 变量名 = new 类型() Hello hello = new Helo(); 需要有set方法 因为本身是通过依赖注入实现的 id = 变量名 class = new 的对象 property 相当于给对象中的属性设置一个值 bean = 对象 new Hello(); 这种就是控制反转 有主动创建对象 到 现在被动接收对象 --> <bean id="hello" class="com.cyz.pojp.Hello"> <property name="str" value="spring"/> </bean> </beans></pre>
-
测试
import com.cyz.pojp.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");
// hello是通过Spring容器创建出来的
System.out.println(hello.toString());//Hello{str='spring'}
}
}
-
将推导改造成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"> <bean id="mysqlImpl" class="com.cyz.pojp.UserDaoMysqlImpl"> </bean> <bean id="oracleImpl" class="com.cyz.pojp.UserDaoOracleImpl"> </bean><bean id="UserServiceImpl" class="com.cyz.service.UserServiceImpl">
<!--
ref : 引用Spring容器中创建好的对象
value: 基本数据类型
-->
<property name="userDao" ref="mysqlImpl"/>
</bean>
</beans>
public class UserTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl"); userServiceImpl.getUser(); } }
-
修改只需要在beans.xml中修改ref引用对象即可
IOC创建对象方式
-
Spring通过无参构造方法创建对象 pojo需要有无参构造
<!-- 无参构造 通过属性赋值--> <bean id="user" class="com.cyz.pojo.User"> <property name="name" value="jack"/> </bean>
-
如何使用有参构造
package com.cyz.pojo;public class User {
private String name;// public User() {
// System.out.println("User无参构造");
// }//使用有参构造
public User(String name) {
this.name = name;
}public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("name="+name); } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; }
}
<!-- 有参构造--> <!-- 第一种参数下标赋值--> <bean id="user" class="com.cyz.pojo.User"> <constructor-arg index="0" value="cyzJava"/> </bean>
<!-- 第二种 通过类型创建 不建议使用--> <bean id="user" class="com.cyz.pojo.User"> <constructor-arg type="java.lang.String" value="cyz666"/> </bean>
<!-- 第三种 通过构造的 参数实现 --> <bean id="user" class="com.cyz.pojo.User"> <constructor-arg name="name" value="张三"/> </bean>
-
注意
在创建bean的时候 对象已经实例化过了所以不管实用不实用对象 都已经创建过了
并且实例化只有一次
也就是内存中只有一个对应的对象 user1 == user2 //true
Spring配置
别名
<alias name="user" alias="xxx"/>
Bean的配置
<!-- id: bean标识 class: bean对应的权限定名: 包名 + 类型 name: 也是别名 比alias高级 且多个 逗号,分号或空格分隔 --> <bean id="user" class="com.cyz.pojo.User" name="u1, u2"> <property name="name" value="ssss"/> </bean>
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 resource="beans2.xml"/> <import resource="beans3.xml"/>
</beans>
DI依赖注入
构造器注入(前面所学)
Set方式注入(重点)
-
依赖注入: Set注入
-
依赖: bean对象的创建依赖与容器
-
注入: bean对象中的所有属性, 由容器注入
-
环境(各种类型注入)
-
pojo
package com.cyz.pojo;public class Address {
private String address;public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Address{" + "address='" + address + '\'' + '}'; }
}
package com.cyz.pojo;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> game;
private String wife;//空指针
private Properties info;//配置类public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; } public List<String> getHobbys() { return hobbys; } public void setHobbys(List<String> hobbys) { this.hobbys = hobbys; } public Map<String, String> getCard() { return card; } public void setCard(Map<String, String> card) { this.card = card; } public Set<String> getGame() { return game; } public void setGame(Set<String> game) { this.game = game; } public String getWife() { return wife; } public void setWife(String wife) { this.wife = wife; } public Properties getInfo() { return info; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", address=" + address.toString() + ", books=" + Arrays.toString(books) + ", hobbys=" + hobbys + ", card=" + card + ", game=" + game + ", wife='" + wife + '\'' + ", info=" + 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"><bean id="address" class="com.cyz.pojo.Address">
<property name="address" value="浙江"/>
</bean><bean id="student" class="com.cyz.pojo.Student">
<!-- 第一种 普通注入 value-->
<property name="name" value="张三"/>
<!-- 第二种 Bean注入 ref-->
<property name="address" ref="address"/>
<!-- 第三种 数组注入 -->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
<!-- 第四种 List注入-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>敲代码</value>
<value>看电影</value>
</list>
</property>
<!-- 第五种 map注入 注意是entry-->
<property name="card">
<map>
<entry key="省份证" value="111111111554545"/>
<entry key="银行卡" value="62662265656565656"/>
</map>
</property>
<!-- 第六种 Set-->
<property name="game">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
<!-- 第七种 空值注入-->
<property name="wife">
<null/>
</property>
<!-- 第八种 Properties 配置类-->
<property name="info">
<props>
<prop key="driver">jjjjj</prop>
<prop key="url">xxxx</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
-
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Student student = (Student) context.getBean("student"); System.out.println(student.toString()); /* Student{name='张三', address=Address{address='浙江'}, books=[红楼梦, 西游记, 水浒传, 三国演义], hobbys=[听歌, 敲代码, 看电影], card={省份证=111111111554545, 银行卡=62662265656565656}, game=[LOL, COC, BOB], wife='null', info={password=123456, url=xxxx, driver=jjjjj, username=root}} */ }
}
拓展方式注入
c命名空间注入
p命名空间注入
package com.cyz.pojo;public class User {
private String name;
private int age;public User() { } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; }
}
<?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"> <!-- 需要无参构造--> <bean id="user" class="com.cyz.pojo.User" p:name="xxx" p:age="18"/> <!-- 需要有参构造--> <bean id="user2" class="com.cyz.pojo.User" c:age="16" c:name="ccc"/> </beans>
@Test public void testp(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user = context.getBean("user",User.class); System.out.println(user); } @Test public void testc(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml"); User user = context.getBean("user2",User.class); System.out.println(user); }
注意点
-
需要导入约束
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
Bean作用域(scope)
-
单例(默认) 实例只有一个 user == user2 singleton
-
原型 每次获取对象都是独立的 prototype
-
request
-
session
<!-- 需要无参构造--> <bean id="user" class="com.cyz.pojo.User" p:name="xxx" p:age="18" scope="singleton"/> <!-- 需要有参构造--> <bean id="user2" class="com.cyz.pojo.User" c:age="16" c:name="ccc" scope="prototype"/>
自动装配Bean
-
Spring会在上下文中自动寻找, 并自动给bean装配属性
三种装配方式
-
在xml中显示的配置
-
在java中显示配置
-
隐式的自动装配bean重要
测试
package com.cyz.pojo; public class Cat { public void shout(){ System.out.println("喵喵"); } }package com.cyz.pojo;
public class Dog {
public void shout(){
System.out.println("旺旺");
}
}package com.cyz.pojo;
public class People {
private Cat cat;
private Dog dog;
private String name;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 getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "People{" + "cat=" + cat + ", dog=" + dog + ", name='" + name + '\'' + '}'; }
}
<?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="cat" class="com.cyz.pojo.Cat"/> <bean id="dog" class="com.cyz.pojo.Dog"/> <bean id="people" class="com.cyz.pojo.People"> <property name="cat" ref="cat"/> <property name="dog" ref="dog"/> <property name="name" value="jack"/> </bean></beans>
<?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"> <!-- 自动装配 byName 自动在上下文中 寻找与setCat 或 setDog setXXX XXX对应的bean 的 id --> <bean id="cat" class="com.cyz.pojo.Cat"/> <bean id="dog" class="com.cyz.pojo.Dog"/> <bean id="people" class="com.cyz.pojo.People" autowire="byName"> <property name="name" value="jack"/> </bean> </beans>
<?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"> <!-- 自动装配 byType 自动在上下文中 寻找与对象类型相同的 对应的bean 的 class --> <bean id="cat" class="com.cyz.pojo.Cat"/> <bean id="dog222" class="com.cyz.pojo.Dog"/> <bean id="people" class="com.cyz.pojo.People" autowire="byType"> <property name="name" value="jack"/> </bean> </beans>
import com.cyz.pojo.People; 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"); People people = context.getBean("people", People.class); people.getCat().shout(); people.getDog().shout(); } }
注意点
-
byName: 需要保证bean的id唯一, 并且这个bean需要和自动注入的属性set方法的值一致
-
byType: 需要保证所以的bean的class唯一, 并且在这个bean需要和自动注入的属性类型一致
注解实现自动装配
-
导入约束
<?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"
>
</beans>
-
配置注解的支持
<context:annotation-config/>
-
@Autowire
-
在属性或set上使用 可以省略set方法
-
前提是符合byType规则
-
对象必须存在
-
package com.cyz.pojo;import org.springframework.beans.factory.annotation.Autowired;
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;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 getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "People{" + "cat=" + cat + ", dog=" + dog + ", name='" + name + '\'' + '}'; }
}
<?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/><bean id="cat" class="com.cyz.pojo.Cat"/> <bean id="dog" class="com.cyz.pojo.Dog"/> <bean id="people" class="com.cyz.pojo.People"/>
</beans>
扩展
-
@Nullable 可以为null
public People(@Nullable String name) { this.name = name; }
-
@required 对象可以为null 默认为true 表示不能为null 会空指针异常
@Autowired(required = false) private Cat cat;
-
@Qualifier 指定一个bean id
@Qualifier(value = "dog222") private Dog dog;
-
@Resource 组合了找id和找class 先byName 在byType 找不到报错
@Resource private Cat cat; //指定对应的id @Resource(name = "cat2") private Cat cat;
注解开发
-
bean实现
aop包的导入 (maven)导入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>
@Component : 组件 放在类上 表示这个类被spring管理 就像bean
-
属性注入
@Value("xxx") : 属性赋值 : 加在属性或set方法上 就像 <property name="name" value="xxx"/>
-
衍生的注解
和@Component相似 使用在MVC层 都是将类交由Spring管理 dao层 @Repository controller层 @Controller service层 @Service
-
自动装配
@Autowired 自动装配通用类型 名字 如果不能唯一装配, 则需要@Qualifier(value = "xxx") @Nullable 字段可以为空 @Resource 自动装配通用名字 类型
-
作用域
@Scope("singleton") @Scope("prototype")使用在类上
XML与注解
-
XML更加万能, 维护简单方便
-
注解: 不是自己的类用不了
-
最佳:
-
xml来管理bean
-
注解只负责属性的注入
-
注意导入约束,开启注解支持, 扫描指定包
-
JavaConfig配置替代xml
package com.cyz.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;@Controller
public class User {
private String name;public String getName() { return name; } @Value("jack") public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; }
}
package com.cyz.config; import com.cyz.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * 相当于bean */ @Configuration//表示一个配置类相当于beans.xml @ComponentScan("com.cyz.pojo") @import(CyzConfig2.class)//导入其他配置类 public class CyzConfig { @Bean public User getUser(){ return new User(); } }
import com.cyz.config.CyzConfig; import com.cyz.pojo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MyTest { public static void main(String[] args) { //注意是AnnotationConfigApplicationContext ApplicationContext context = new AnnotationConfigApplicationContext(CyzConfig.class); //注意那的是getUser 对应配置的bean名字 User getUser = context.getBean("getUser", User.class); System.out.println(getUser.getName()); } }
AOP
代理模式
-
SpringAOP的底层
租房人 中介(代理) 房东两者共同是租房(接口) 因为目的相同所以 交由代理(处理过程)</pre>
静态代理
-
角色分析
-
抽象角色: 一般使用接口或者抽象类来解决
-
真实角色: 被代理的角色
-
代理角色: 代理真实角色, 代理真实角色后, 我们一般会做一些附属操作
-
客户: 访问代理对象的人
-
实现
-
接口
-
真实角色
-
代理角色
-
客户端访问代理角色
package com.cyz.demo01;//租房
public interface Rent {
public void rent();
}
package com.cyz.demo01; //房东 public class Host implements Rent { public void rent() { System.out.println("房东要出租房子"); } }
package com.cyz.demo01; public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } public void rent() { seeHouse(); host.rent(); hetong(); fare(); } //看房 public void seeHouse(){ System.out.println("中介带你看房子"); } //合同 public void hetong(){ System.out.println("签租赁合同"); } //收中介费 public void fare(){ System.out.println("收中介费"); } }
package com.cyz.demo01; //租房 public interface Rent { public void rent(); }
-
好处
可以是真实角色的操作更加的纯粹! 不用去关注一些公共的业务公共也就交个代理角色! 实现了业务的分工
公共业务发生扩展的时候, 方便集中管理
-
缺点
一个真实角色就会产生一个代理角色, 代码量翻倍, 开发效率低
深化理解
package com.cyz.demo02;public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
package com.cyz.demo02; public class UserServiceImpl implements UserService { public void add() { // 原先没有代理的时候 做扩展需要 每一个方法都需要改 // System.out.println("使用了add方法"); System.out.println("增加了一个用户"); } public void delete() { System.out.println("删除了一个用户"); } public void update() { System.out.println("修改了一个用户"); } public void query() { System.out.println("查询了一个用户"); } }
package com.cyz.demo02; 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.delete(); } public void query() { log("query"); userService.query(); } // 公共业务 不用在原有的代码上修改 public void log(String msg){ System.out.println("使用了"+msg+"方法"); } }
package com.cyz.demo02; public class Client { public static void main(String[] args) { UserServiceImpl userService = new UserServiceImpl(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(userService); proxy.add(); } }
-
不用去修改原有的代码
-
在代理完成新增的功能
AOP
-
SpringAOP实现底层
-
在原有代码上新增功能是 使用代理 而不去修改原有的代码
-
动态代理
-
解决静态代理的缺点
-
使用反射
动态代理和静态代理角色一样动态代理的代理类是动态生成的
动态代理分两大类: 基于接口的动态代理 基于类的动态代理
基于接口: JDK动态代理 (我们使用)
基于类: cglib
java字节码实现: javassist
-
两个代理类
Proxy 代理InvocationHandler 调用处理程序
Proxy
-
反射包下的代理类
-
提供动态代理类的一些静态方法
InvocationHandler
-
反射包下的接口
实现
package com.cyz.demo03;//房东
public class Host implements Rent {public void rent() { System.out.println("房东要出租房子"); }
}
package com.cyz.demo03; //租房 public interface Rent { public void rent(); }
package com.cyz.demo03; 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; } /* newProxyInstance Loader Interfaces InvocationHandler */ // 生成得到代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this); } // 处理代理实例, 并返回结果 这里做业务 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { seeHourse(); //动态代理的本质 就是反射机制的实现 Object result = method.invoke(rent, args); fare(); return result; } public void seeHourse(){ System.out.println("中介带看房子"); } public void fare(){ System.out.println("收中介费"); } }
package com.cyz.demo03; public class Client { public static void main(String[] args) { //真实角色 Host host = new Host(); //代理角色 现在没有 需要生成 ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); //通过调用程序处理角色来处理我们的接口对象 proxyInvocationHandler.setRent(host); //获取代理角色 Rent proxy = (Rent) proxyInvocationHandler.getProxy();//动态生成的代理 proxy.rent(); } }
深化
-
通用代理类
package com.cyz.demo04;import com.cyz.demo03.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//使用这个类 就会自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {// 被代理的接口
private Object target;public void setTarget(Object target) { this.target = target; } /* newProxyInstance Loader Interfaces InvocationHandler */ // 生成得到代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); }
// 处理代理实例, 并返回结果 这里做业务
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 msg){ System.out.println("执行了"+msg+"方法"); }
}
package com.cyz.demo04; import com.cyz.demo02.UserService; import com.cyz.demo02.UserServiceImpl; public class Client { public static void main(String[] args) { // 真实角色 UserServiceImpl userService = new UserServiceImpl(); // 代理角色 不存在 ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); proxyInvocationHandler.setTarget(userService);//需要代理的对象 //动态代理类 UserService proxy = (UserService) proxyInvocationHandler.getProxy(); proxy.add(); } }
-
主要两点
Proxy : 提供动态代理类和实例的静态方法InvocationHandler : 调用处理程序实现接口 并返回结果
动代理的好处
可以是真实角色的操作更加的纯粹! 不用去关注一些公共的业务公共也就交个代理角色! 实现了业务的分工
公共业务发生扩展的时候, 方便集中管理
一个动态代理类代理的是一个接口, 一般就是对应的一类应用
一个动态代理类可以代理多个类, 主要是实现了同一个接口即可
AOP实现
-
面向切面编程
-
通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术
-
耦合性降低, 提供程序可重用性, 提高开发效率
AOP在Spring中的作用
-
提供声明式事务: 允许用户自定义切面
横切关注点: 跨越应用程序多个模块的方法或功能, 即是: 与我们业务逻辑无关的, 但我们需要关注的部分. 如: 日志 安全 缓存 事务 等等切面: 横切关注点 被模块化 的特殊对象 他是一个类 Log
通知: 切面必须要完成的工作 他是类中的一个方法 Log里的方法
目标: 被通知的对象
代理: 向目标对象应用通知之后创建的对象
切入点: 切面通知 执行的 "地点" 的定义
连接点: 与切入点匹配的执行点
-
导入包
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency>
方式一
-
实现Spring接口
package com.cyz.service;public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
package com.cyz.service; 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 select() { System.out.println("查询了一个用户"); } }
package com.cyz.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class Log implements MethodBeforeAdvice { //method 要执行的目标对象的方法 //args: 参数 //target: 目标对象 public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了"); } }
package com.cyz.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了"+method.getName()+"方法, 返回结果为:"+returnValue); } }
<?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 id="userService" class="com.cyz.service.UserServiceImpl"/> <bean id="log" class="com.cyz.log.Log"/> <bean id="afterLog" class="com.cyz.log.AfterLog"/> <!-- 方式一 使用原生Spring API 接口--> <!-- 配置aop 需要导入约束--> <aop:config> <!-- 切入点: expression execution(要执行的位置 * * * * ) --> <aop:pointcut id="pointcur" expression="execution(* com.cyz.service.UserServiceImpl.*(..))"/> <!-- 执行环绕增加--> <aop:advisor advice-ref="log" pointcut-ref="pointcur"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcur"/> </aop:config> </beans>
import com.cyz.service.UserService; import com.cyz.service.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 动态代理的是接口 UserService userService = context.getBean("userService",UserService.class); userService.add(); } }
方式二
-
使用自定义类
package com.cyz.diy;public class DiyPointCut {
public void before(){
System.out.println("===方法执行前=");
}public void after(){ System.out.println("=============方法执行后==========="); }
}
<?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 id="userService" class="com.cyz.service.UserServiceImpl"/> <!-- 方式二 自定义类--> <bean id="diy" class="com.cyz.diy.DiyPointCut"/> <aop:config> <!-- 自定义类切面 ref 要引用的类--> <aop:aspect ref="diy"> <!-- 切入点 第一个 参数 表示 返回类型 * 代表所有的类型 包名 类名 类里的方法 --> <aop:pointcut id="point" expression="execution(* com.cyz.service.UserServiceImpl.*(..))"/> <!-- 通知--> <aop:before method="before" pointcut-ref="point"/> <aop:after method="after" pointcut-ref="point"/> </aop:aspect> </aop:config> </beans>
使用注解
package com.cyz.diy;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.cyz.service.UserServiceImpl.*(..))") public void before(){ System.out.println("=========注解====方法执行前==========="); } @After("execution(* com.cyz.service.UserServiceImpl.*(..))") public void after(){ System.out.println("========注解=====方法执行后==========="); }
// 在环绕增强中 我们可以给定一个参数: 代表我们要获取处理切入的点 joinPoint
@Around("execution(* com.cyz.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("环绕后"); } /* 环绕前
signature:void com.cyz.service.UserService.add()
=注解方法执行前=======
增加了一个用户
环绕后
注解=方法执行后=======*/
}
<?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 id="userService" class="com.cyz.service.UserServiceImpl"/> <!-- 方式三 注解开发--> <bean id="annotationPointCut" class="com.cyz.diy.AnnotationPointCut"/> <!-- 开启注解支持 JDK(默认) 默认 proxy-target-class="false" cglib : <aop:aspectj-autoproxy proxy-target-class="true"/> --> <aop:aspectj-autoproxy/> </beans>
整合MyBatis
-
导入相关架包
-
juni
-
mybatis
-
mysql数据库
-
spring相关的
-
aop注入
-
mybatis-spring
-
<dependencies> <!-- mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!-- mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- Spring操作数据库的化 需要spring-jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <!--mybatis整合--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.4</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> </dependencies><build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>/*.properties</include>
<include>/.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build><properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties></pre>
-
编写配置文件
-
测试
MyBatis
-
编写实体类
-
编写核心配置文件
-
编写接口
-
编写Mapper.xml
-
测试
package com.cyz.pojo;import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}
package com.cyz.mapper; import com.cyz.pojo.User; import java.util.List; public interface UserMapper { public List<User> selectUser(); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cyz.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from mybatis.user </select> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--核心配置文件--> <configuration> <typeAliases> <package name="com.cyz.pojo"/> </typeAliases> <!-- 环境--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <!-- 数据库配置--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.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="123456"/> </dataSource> </environment> </environments> <!-- 注册--> <mappers> <mapper resource="com/cyz/mapper/UserMapper.xml"/> </mappers> </configuration>
import com.cyz.mapper.UserMapper; import com.cyz.pojo.User; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import org.apache.ibatis.io.Resources; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyTest { @Test public void test() throws IOException { String resources = "mybatis-config.xml"; InputStream in = Resources.getResourceAsStream(resources); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in); SqlSession sqlSession = sessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userList = mapper.selectUser(); for (User user : userList) { System.out.println(user); } } }
MyBatis-Spring
-
编写数据源配置
-
sqlSessionFactory
-
SqlSessionTemplate
-
需要给接口加实现类
-
把自己的实现类,注入到spring中
-
测试使用
package com.cyz.pojo;import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}
package com.cyz.mapper; import com.cyz.pojo.User; import java.util.List; public interface UserMapper { public List<User> selectUser(); }
package com.cyz.mapper; import com.cyz.pojo.User; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; public class UserMapperImpl implements UserMapper { //原来我们所有的操作都使用 sqlSession 来执行 现在使用SqlSessionTemplate private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession){ this.sqlSession = sqlSession; } public List<User> selectUser() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--核心配置文件--> <configuration> <typeAliases> <package name="com.cyz.pojo"/> </typeAliases> <!--其他配置转交给mybatis-spring --> <!-- 设置 --> <!-- <settings>--> <!-- <setting name="" value=""/>--> <!-- </settings>--> </configuration>
<?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" > <!-- DataSource 使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid 使用spring提供的jdbc org.springframework.jdbc.datasource.DriverManagerDataSource --> <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=false&useUnicode=true&characterEncoding=UTF-8"/> <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/cyz/mapper/UserMapper.xml"/> </bean> <!-- SqlSessionTemplate 就是我们使用的 sqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!-- 只能通过否早方法注入sqlSessionFactory 因为没有set方法--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> </beans>
<?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" > <import resource="spring-dao.xml"/> <bean id="userMapper" class="com.cyz.mapper.UserMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cyz.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from mybatis.user </select> </mapper>
import com.cyz.mapper.UserMapper; import com.cyz.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyTest { @Test public void test() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); List<User> userList = userMapper.selectUser(); for (User user : userList) { System.out.println(user); } } }
方式二
-
继承SqlSessionDaoSupport
package com.cyz.mapper;import com.cyz.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
<?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" > <import resource="spring-dao.xml"/> <bean id="userMapper2" class="com.cyz.mapper.UserMapperImpl2"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean> </beans>
<?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" > <!-- DataSource 使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid 使用spring提供的jdbc org.springframework.jdbc.datasource.DriverManagerDataSource --> <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=false&useUnicode=true&characterEncoding=UTF-8"/> <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/cyz/mapper/UserMapper.xml"/> </bean> </beans>
import com.cyz.mapper.UserMapper; import com.cyz.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; import java.io.InputStream; import java.util.List; public class MyTest { @Test public void test() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper2", UserMapper.class); List<User> userList = userMapper.selectUser(); for (User user : userList) { System.out.println(user); } } }
声明式事务
-
要么都成功, 要么都失败
-
涉及到数据一致性的问题 很重要
-
确保完整性和一致性
-
AOP形式 交由容器去管理
ACID原则
-
原子性 确保要么成功, 要么失败
-
一致性 资源和状态保持一致, 也就是要么成功, 要么失败
-
隔离性 多个业务操作同一个数据, 互不影响
-
持久性 事务一旦提交, 无论系统发生什么, 结果都不会被影响, 被持久化到存储器中
为什么需要事务
-
不配置事务, 可能存在数据提交不一致的情况
-
如果我们不在Spring中去配置声明式事务, 我们就需要在代码中手动配置事务
-
涉及到数据的一致性和完整性
测试
package com.cyz.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
package com.cyz.mapper; import com.cyz.pojo.User; import java.util.List; public interface UserMapper { public List<User> selectUser(); public int addUser(User user); public int deleteUser(int id); }
package com.cyz.mapper; import com.cyz.pojo.User; import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.support.SqlSessionDaoSupport; import java.util.List; public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper { public List<User> selectUser() { User user = new User(7, "xiO", "121313"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addUser(user); mapper.deleteUser(7); return mapper.selectUser(); } public int addUser(User user) { return getSqlSession().getMapper(UserMapper.class).addUser(user); } public int deleteUser(int id) { return getSqlSession().getMapper(UserMapper.class).deleteUser(id); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cyz.mapper.UserMapper"> <select id="selectUser" resultType="user"> select * from mybatis.user </select> <insert id="addUser" parameterType="user"> insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd}) </insert> <delete id="deleteUser" parameterType="int"> delete from mybatis.user where id=#{id} </delete> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--核心配置文件--> <configuration> <typeAliases> <package name="com.cyz.pojo"/> </typeAliases> <!--其他配置转交给mybatis-spring --> <!-- 设置 --> <!-- <settings>--> <!-- <setting name="" value=""/>--> <!-- </settings>--> </configuration>
<?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" xmlns:tx="http://www.springframework.org/schema/tx" 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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" > <!-- DataSource 使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid 使用spring提供的jdbc org.springframework.jdbc.datasource.DriverManagerDataSource --> <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=false&useUnicode=true&characterEncoding=UTF-8"/> <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/cyz/mapper/UserMapper.xml"/> </bean> <!-- 开启声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 结合AOP实现事务的织入--> <!-- 配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 给哪些方法配置事务--> <!-- 配置事务的传播特性 new 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.cyz.mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" /> </aop:config> </beans>
import com.cyz.mapper.UserMapper;
import com.cyz.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.util.List;
public class MyTest {
-
不推荐
-
需要在代码中, 进行事务管理.
-