spring-framework 弹簧框架 (spring.io)
官方文档:[Index of /spring-framework/docs
下载的spring web mvc:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.0.RELEASEversion>
dependency>
2002,首次推出spring框架雏形,interface21框架!
2004年3月24日,spring 1.0版本发布
Rod Johnson , spring Framework 创始人
spring理念:让现有技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
官方下载地址:Index of /spring-framework/docs
github:https://github.com/spring-projects/spring-framework
Spring 就是一个轻量级的控制反转IOC和面向切面编程AOP的框架!
Spring框架由组织成约20个模块的功能组成。这些模块分为核心容器、数据访问/集成、Web、AOP(面向方面的编程)、检测、消息传递和测试,如下图所示。

发展了太久,违背了原来的理念:配置十分繁琐!
总结: IOC就是将对象由Spring去创建,管理,装配!
之前开发:
弊端:
用户更改需求的时候,程序员需要改动具体实现接口的代码,很麻烦!
利用生成 Set 接口,发生了革命性变化!
public class UserServiceImpl implements UserService{
//利用set进行动态实现Dao层接口的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
//利用新new出来的Dao层implement实现类对象,调用Dao层接口方法
//private UserDao userDao = new UserDaoImpl();
private UserDao userDao = new UserDaoOracleImpl();
public void getUser() {
//userDao.getUser();
//userDao.getMySql();
userDao.getOracle();
}
}
之前,主动创建对象,控制权在程序员手上
现在,使用 Set 注入后,程序员没有了主动性,变成了被动接受的对象,那么控制权交给了谁?
程序员不用再管理对象的创建
系统耦合性大大降低
程序员可以更加专注在业务上
控制创建对象的方式;
原本应用程序的对象是通过程序本身控制创建,
加入Spring后,对象由Spring来创建;
程序本身不再创建对象了,而是被动接收Spring创建的对象;
就是利用set方法进行注入;
DI(依赖注入)是实现IOC(控制反转)这个编程思想的一种方式;

Hello.java
package com.kuang.pojo;
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
<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="com.kuang.pojo.Hello">
<property name="str" value="Spring">property>
bean>
beans>
MyTest.java
import com.kuang.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
// 1、获取Spring的上下文对象,拿到Spring容器
// 允许容器从各种外部资源(如本地文件系统、Java 等)加载配置元数据。ApplicationContext CLASSPATH
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 2、容器在手,天下我有,需要什么,直接从容器中获取
// 我们的对象现在都在Spring中管理了,我们要使用对象,不用new,直接从ApplicationContext里面取出来就行
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qWHpZJth-1660011316857)(https://s2.loli.net/2022/08/02/93S5JK1R78M6Fyf.png)]
【JSP】JSP从基础到入门笔记完整一篇_宋丹敏的博客-CSDN博客
ServletContext

ApplicationContext
用对象的时候去容器中拿

是由Spring容器创建的;
<bean id="hello" class="com.kuang.pojo.Hello">
<property name="str" value="Spring">property>
bean>
由Spring容器设置;
<bean id="hello" class="com.kuang.pojo.Hello">
<property name="str" value="Spring">property>
bean>

User.java
package com.kuang.pojo;
public class User {
private String name;
// 无参构造
public User(){
System.out.println("user的无参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+name);
}
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="秦疆">property>
bean>
beans>
MyTest.java
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取应用上下文,加载beans.xml配置元数据
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//通过bean 从context中获取User对象
User user = (User) context.getBean("user");
user.show();
//System.out.println(user.getName());
}
}
运行结果:

这里如果将User实体类中定义的无参构造删除,只写入有参构造方法,就会报错:

所以得出结论:IOC创建对象通过使用无参构造创建
那么只有有参构造时候,如何创建对象?
bean.xml
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg index="0" value="狂神说Java">constructor-arg>
bean>
实例:
User.java
package com.kuang.pojo;
public class User {
private String name;
// 有参构造
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);
}
}
bean.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg index="0" value="狂神说Java">constructor-arg>
bean>
beans>
MyTest.java
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取应用上下文,加载beans.xml配置元数据
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//通过bean 从context中获取User对象
User user = (User) context.getBean("user");
user.show();
}
}
测试结果:

bean.xml
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg type="java.lang.String" value="秦疆">constructor-arg>
bean>
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="name" value="qingjiang">constructor-arg>
bean>
Spring容器, 就类似于婚介所,不管你要不要,婚介所都有已经存在的对象,如果对象你想要,直接获取就行,而婚介所中存在的每个对象都独一无二
在配置文件加载的时候,容器中的管理对象就已经初始化了!
bean.xml
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="name" value="qingjiang">constructor-arg>
bean>
<alias name="user" alias="userNew">alias>
<bean id="userT" class="com.kuang.pojo.UserT" name="user2 u2, u3, u4" >
<property name="name" value="西部开源">property>
bean>
这个import,一般用于团队开发;
可以将多个配置文件,导入合并为一个;
applicationContext.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="beans.xml">import>
<import resource="beans2.xml">import>
<import resource="beans3.xml">import>
beans>

看4.1 4.2
Spring团队提倡构造函数注入
【环境搭建】
package com.kuang.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> games;
private String wife; //妻子,空指针null
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> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
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 +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
<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="address" class="com.kuang.pojo.Address">
<property name="address" value="西安">property>
bean>
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="秦疆">property>
<property name="address" ref="address">property>
<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="123712739171293">entry>
<entry key="银行卡" value="234234234324344">entry>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>cfvalue>
<value>红警value>
<value>吃鸡value>
set>
property>
<property name="wife">
<null>null>
property>
<property name="info">
<props>
<prop key="driver">231231prop>
<prop key="url">nanprop>
<prop key="username">rootprop>
<prop key="password">231231prop>
props>
property>
bean>
beans>
import com.kuang.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//引入applicationContext.xml配置文件,生成ApplicationContext,要获取对象的时候,只需要从context中获取就行
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//拿到student的对象 == 拿到student的bean
Student student = (Student) applicationContext.getBean("student");
//输出student对象中name属性的value值
System.out.println(student.toString());
/*
Student{
name='秦疆',
address=Address{address='西安'},
books=[红楼梦, 西游记, 三国演义],
hobbys=[听歌, 敲代码, 看书],
card={
身份证=123712739171293,
银行卡=234234234324344
},
games=[LOL, cf, 红警, 吃鸡],
wife='null',
info={
password=231231,
url=nan,
driver=231231,
username=root
}
}
*/
}
}
测试结果:获取到了student对象的所有类型注入的值


userBean.xml
xmlns:p="http://www.springframework.org/schema/p"
userBean.xml
xmlns:c="http://www.springframework.org/schema/c"
User.java
package com.kuang.pojo;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
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 +
'}';
}
}
userBean.xml
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User" p:name="秦疆" p:age="18">bean>
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神">bean>
beans>
测试类:
@Test
public void test2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("userBean.xml");
User user = (User) applicationContext.getBean("user",User.class);
User user2 = (User) applicationContext.getBean("user2",User.class);
System.out.println(user.toString());
//User{name='秦疆', age=18}
System.out.println(user2.toString());
//User{name='秦疆', age=18}
}
p命名和c命名空间不能直接使用,需要导入xml头部约束!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B7LpyXuk-1660011316868)(https://s2.loli.net/2022/08/03/ogaMd528nmURvYl.png)]
scope="singleton"

userBean.xml
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神" scope="singleton">bean>
测试类:
@Test
public void test2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("userBean.xml");
User user = (User) applicationContext.getBean("user",User.class);
User user2 = (User) applicationContext.getBean("user",User.class);
System.out.println(user.toString());
//User{name='秦疆', age=18}
System.out.println(user2.toString());
//User{name='秦疆', age=18}
/*
hashcode()方法是干什么的?
hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。
当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值,
实际上hashmap中会有一个table保存已经存进去的对象的hashcode值,
如果table中没有改hashcode值,则直接存入,
如果有,就调用equals方法与新元素进行比较,相同就不存了,不同就存入。
*/
System.out.println(user.hashCode());
System.out.println(user2.hashCode());
System.out.println(user == user2);
}
测试结果:true
单例模式,从bean中拿到的对象是同一个

scope="prototype"

userBean.xml
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神" scope="prototype">bean>
测试类: 同上
测试结果: false
测试类:
@Test
public void test2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("userBean.xml");
User user = (User) applicationContext.getBean("user",User.class);
User user2 = (User) applicationContext.getBean("user2",User.class);
System.out.println(user.toString());
System.out.println(user2.toString());
System.out.println(user.hashCode());
System.out.println(user2.hashCode());
System.out.println(user == user2);
}
测试结果: false

这些只能在web开发中使用到!
在Spring中有三种装配方式:
环境搭建:一个人有两个宠物!
Cat.java
package com.kuang.pojo;
public class Cat {
public void shout(){
System.out.println("miao~");
}
}
Dog.java
package com.kuang.pojo;
public class Dog {
public void shout(){
System.out.println("wang~");
}
}
People.java
package com.kuang.pojo;
public class People {
//人有猫、狗、名字
private Cat cat;
private Dog dog;
private String name;
public People() {
}
public People(Cat cat, Dog dog, String name) {
this.cat = cat;
this.dog = dog;
this.name = 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 + '\'' +
'}';
}
}
MyTest.java
import com.kuang.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 applicationContext = new ClassPathXmlApplicationContext("beans.xml");
People people = applicationContext.getBean("people", People.class);
people.getDog().shout();
people.getCat().shout();
}
}
测试结果,环境搭建成功:

通过byname,将cat、dog自动装配到people 的bean中
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dog" class="com.kuang.pojo.Dog">bean>
<bean id="cat" class="com.kuang.pojo.Cat">bean>
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="秦疆">property>
bean>
beans>
测试类结果:

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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dog" class="com.kuang.pojo.Dog">bean>
<bean id="cat" class="com.kuang.pojo.Cat">bean>
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="秦疆">property>
bean>
beans>
小结:

jdk1.5支持的注解,spring2.5支持注解!
使用注解须知:
使用 Autowired 我们就可以不用再编写set方法了,前提是你这个自动装配的属性在IOC(spring)容器中存在,且符合名字byname!
@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;
科普:
@Nullable 字段标记了这个注解,说明这个字段可以为null;
@Resource(name = "cat")
private Cat cat;
@Resource(name = "dog")
private Dog dog;
@Autowired 默认 byType 类型查找,当找不到时候,再通过byName
@Resource 默认byName 类型查找,
当注入在IOC容器中该类型只有一个时,就通过ByType进行装配;
当注入在IOC容器存在多个同一类型的对象时,就是根据ByName进行装配;
@Autowired 直接在属性上使用 or 在set方法上使用(使用了@Autowired后可以将set方法删除)
使用示例:
@Autowired
private Dog dog;
使用@Autowired就可以不用写set方法了
如果现实的定义了Autowired属性为false,说明这个对象可以为null,否则不允许为空 <==> @Nullable
@Autowired(required = false)
private Cat cat;
@Qualifer + @Autowired <==> @Resource
@Nullable 可以为空
使用示例:
public People(@Nullable String name) {
this.name = name;
}
组件
User.java
@Component
public class User {
public String name;
@Value("kuangshen")
public void setName(String name){
this.name = name;
}
}
or
@Component
public class User {
@Value("kuangshen")
public String name;
}
beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.kuang.pojo">context:component-scan>
beans>
衍生的注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
加上注解,就说明你这个类被spring托管了,
这四个注解功能都是一样的,都是代表将某个类注册到spring中,装配bean!
xml与注解:
xml更加万能,适用于任何场合!维护方便
注解,不是自己类使用不了,维护相对复杂
springboot使用注解比较方便,spring使用还是xml比价方便
我们在使用的过程中,只需要注意一个问题,必须要注解生效:
<context:annotation-config/>
<context:component-scan base-package="com.kuang">context:component-scan>
我们现在要完全不使用spring的 beans.xml 配置,全权交给Java来做!
JavaConfig 是 Spring 的一个子项目,在Spring4之后,它称为了一个核心功能!!!!
User.java
package com.kuang.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 这里这个注解的意思,就是说明这个类被 Spring接管了,注册到了容器中
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("qinjiang") //属性注入值
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
KuangConfig.java
package com.kuang.config;
import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Controller;
//这个也会被 Spring 容器托管,注册到容器中,因为他本身就是一个 Component,
// @Configuration代表这是一个配置类,和我们之前看到的beans.xml是一样的
@Configuration
@ComponentScan("com.kuang.pojo") //可以扫描到pojo包下的实体类
@Import(KuangConfig2.class) //引入,KuangConfig2配置类
public class KuangConfig {
// 注册一个bean,就相当于我们之前写的一个bean标签
// 这个方法的名字就相当于bean标签的id属性,
// 这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User(); //就是返回到要注入到bean的对象
}
}
KuangConfig.java
package com.kuang.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KuangConfig2 {
// 将KuangConfig2配置类融合入KuangConfig中去 ————
}
MyTest.java
import com.kuang.config.KuangConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContextExtensionsKt;
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只通过AnnotationConfig 上下文来获取容器,通过配置类的class对象加载!
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(KuangConfig.class);
User getUser = (User) applicationContext.getBean("getUser");
System.out.println(getUser.getName());
}
}
测试结果:

为什么要学习代理模式?
因为这就是SpringAOP的底层;
① 就相当于 房东 – 中介 – 我 之间的关系

② 代理模式分为:静态代理 和 动态代理
接口
Rent.java
package com.kuang.demo1;
/*
租房 : 接口
房东 和 中介 的目的都是租房
*/
public interface Rent {
public void rent();
}
真实角色
Landlord.java
package com.kuang.demo1;
/*
房东
*/
public class Landlord implements Rent{
//房东说:要出租房子
public void rent() {
System.out.println("房东:我要出租房子!");
}
}
代理角色
Proxy.java
package com.kuang.demo1;
/*
中介
可以帮助房东发布租房的消息
可以帮你签署合同
可以带你去看房
可以收中介费
*/
public class Proxy implements Rent{
//中介说:房东要出租房子
private Landlord landlord;
public Proxy(){
}
public Proxy(Landlord landlord) {
this.landlord = landlord;
}
public void rent(){
landlord.rent();
seeHouse();
hetong();
fare();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//签合同
public void hetong(){
System.out.println("签租赁合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
客户端访问代理角色
Client.java
package com.kuang.demo1;
/*
客户 :我 访问中介的人
*/
public class Client {
//我找到中介,得到中介说房东要租房的信息
public static void main(String[] args) {
//先要房东存在,且要出租房子
Landlord landlord = new Landlord();
//将房东扔给中介
Proxy proxy = new Proxy(landlord);
//中介给我房东出租的房子,此外帮,做一个附属操作
proxy.rent();
}
}
Client.java运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rEMdqMtJ-1660011316876)(C:\Users\16431\AppData\Roaming\Typora\typora-user-images\image-20220804151407378.png)]
好处:
缺点:
业务需求:要求执行增删改查的时候输入日志;
**普通思路:**给每个增删改查的方法加入日志输出,执行一个,输出一个;但是这样做十分麻烦;
例如像这样:

**代理思想:**做一个代理,对业务层的增删改查进行代理;代理做的事情就是实现日志功能;让dao层和controller层直接接触代理,不接触service层;
就是AOP思想,面向切面编程;

代码示例:spring-08-proxy
package com.kuang.demo2;
//Service层接口
public interface UserService {
//抽象业务一般就写CRUD
public void add();
public void delete();
public void update();
public void query();
}
package com.kuang.demo2;
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("查询了一个用户");
}
}
package com.kuang.demo2;
/*
日志功能,代理来实现
*/
public class LogProxy implements UserService{
//要代理UserServiceImpl,得先有UserServiceImpl
UserServiceImpl userService = new UserServiceImpl();
// 代理本身干的事情是让每个CRUD方法打印出日志;
private void log(String msg){
System.out.println("【log】"+msg+"方法执行了");
}
//新的CRUD方法,不仅要有原来的实现方法,也要有新增的日志方法
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();//原来的实现方法
}
}
package com.kuang.demo2;
public class Client {
public static void main(String[] args) {
//我要执行,得先有代理
//LogProxy()在UserService层原有的基础上加入了日志功能,重新实现了UserService接口,所以,返回结果还是UserService类型
UserService userService = new LogProxy();
userService.add();
userService.delete();
userService.update();
userService.query();
}
}
代理后测试结果:

jdk实现动态代理—是基于接口的
InvocationHandler
Proxy
在jdk1.8文档中查这两个类,就可以看到里面的方法,进行参考;
cglib实现动态代理—是基于类的
javasist实现动态代理—是基于java字节码的
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们自己写的!
动态代理分为两大类:基于接口的动态代理、基于类的动态代理
需要了解两个类:Proxy:代理 , InvocationHandler 调用处理
InvocationHandler 代理调用处理程序类
invoke:调用
public interface InvocationHandler;
InvocationHandler是由代理实例的调用处理程序实现的接口 。
每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
Object | invoke(Object proxy, 方法 method, Object[] args) 处理代理实例上的方法调用并返回结果。 |
|---|---|
jdk动态代理–基于接口( InvocationHandler、Proxy )的实例:
spring-08-proxy
Rent.java
package com.kuang.demo3;
/*
租房 : 接口
房东 和 中介 的目的都是租房
*/
public interface Rent {
public void rent();
}
Landlord.java
package com.kuang.demo3;
/*
房东
*/
public class Landlord implements Rent {
//房东说:要出租房子
public void rent() {
System.out.println("房东:我要出租房子!");
}
}
ProxyInvocationHandler.java
package com.kuang.demo3;
import com.kuang.demo3.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
InvocationHandler 调用处理器
invocation 调用 handler 处理
是一个接口(是由代理实例的调用处理程序实现的接口)
只要实现这个接口,就能自动生成代理,并返回代理结果
每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。
Object invoke(Object proxy, 方法 method, Object[] args)
处理代理实例上的方法调用并返回结果。
所有已知实现类:
CompositeDataInvocationHandler ,
EventHandler ,
MBeanServerInvocationHandler ,
RemoteObjectInvocationHandler
InvocationHandler 在 java.lang.reflect 包中
Proxy 在 java.lang.reflect.Proxy 包中
为某个接口创建Foo代理:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class>[] { Foo.class }, handler);
*/
//等我们会用到这个类,自动生成代理类!
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);
}
//处理代理实例并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理添加的新功能
seeHouse();
fare();
//动态代理的本质,就是使用反射机制实现!
Object result = method.invoke(rent, args);
return result;
}
private void fare() {
System.out.println("收中介费!");
}
private void seeHouse() {
System.out.println("中介带看房子!");
}
}
Client.java
package com.kuang.demo3;
import com.kuang.demo3.Rent;
public class Client {
public static void main(String[] args) {
//真实角色,客户要拿到信息,虽然有代理(中介),但是真实的角色(房东)也得存在
Landlord landlord = new Landlord();
//代理角色 动态代理,没有代理类,不是真实存在的,是动态生成的,现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过 proxyInvocationHandler 调用程序处理角色来处理我们要调用的接口对象!
pih.setRent(landlord);
//生成代理
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
测试结果:代理成功!

ProxyInvocationHandler.java
package com.kuang.demo4;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
JDK动态代理类模板: 代理Object
*/
//等我们会用到这个类,自动生成代理类!
public class ProxyInvocationHandler implements InvocationHandler {
//1、被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//2、生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
//3、处理代理实例并返回结果
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("【log】执行了"+msg+"方法");
}
}
Client.java
package com.kuang.demo4;
import com.kuang.demo2.UserService;
import com.kuang.demo2.UserServiceImpl;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,现在不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象
pih.setTarget(userService);
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.query();
proxy.delete();
proxy.update();
}
}
UserService.java
package com.kuang.demo2;
//Service层接口
public interface UserService {
//抽象业务一般就写CRUD
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl.java
package com.kuang.demo2;
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("查询了一个用户");
}
}
测试结果:Client.java运行结果,代理成功!
spring-08-proxy
demo2(Service ServiceImpl) and demo4(Client ProxyInvocationHandler)

可以使真实角色的操作更加纯粹!不用关注一些公共的业务
公共的业务就交给了代理角色,实现了业务的分工!
公共业务发生扩展的时候,方便集中!
一个动态代理类代理的是一个接口,一般就是对应的一类业务!
一个动态代理类可以代理多个类,只是实现了同一个接口即可!
静态代理使用场景:
要代理的service业务层有接口的时候,使用静态代理,直接将接口重新实现,而重新实现的代理里面包含新的业务功能+原有的业务,而客户(也就是controller层)不再调用原来的service层,而是调用代理的service层;
静态代理是将代理写死的!
动态代理使用场景:
没有接口的时候,只有类,这时候要实现代理,就只能使用动态代理,通过类自动生成代理对象;这里面就是反射思想,通过类的class对象创建实例;
AOP: Aspect Oriented Programming 面向切面编程
是OOP的一种延伸;
AOP框架:Aspects 框架
Spring框架把Aspects框架也集成进来,用来实现AOP面向切面编程
面向切面编程实现就是为了让开发人员专注业务逻辑代码,提高开发效率
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
是函数式编程的一种衍生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序可用性,提高开发效率
AOP 面向切面编程作用:
像类似于事务处理、日志、权限判断这些代码在类中很多方法中都要使用,如果每个方法中都要写这些代码,就很繁琐,所以把这些都提取为一个工具类,哪个方法要用它,就在哪里方法中注入就行,这样也更好维护。
POP、OOP、AOP 是什么意思?区别是什么?_宋丹敏的博客-CSDN博客_aop oop pop

提供声明式事务:允许用户自定义切面!
所有增删改完了之后都要通过commit()方法提交事务;

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CyKDtVN0-1660011316883)(https://s2.loli.net/2022/08/05/zMWrPfNdXuU2GlC.png)]
导AOP织入包 aspectjweaver
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.9.1version>
<scope>runtimescope>
dependency>
package com.kuang.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/*
MethodBeforeAdvice 前置教育
*/
public class Log implements MethodBeforeAdvice {
/*
method: 要执行的目标对象的方法
object: 参数
target: 目标对象
*/
public void before(Method method, Object[] objects, Object target) throws Throwable {
System.out.println("【log】"+target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
package com.kuang.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/*
AfterReturningAdvice 后置通知
*/
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {
System.out.println("【afterlog】执行了"+method.getName()+"方法,返回结果为:"+returnValue);
}
}
package com.kuang.service;
public interface UserService {
//业务层CRUD方法
public void add();
public void delete();
public void update();
public void query();
}
package com.kuang.service;
public class UserServiceImpl implements UserService{
public void add(){
System.out.println("add了一个用户");
}
public void delete() {
System.out.println("delete了一个用户");
}
public void update() {
System.out.println("update了一个用户");
}
public void query() {
System.out.println("query了一个用户");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log">bean>
<bean id="afterLog" class="com.kuang.log.AfterLog">bean>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
aop:config>
beans>
package com.kuang.diy;
public class DiyPointCut {
public void before(){
System.out.println("====方法执行前====");
}
public void after(){
System.out.println("====方法执行后====");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log">bean>
<bean id="afterLog" class="com.kuang.log.AfterLog">bean>
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
aop:aspect>
aop:config>
beans>

package com.kuang.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.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("环绕前");
//执行方法(前 Before())
Object proceed = jp.proceed();
System.out.println("环绕后");
//Signature signature = jp.getSignature(); //获得签名
//System.out.println("signature"+signature);
//System.out.println("proceed:"+proceed);
//执行方法(后 After())
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log">bean>
<bean id="afterLog" class="com.kuang.log.AfterLog">bean>
<bean id="applicationContext" class="com.kuang.diy.AnnotationPointCut"/>
<aop:aspectj-autoproxy/>
beans>
import com.kuang.service.UserService;
import com.kuang.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//要用spring容器中的对象,先拿到ApplicationContext
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//从ApplicationContext中取出想要拿到的对象
UserService userService = (UserService) applicationContext.getBean("userService");
//通过拿到的类,调用方法
userService.add();
}
}

步骤:
导入相关jar包
junit
mybatis
mysql数据库
spring相关的
aop织入
mybatis-spring 【spirng整合mybatis的jar包】
mybatis-spring – 官网中文文档 http://mybatis.org/spring/zh/index.html
编写配置文件
测试
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-studyartifactId>
<groupId>com.kuanggroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>spring-10-mybatisartifactId>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.18version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.9.1version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.7version>
dependency>
dependencies>
project>
步骤:
pojo/Users.java
package com.kuang.pojo;
import lombok.Data;
@Data //省略写 get\set\构造\toString
public class Users {
private String id;
private String name;
private String pwd;
}
mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="com.kuang.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="Mapper/UserMapper.xml"/>
mappers>
configuration>
jdbc.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=root
mapper/UserMapper.java
package com.kuang.mapper;
import com.kuang.pojo.Users;
import java.util.List;
public interface UserMapper {
public List<Users> selectUser();
}
Mapper/UserMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="selectUser" resultType="users">
select * from user
select>
mapper>
MyTest.java
import com.kuang.mapper.UserMapper;
import com.kuang.pojo.Users;
import jdk.internal.util.xml.impl.Input;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
@Test
public void test1() throws IOException {
//获取SqlsessionFactoryBuilder
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//读取流,获取sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//获取sqlsession,设为true,自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取要测试的类
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用接口中要测试的方法
List<Users> usersList = userMapper.selectUser();
for (Users users : usersList) {
System.out.println(users);
}
//关闭sqlsession
sqlSession.close();
}
}
测试结果;

中文文档官网:mybatis-spring – http://mybatis.org/spring/zh/index.html
将 MyBatis 代码无缝地整合到 Spring 中。
允许 MyBatis 参与到 Spring 的事务管理之中,
创建映射器 mapper 和 SqlSession 并注入到 bean 中,将 Mybatis 的异常转换为 Spring 的 DataAccessException。
可以做到应用代码不依赖于 MyBatis,Spring 或 MyBatis-Spring。
导jar包
mybatis-spring jar包 spring-jdbc jar包
编写数据源DataSource配置
sqlSessionFactory
引入数据源DataSource
导入mybatisConfig核心配置文件
绑定mapper
sqlSessionTemplate 生成sqlSession
需要给接口加实现类【不同】
将自己写入实现类,注入MyBatis中
测试使用
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.22version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.7version>
dependency>
package com.kuang.pojo;
import lombok.Data;
@Data //省略写 get\set\构造\toString
public class Users {
private String id;
private String name;
private String pwd;
}
package com.kuang.mapper;
import com.kuang.pojo.Users;
import java.util.List;
public interface UserMapper {
public List<Users> selectUser();
}
package com.kuang.mapper;
import com.kuang.pojo.Users;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//我们的所有操作在原来,都使用sqlSession来执行,现在,使用sqlSessionTemplated来执行;
private SqlSessionTemplate sqlSession;
//通过set方法注入
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
//输出列表
public List<Users> selectUser() {
//获取UserMapper对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="selectUser" resultType="users">
select * from user
select>
mapper>
<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">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
beans>
<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">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
beans>
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.kuang.pojo"/>
typeAliases>
configuration>
<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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true"/>
<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:Mapper/*.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
beans>
import com.kuang.mapper.UserMapper;
import com.kuang.pojo.Users;
import jdk.internal.util.xml.impl.Input;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.mybatis.spring.SqlSessionTemplate;
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 test2(){
//将bean中注册的类导入applicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从applicationContext中获取要操作的对象
UserMapper userMapper = context.getBean("userMapper",UserMapper.class);
//测试对象中的方法
for (Users users : userMapper.selectUser()) {
System.out.println(users);
}
}
}

mybatis-spring官网中文文档:http://mybatis.org/spring/zh/sqlsession.html
UserMapperImpl2.java
package com.kuang.mapper;
import com.kuang.pojo.Users;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
/*
spring整合mybatis方式二: extends SqlSessionDaoSupport
*/
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<Users> selectUser() {
/* //获取sqlSessionTemplate,直接通过getSqlSession方法就可以获取
SqlSession sqlSession = getSqlSession();
//获取测试的接口类
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//测试方法
return mapper.selectUser();*/
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
applicationContext.xml
<bean id="userMapper2" class="com.kuang.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
MyTest.java
@Test
public void test3(){
//将bean中注册的类导入applicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//从applicationContext中获取要操作的对象
UserMapper userMapper = context.getBean("userMapper2",UserMapper.class);
//测试对象中的方法
for (Users users : userMapper.selectUser()) {
System.out.println(users);
}
}
测试结果:

事务的ACID原则:
事务分为:声明式事务和编程式事务
mybatis-spring中文文档:http://mybatis.org/spring/zh/transactions.html#configuration
配置声明式事务:
在声明式的事务处理中,要配置一个切面,其中就用到了propagation 传播,表示打算对这些方法怎么使用事务,是用还是不用,
其中propagation有七种配置,
REQUIRED、 默认是REQUIRED 必须的
SUPPORTS、
MANDATORY、
REQUIRES_NEW、
NOT_SUPPORTED、
NEVER、NESTED。

add(User user); 和 delete(int id); 两个方法要么都执行,要么都不执行;
package com.kuang.mapper;
import com.kuang.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
/*
模拟事务失败
*/
//添加一个用户
public int add(User user);
//删除一个用户
public int delete(int id);
}
package com.kuang.mapper;
import com.kuang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
//我们的所有操作在原来,都使用sqlSession来执行,现在,使用sqlSessionTemplated来执行;
private SqlSessionTemplate sqlSession;
//通过set方法注入
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
//输出列表
public List<User> selectUser() {
//事务操作:插入和删除要么都执行,要么都不执行
User user = new User(9,"10小王","123");
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
mapper.add(user);
mapper.delete(9);
//获取UserMapper对象,调用对象中的方法
return mapper.selectUser();
}
public int add(User user) {
return getSqlSession().getMapper(UserMapper.class).add(user);
}
public int delete(int id) {
return getSqlSession().getMapper(UserMapper.class).delete(id);
}
}
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data // == get、set、toString
@AllArgsConstructor // == 有参构造
@NoArgsConstructor // == 无参构造
public class User {
private int id;
private String name;
private String pwd;
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.mapper.UserMapper">
<insert id="add" parameterType="User">
insert into user (id,name,pwd) value (#{id},#{name},#{pwd})
insert>
<delete id="delete" parameterType="int">
delete from user where id=#{id}
delete>
<select id="selectUser" resultType="User">
select id,name,pwd from user
select>
mapper>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl" >
<property name="sqlSessionTemplate" ref="sqlSession" >property>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg 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="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
aop:config>
beans>
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="com.kuang.pojo.User" alias="User"/>
<package name="com.kuang.pojo"/>
typeAliases>
configuration>
<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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true"/>
<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:Mapper/*.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
beans>
测试成功,add和delete方法要么都执行了,要么都没有执行,没有出现add了一条用户信息后,数据库中多了一条用户信息,delete没有成功;
主要就是银行取款存款操作;
如果不配置事务,可能存在数据提交不一致的情况;
比如:银行存钱操作
如果我们不在spirng中去配置声明式事务,我们就需要在代码中手动配置事务;
事务在项目的开发中十分重要,涉及到数据的完整性和一致性;
事务的ACID原则;