Spring5框架
内容介绍:
- Spring框架概述
- IOC容器
- Aop
- JdbcTemplate
- 事务管理
- Spring5新特性
Spring框架概述
百度百科: Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
Spring简述
- Spring框架是一个轻量级的开放源代码的J2EE应用程序框架。
- Spring可以解决企业应用开发的复杂性
- Spring两个核心部分:IOC 和 Aop
- IOC:控制反转,把创建对象过程交个Spring进行管理。
- Aop:面向切面,不修改源代码进行功能增强
Spring特点
- 方便解耦,简化开发
- AOP编程的支持
- 声明式事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低java EE API 的使用难度
- Java 源码是经典学习范例
下载Spring5
- 使用Spring 最新稳定版
- 下载地址
https://repo.spring.io/artifactory/release/org/springframework/spring
我下载的是spring-5.2.6.RELEASE-dist.zip版本
libs:各种jar包
入门案例
Spring5模型:
- 创建一个普通java项目
- 导入 Spring 相关的基本 Jar 包
除了以上这四个包,还需要 commons-logging-1.1.1.jar 日志包
(依赖于日志包,如果不导入日志包,就会报错)
创建lib文件夹,将五个jar包放入
- 打开Modules
- 将之前的五个jar包,都导入
- 创建普通类,在这个类创建普通方法 ```java package com.wexiao.spring5;
/**
- @author 微咲
- @version 1.0
*/
public class User {
public void add(){
} }System.out.println("add...");
4. **创建Spring配置文件,在配置文件配置创建的对象**
(1) Spring 配置文件使用 xml格式<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1641627116553-1fc8cfda-0010-468c-90c1-dca4de7b71a2.png#clientId=u34f79b0a-0a14-4&from=paste&height=422&id=u94455707&margin=%5Bobject%20Object%5D&name=image.png&originHeight=654&originWidth=856&originalType=binary&ratio=1&size=378824&status=done&style=none&taskId=u73a17df1-7fda-43c5-b02f-baa2783736c&width=552.9801025390625)<br />创建好的样子:bean1.xml<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1641627150954-df0a13c9-7a09-43c6-b47b-9a7d7918d5cb.png#clientId=u34f79b0a-0a14-4&from=paste&height=137&id=u525445e1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=274&originWidth=1765&originalType=binary&ratio=1&size=889155&status=done&style=none&taskId=uf4595655-87cb-44f7-b6ad-0edfe5ed193&width=881.3635864257812)
配置User对象创建:bean1.xml
```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">
<!--配置User类对象创建--><!--class:类的全路径,id:别名-->
<bean id="user" class="com.wexiao.spring5.User"></bean>
</beans>
- 进行测试代码编写 ```java package com.wexiao.spring5.testdemo;
import com.wexiao.spring5.User; import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
- @author 微咲
@version 1.0 */ public class TestSpring5 {
@Test public void testAdd() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
} }
运行结果:
```xml
com.wexiao.spring5.User@6973bf95
add...
IOC容器
- IOC 底层原理
- IOC 接口(BeanFactory)
- IOC 操作 Bean 管理(基于 xml)
- IOC 操作 Bean 管理(基于注解)
1. IOC 概念和原理
什么是 IOC
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
- 控制反转,把对象创建的对象之间的调用过程,交给 Spring 进行管理
- 使用 IOC 目的:为了耦合度降低
- 入门案例就是 IOC 实现
IOC 底层原理
- xml 解析、工厂模式、反射
画图讲解 IOC 底层原理
通过在 UserService 类中调用 UserDao 中的方法来演示
- 原始方式
- 工厂模式
目的:耦合度降低最低限度
- IOC过程
2. IOC 接口
IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
Spring 提供 IOC 容器实现 两种方式
- BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员使用。
*加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
- ApplicationConText:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。
*加载配置文件时候就会把在配置文件对象进行创建
- ApplicationContext 接口有实现类
FileSystemXmlApplicationContext:XML文件的绝对路径
ClassPathXmlApplicationContext:XML文件的相对路径
3. IOC 操作 —— Bean 管理
什么是 Bean 管理
Bean管理指的是两个操作:
- Spring 创建对象
- Spring 注入属性
Bean 管理操作有两种方式
- 基于 xml 配置文件方式实现
- 基于注解方式实现
Bean操作 基于 xml 方式
- 基于 xml 方式创建对象
在 Spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
在 bean 标签有很多属性,介绍常用的属性
id 属性:唯一标识
class属性:类全路径(包 类 路径)
- 创建对象时候,默认也是执行无参数构造方法
- 基于 xml 方式注入属性
**DI:依赖注入,就是注入属性
**
- 第一种注入方式:使用 set 方法进行注入
a. 创建类,定义属性和对应 set 方法
package com.wexiao.spring5;
/**
* 演示使用set方法进行注入属性
*
* @author 微咲
* @version 1.0
*/
public class Book {
// 创建属性
private String bname;
private String bauthor;
// 创建属性对应的 set 方法
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
public void setBname(String name) {
this.bname = name;
}
}
b. 在 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">
<!--set方法注入属性-->
<bean id="book" class="com.wexiao.spring5.Book">
<!--使用property完成属性注入-->
<property name="bname" value="yellow"></property>
<property name="bauthor" value="wexiao"></property>
</bean>
</beans>
c. 创建测试方法,进行测试
@Test
public void testBook() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Book book = context.getBean("book", Book.class);
System.out.println(book);
book.testDemo();
}
- 第二种注入方式:使用有参数构造进行注入
a. 创建类,定义属性,创建属性对应有参构造方法
package com.wexiao.spring5;
/**
* 使用有参构造注入
* @author 微咲
* @version 1.0
*/
public class Orders {
// 属性
private String oname;
private String address;
// 有参构造
public Orders(String oname, String address) {
this.oname = oname;
this.address = address;
}
public void testDemo() {
System.out.println(oname + "::" + address);
}
}
b. 在 Spring 配置文件中进行配置
<!--有参构造注入属性-->
<bean id="orders" class="com.wexiao.spring5.Orders">
<!--使用有参构造注入属性-->
<constructor-arg name="oname" value="abc"></constructor-arg>
<constructor-arg name="address" value="china"></constructor-arg>
<!--按照索引来赋值-->
<!--<constructor-arg index="0" value="abc"></constructor-arg>-->
</bean>
c. 创建测试方法,进行测试
@Test
public void testOrders() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Orders orders = context.getBean("orders", Orders.class);
System.out.println(orders);
orders.testDemo();
}
- P 名称空间注入 (了解)
使用 p 名称空间注入,可以简化基于 xml 配置方式
a. 添加 p 名称空间在配置文件中
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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">
b. 进行输入注入,在bean标签里面进行操作
<!-- p 注入属性-->
<bean id="book" class="com.wexiao.spring5.Book" p:bname="111" p:bauthor="222">
</bean>
xml 注入其他类型属性
- 字面量
null 值
<!-- null 值-->
<property name="address">
<null/>
</property>
属性值包含特殊符号
- 注入属性 - 外部 bean
- 创建两个类 service 类和 dao 类 ```java package com.wexiao.spring5.dao;
/**
- @author 微咲
- @version 1.0 */ public interface UserDao { void update(); }
```java
package com.wexiao.spring5.dao;
/**
* @author 微咲
* @version 1.0
*/
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("dao update...");
}
}
- 在 service 调用 dao 里面的方法 ```java package com.wexiao.spring5.service;
import com.wexiao.spring5.dao.UserDao; import com.wexiao.spring5.dao.UserDaoImpl;
/**
- @author 微咲
@version 1.0 */ public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service add...");
userDao.update();
//原始方式创建USerDao对象
// UserDao userDao = new UserDaoImpl(); // userDao.update(); } }
3. **在 spring 配置文件中进行配置 ( ref )**
```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">
<!--service 和 dao 对象创建-->
<bean id="userService" class="com.wexiao.spring5.service.UserService">
<!--注入userDao对象
name属性:类里面属性名称
ref属性:xml中,创建userDao对象bean标签的id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.wexiao.spring5.dao.UserDaoImpl"></bean>
// 外部bean 在外面建个对象,ref引入
</beans>
d. 创建测试类,测试:
package com.wexiao.spring5.testdemo;
import com.wexiao.spring5.Orders;
import com.wexiao.spring5.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author 微咲
* @version 1.0
*/
public class TestBean {
@Test
public void testOrders() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
}
输出:
com.wexiao.spring5.service.UserService@56528192 service add… dao update…
- 注入属性 - 内部 bean 和级联赋值
- 一对多关系:部门和员工
- 在实体类之家表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
c. 在Spring配置文件中进行配置
- 注入属性 - 级联赋值
- 外部bean 赋值
- 第二种写法 .
- 注入属性 - 集合
- 注入数组类型属性
- 注入 List 集合类型属性
- 注入 Map 集合类型属性
- 创建类,定义集合,生成set方法 ```java package com.wexiao.spring5.collectiontype;
import java.util.List; import java.util.Map;
/**
- @author 微咲
@version 1.0 */ public class Stu {
//1. 数组类型属性 private String[] courses;
//2. list集合类型属性 private List
list; //3. map集合类型属性 private Map
map; public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List
list) { this.list = list;
}
public void setMap(Map
map) { this.map = map;
}
public void test(){
System.out.println(Arrays.toString((courses)));
System.out.println(list);
System.out.println(map);
} }
- **在 Spring 配置文件进行配置**
```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="stu" class="com.wexiao.spring5.collectiontype.Stu">
<!--数组-->
<property name="courses">
<array>
<value>java</value>
<value>mysql</value>
</array>
</property>
<!--集合-->
<property name="list">
<list>
<value>java</value>
<value>mysql</value>
</list>
</property>
<!--map-->
<property name="map">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="MYSQL" value="mysql"></entry>
</map>
</property>
</bean>
</beans>
测试
@Test
public void testStu() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanlist.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
stu.test();
}
结果
com.wexiao.spring5.collectiontype.Stu@4b5d6a01 [java, mysql] [java, mysql] {JAVA=java, MYSQL=mysql}
- 在集合里面设置对象类型值
<!--创建多个对象-->
<bean id="course1" class="com.wexiao.spring5.collectiontype.Course">
<property name="cname" value="111"></property>
</bean>
<bean id="course2" class="com.wexiao.spring5.collectiontype.Course">
<property name="cname" value="222"></property>
</bean>
<!--对象集合(使用 ref 标签)-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
测试
@Test
public void testStu1() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanlist.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
stu.test();
}
com.wexiao.spring5.collectiontype.Stu@61230f6a [java, mysql] [java, mysql] {JAVA=java, MYSQL=mysql} [Course{cname=’111’}, Course{cname=’222’}]
- 把集合注入部分提取出来
(1)在Spring 配置文件中引入名称空间 util
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
tree.java
package com.wexiao.spring5.collectiontype;
import java.util.List;
/**
* @author 微咲
* @version 1.0
*/
public class Tree {
private List<String> list;
public void setList(List<String> treeList) {
this.list = treeList;
}
@Override
public String toString() {
return "Tree{" +
"treeList=" + list +
'}';
}
}
(2)使用 util 标签完成 list 集合注入提取
xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--提取 list 集合属性-->
<util:list id="bookList">
<value>111</value>
<value>222</value>
<value>333</value>
</util:list>
<!--提取 list 集合属性注入使用-->
<bean id="tree" class="com.wexiao.spring5.collectiontype.Tree">
<property name="list" ref="bookList"></property>
</bean>
</beans>
测试
@Test
public void testTree() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanlistutil.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Tree tree = context.getBean("tree", Tree.class);
System.out.println(tree);
}
Tree{treeList=[111, 222, 333]}
FactoryBean
- Spring 有两种 bean,一种是普通 bean,另外一种工厂bean(FactoryBean)
- 普通 bean:在配置文件中定义 bean 类型( class )就是返回类型
- 工厂 bean:在配置文件中定义 bean 类型可以和返回类型不一样
- 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
- 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
MyBean.java
package com.wexiao.spring5.factorybean;
import com.wexiao.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;
/**
* @author wexiao
* @version 1.0
*/
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("111");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--工厂bean-->
<bean id="myBean" class="com.wexiao.spring5.factorybean.MyBean">
</bean>
</beans>
测试
@Test
public void facBean() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("factorybean.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
Course{cname=’111’}
bean 作用域
- 在 Spring 里,设置创建 bean 实例是单实例还是多实例
在 Spring 里,默认情况下,bean 是单实例对象
<bean id="book" class="com.wexiao.spring5.Book">
</bean>
@Test
public void testBook() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
//book.testDemo();
}
com.wexiao.spring5.Book@6fe7aac8 com.wexiao.spring5.Book@6fe7aac8
- 如何设置单实例还是多实例
1,在 Spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
2,scope 属性值:
a, 默认值,singleton,表示单实例对象
b, prototype,表示多实例对象
c, request
d, session
3,singleton 和 prototype 区别
a, singleton单实例,prototype多实例
b, 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建对象,在调用 getBean 方法时候创建多实例对象
<bean id="book" class="com.wexiao.spring5.Book" scope="prototype">
</bean>
@Test
public void testBook() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
//book.testDemo();
}
com.wexiao.spring5.Book@6fe7aac8 com.wexiao.spring5.Book@1d119efb
bean 生命周期
从对象创建到对象销毁的过程
- bean 声明周期
- 通过构造器创建bean实例(无参数构造)。
- 为bean的属性设置值和对其他 bean引用(调用set方法)
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- bean可以使用了(对象获取到了)
- 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
- 演示生命周期
BeanLife.java
package com.wexiao.spring5;
/**
* @author wexiao
* @version 1.0
*/
public class BeanLife {
private String life;
public BeanLife() {
System.out.println("第一步,执行无参构造创建bean实例");
}
public void setLife(String life) {
this.life = life;
System.out.println("第二步,调用set方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步,执行初始化方法");
}
//创建销毁的方法
public void destroyMethod(){
System.out.println("第五步,执行销毁的方法");
}
}
xml
init-method destroy-method
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="beanLife" class="com.wexiao.spring5.BeanLife" init-method="initMethod" destroy-method="destroyMethod">
<property name="life" value="LIFE"></property>
</bean>
</beans>
演示方法
@Test
public void BeanLife() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanlife.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
BeanLife beanLife = context.getBean("beanLife", BeanLife.class);
System.out.println("第四步,获取创建bean实例对象");
System.out.println(beanLife);
//手动让bean实例销毁
((ClassPathXmlApplicationContext)context).close();
}
第一步,执行无参构造创建bean实例 第二步,调用set方法设置属性值 第三步,执行初始化方法 第四步,获取创建bean实例对象 com.wexiao.spring5.BeanLife@59d016c9 第五步,执行销毁的方法
- bean 的后置处理器,bean 生命周期有七步
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他 bean引用(调用set方法)
- 把 bean 实例传递 bean 后置处理器的方法
postProcessBeforeInitialization
- 调用bean的初始化的方法(需要进行配置初始化的方法)
- 把 bean 实例传递 bean 后置处理器的方法
postProcessAfterInitialization
- bean可以使用了(对象获取到了)
- 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
- 演示添加后置处理器效果
MyBeanPost.java
package com.wexiao.spring5.beanlife;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
/**
* @author wexiao
* @version 1.0
*/
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="beanLife" class="com.wexiao.spring5.beanlife.BeanLife" init-method="initMethod" destroy-method="destroyMethod">
<property name="life" value="LIFE"></property>
</bean>
<!--配置后置处理器(所有bean)-->
<bean id="myBeanPost" class="com.wexiao.spring5.beanlife.MyBeanPost"></bean>
</beans>
演示方法
@Test
public void BeanLife() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanlife.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
BeanLife beanLife = context.getBean("beanLife", BeanLife.class);
System.out.println("第四步,获取创建bean实例对象");
System.out.println(beanLife);
//手动让bean实例销毁
((ClassPathXmlApplicationContext)context).close();
}
第一步,执行无参构造创建bean实例 第二步,调用set方法设置属性值 在初始化之前执行的方法 第三步,执行初始化方法 在初始化之后执行的方法 第四步,获取创建bean实例对象 com.wexiao.spring5.beanlife.BeanLife@3967e60c 第五步,执行销毁的方法
xml自动装配
手动装配:
- 什么是自动装配
根据指定装配规则(属性名或者属性类型),spring 自动将匹配的属性值进行注入
演示自动装配过程
xml引入外部属性文件
- 直接配置数据库信息
- 引入德鲁伊连接池依赖 jar 包 druid-1.1.10.jar
- 配置德鲁伊连接池
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <!--驱动名称-->
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property> <!--数据库地址-->
<property name="username" value="root"></property> <!--数据库用户名-->
<property name="password" value="root"></property> <!--数据库密码-->
</bean>
</beans>
- 引入外部属性文件配置数据库连接池
创建外部属性文件,properties 格式文件,写数据库信息
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.username=root
prop.password=root
把外部 properties 属性文件引入到 spring 配置文件中
- 引入名称空间
xmlns:context=”http://www.springframework.org/schema/context”
http://www.springframework.org/schema/context http://www.springframework.org/schema/util/spring-context.xsd
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/util/spring-context.xsd">
在 spring 配置文件使用标签引入外部属性文件 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
<a name="oHaMn"></a>
#### Bean操作 基于注解方式
- **什么是注解**
- 注解是代码特殊标记,格式。@注解名称(属性名称=属性值,属性名称=属性值..)
- 使用注解,注解在类上面,方法上面,属性上面
- 使用注解目的:简化 xml 配置
- **Spring 针对 Bean 管理中创建对象提供注解**
- @Component
- @Service
- @Controller
- @Repository
* 上面四个注解功能是一样的,都可以用来创建 bean 实例 (用于不同成中来区分不同层)
> Spring主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:
> @Component:可以用于注册所有bean
> @Repository:主要用于注册dao层的bean
> @Controller:主要用于注册控制层的bean
> @Service:主要用于注册服务层的bean
- **基于注解方式实现对象创建**
1. **引入依赖**
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1642659950351-3240bd3e-b951-4ed4-acad-234afc4c784e.png#clientId=u3cc49f97-7499-4&from=paste&height=165&id=u58bba5bb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=165&originWidth=371&originalType=binary&ratio=1&size=95652&status=done&style=none&taskId=u7dd85aaf-c029-485f-a7e5-4073e35cb1e&width=371)
2. **开启组件扫描**
xmlns:context="[http://www.springframework.org/schema/context"](http://www.springframework.org/schema/context")<br />[http://www.springframework.org/schema/context](http://www.springframework.org/schema/context) [http://www.springframework.org/schema/util/spring-context.xsd](http://www.springframework.org/schema/util/spring-context.xsd)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/util/spring-context.xsd">
<!--开启组件扫描
1. 如果扫描多个包,多个包使用逗号隔开
2. 扫描包上层目录
-->
<context:component-scan base-package="com.wexiao"></context:component-scan>
</beans>
开启组件扫描细节配置
- 创建类,在类上面添加创建对象注解 ```java package com.wexiao.spring5.annotation;
import org.springframework.stereotype.Component;
/**
- @author wexiao
- @version 1.0
*/
//在注解里面value属性值可以省略不写
//默认值是类名称,首字母小写
//Annotation1 — annotation1
@Component(value = “annotation1”) //
public class Annotation1 { public void test(){
} }System.out.println("test...");
**测试**
```java
@Test
public void testAdd() {
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanannotation.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
Annotation1 annotation1 = context.getBean("annotation1", Annotation1.class);
System.out.println(annotation1);
annotation1.test();
}
com.wexiao.spring5.annotation.Annotation1@4c402120 test…
基于注解方式实现属性注入
- @Autowired:根据属性类型进行自动装配(对象)
- 把service和dao对象创建,在service和 dao类添加创建对象注解
- 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解. ```java package com.wexiao.spring5.service;
import com.wexiao.spring5.dao.UserDao; import com.wexiao.spring5.dao.UserDaoImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service;
/**
- @author 微咲
@version 1.0 */ @Service public class UserService {
@Autowired private UserDao userDao;
//不需要set方法,注解注入 /* public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}*/
public void add() {
System.out.println("service add...");
userDao.update();
} }
**xml文件**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启组件扫描
1. 如果扫描多个包,多个包使用逗号隔开
2. 扫描包上层目录
-->
<context:component-scan base-package="com.wexiao"></context:component-scan>
</beans>
测试
@Test
public void testAnnotation1() { //属性注入
//1. 加载spring配置文件 ClassPathXmlApplicationContext:在src下 FileSystemXmlApplicationContext:某个文件夹下
ApplicationContext context = new ClassPathXmlApplicationContext("beanannotation.xml");
//2. 获取配置创建的对象 getBean(别名,类.class)
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
com.wexiao.spring5.service.UserService@198b6731 service add… dao update…
- @Qualifier:根据名称进行注入(对象)
这个@Qualifier 注解的使用,和上面 @Autowired 一起使用
//添加属性注入
@Autowired //根据类型注入
@Qualifier(value = "userDaoImpl1") //根据名称注入
private UserDao userDao;
- @Resource:可以根据类型注入,也可以根据名称注入(对象)
javax中的注解
import javax.annotation.Resource;
//@Resource //根据类型注入
@Resource(name = "userDaoImpl1") //根据名称注入
private UserDao userDao;
- @Value:注入普通类型属性(普通属性)
@Value(value = "111")
private String name;
完全注解开发
- 创建配置类,替代 xml 配置文件 ```java package com.wexiao.spring5.config;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;
/**
- @author wexiao
- @version 1.0 */
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {“com.wexiao”}) //组件扫描
}
2. **编写测试类**
不再是加载 xml 配置文件,而是加载 **spring配置类** AnnotationConfigApplicationContext(类.class)
```java
@Test
public void testConfig() {
//1. 加载spring配置类 AnnotationConfigApplicationContext(类.class)
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
//2. 获取配置创建的对象 getBean(别名,类.class)
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
AOP
什么是 AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
(3)使用登陆例子说明 AOP
AOP 底层原理
有两种情况动态代理
- 有接口情况,使用 JDK 动态代理
- 没有接口情况,使用 CGLIB 动态代理
JDK 动态代理
- 使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象
调用 newProxyInstance 方法
方法有三个参数:
- 类加载器
- 增强方法所在的类,这个类实现的接口。 支持多个接口
- 实现这个接口 InvocationHandler,创建代理对象,写增强的方法。
- 编写 JDK 动态代理代码
(1)创建接口,定义方法
package com.wexiao.spring5;
/**
* @author wexiao
* @version 1.0
*/
public interface UserDao {
public int add(int a, int b);
public String update(String id);
}
(2)创建接口实现类,实现方法
package com.wexiao.spring5;
/**
* @author wexiao
* @version 1.0
*/
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public String update(String id) {
return id;
}
}
(3)使用 Proxy 类创建接口代理对象
package com.wexiao.spring5;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
* @author wexiao
* @version 1.0
*/
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类 代理对象
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println(result);
}
}
//创建代理对象
class UserDaoProxy implements InvocationHandler {
//1. 传递 被代理对象
// 有参构造传递
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行..." + method.getName() + ",传递的参数:" + Arrays.toString(args));
//被增强的方法执行
Object res = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行..." + obj);
//返回执行方法
return res;
}
}
AOP 术语
- 连接点
类里面那些方法可以被增强,这些方法称为连接点
- 切入点
实际被增强的方法,称为切入点
- 通知(增强)
- 实际增强的逻辑部分称为通知(增强)
- 通知有多种类型
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知 [ finally ]
- 切面
动作,把通知应用到切入点的过程
AOP 准备操作
- Spring框架一般都是基于AspectJ实现AOP操作
什么是 AspectJ ?
*AspectJ不是Spring组成部分,独立AOP框架,一般把Aspect]和Spimg框架一起使用,进行AOP操作
- 基于AspestJ实现AOP操作
(1) 基于xml配置文件实现
(2) 基于注解方式实现(使用)
- 在项目工程里面引入 AOP 相关依赖
- 切入点表达式
- 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
- 语法结构:
execution( [权限修饰符] [返回类型] [类全路径] 方法名称)
举例1:对 com.wexiao.dao.BookDao 类里面的 add 进行增强
execution(* com.wexiao.dao.BookDao.add(…))
举例2:对 com.wexiao.dao.BookDao 类里面的所有方法进行增强
execution( com.wexiao.dao.BookDao.(…))
举例3:对 com.wexiao.dao包里所有类里面的所有方法进行增强
execution( com.wexiao.dao..*(…))
AOP操作(AspectJ 注解)
1. 创建类,在类里面定义方法
package com.wexiao.spring5.aopAnnotation;
/**
* 被增强的类
* @author wexiao
* @version 1.0
*/
public class User {
public void add(){
System.out.println("add... ");
}
}
2. 创建增强类(编写增强逻辑)
package com.wexiao.spring5.aopAnnotation;
/**
* 增强的类
* @author wexiao
* @version 1.0
*/
public class UserProxy {
//前置通知
public void before(){
System.out.println("before...");
}
}
3. 进行通知的配置
(1)在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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.wexiao.spring5.aopAnnotation"></context:component-scan>
</beans>
(2)使用注解创建User和 UserProxy对象
(3)在增强类上面添加注解@Aspect
@Aspect //AOP增强
(4)在spring配置文件中开启生成代理对象
<!--开启AspectJ生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!--找到@Aspect注解 生成代理对象-->
4. 配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置。
package com.wexiao.spring5.aopAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 增强的类
* @author wexiao
* @version 1.0
*/
@Component
@Aspect //AOP增强
public class UserProxy {
//前置通知
//@Before 注解表示作为前置通知
@Before(value = "execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void before(){
System.out.println("before...");
}
//后置通知
@After(value = "execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void after(){
System.out.println("after...");
}
//返回通知
@AfterReturning(value = "execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning...");
}
//异常通知
@AfterThrowing(value = "execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//环绕通知
@Around(value = "execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前...");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕后...");
}
}
测试
@Test
public void testAopAnnotation() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
环绕前… before… add… 环绕后… after… afterReturning…
5. 相同切入点抽取
package com.wexiao.spring5.aopAnnotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 增强的类
* @author wexiao
* @version 1.0
*/
@Component
@Aspect
public class UserProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void pointCut(){
}
//前置通知
//@Before 注解表示作为前置通知
@Before(value = "pointCut()")
public void before(){
System.out.println("before...");
}
//后置通知
@After(value = "pointCut()")
public void after(){
System.out.println("after...");
}
//返回通知
@AfterReturning(value = "pointCut()")
public void afterReturning(){
System.out.println("afterReturning...");
}
//异常通知
@AfterThrowing(value = "pointCut()")
public void afterThrowing(){
System.out.println("afterThrowing...");
}
//环绕通知
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前...");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.out.println("环绕后...");
}
}
6. 有多个增强类对同一个方法进行增强设置增强类的优先级
- 在增强类上面添加注解 @Order(数值类型值),数值类型值越小优先级越高
在原有基础上新添一个 增强类 UserProxy2
加入 @Order(1) 注解
package com.wexiao.spring5.aopAnnotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author wexiao
* @version 1.0
*/
@Component
@Aspect
@Order(1)
public class UserProxy2 {
//前置通知
//@Before 注解表示作为前置通知
@Before(value ="execution(* com.wexiao.spring5.aopAnnotation.User.add(..))")
public void before(){
System.out.println(" UserProxy2 before...");
}
}
原有增强类上 添加 @Order(2) 注解
测试后(运行 User的add方法)
@Test
public void testAopAnnotation() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
Person before… 环绕前… before… add… 环绕后… after… afterReturning…
7. 完全注解
- 配置文件 -> 配置类 ```java package com.wexiao.spring5.congif;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
- Spring 配置类
- @author wexiao
- @version 1.0 */
@Configuration
/
/
public class ConfigAop { }
2. **测试**
```java
@Test
public void testConfig() {
//1. 加载spring配置类 AnnotationConfigApplicationContext(类.class)
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);
//2. 获取配置创建的对象 getBean(别名,类.class)
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
AOP操作(AspectJ 配置文件)
1、创建两个类,增强类和被增强类,创建方法
Book.java
package com.wexiao.spring5.aopxml;
/**
* 被增强类
* @author wexiao
* @version 1.0
*/
public class Book {
public void buy(){
System.out.println("buy....");
}
}
BookProxy.java
package com.wexiao.spring5.aopxml;
/**
* 增强类
* @author wexiao
* @version 1.0
*/
public class BookProxy {
public void before(){
System.out.println("before...");
}
}
2、在spring配置文件中创建两个类对象
<!--创建对象-->
<bean id="book" class="com.wexiao.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.wexiao.spring5.aopxml.BookProxy"></bean>
3、在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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--创建对象-->
<bean id="book" class="com.wexiao.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.wexiao.spring5.aopxml.BookProxy"></bean>
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.wexiao.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy"> <!--增强类-->
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
</beans>
4、测试
@Test
public void testXml() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book = context.getBean("book", Book.class);
book.buy();
}
before… buy….
JdbcTempalte
什么是 JdbcTemplate
Spring 框架 对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作
准备工作
- 引入相关 jar包
在 spring 配置文件配置数据库连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql:///user_db"/>
<property name="username" value="root"/>
<property name="password" value="wexiao"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
配置 JdbcTemplate 对象,注入 DateSource
<!-- 创建 JdbcTemplate 对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入 dateSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
- 创建 service 类,创建 dao类,在 dao 注入 JdbcTemplate 对象
配置文件
<!--开启组件扫描 扫描注解-->
<context:component-scan base-package="com.wexiao"></context:component-scan>
Service ```java package com.wexiao.spring5.service;
import com.wexiao.spring5.dao.BookDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
/**
- @author wexiao
- @version 1.0 */
@Service public class BookService {
//注入 dao
@Autowired
private BookDao bookDao;
}
- dao
```java
package com.wexiao.spring5.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* @author wexiao
* @version 1.0
*/
@Repository
public class BookDaoImpl implements BookDao {
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
}
JdbcTemplate 操作数据库 (添加为例)
- 创建数据库,建立数据库对应的实体类
数据库
CREATE DATABASE user_db
CREATE TABLE `t_book` (
user_id INT,
`username` VARCHAR(255),
`ustatus` VARCHAR(255)
) ;
实体类 ```java package com.wexiao.spring5.entity;
/**
- @author wexiao
@version 1.0 */ public class Book { private String userId;
public void setUserId(String userId) {
this.userId = userId;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setUstatus(String ustatus) {
this.ustatus = ustatus;
}
private String userName; private String ustatus;
public String getUserId() {
return userId;
}
public String getUserName() {
return userName;
}
public String getUstatus() {
return ustatus;
} }
2. **编写 service 和 dao**
(1)在 dao 进行数据库添加操作
```java
package com.wexiao.spring5.dao;
import com.wexiao.spring5.entity.Book;
/**
* @author wexiao
* @version 1.0
*/
public interface BookDao {
//添加
void add(Book book);
}
(2)调用 JdbcTemplate 对象里面 update 方法实现添加操作
- 有两个参数
- 第一个参数:sql 语句
第二个参数:可变参数,设置 sql 语句值
BookDaoImpl ```java package com.wexiao.spring5.dao;
import com.wexiao.spring5.entity.Book; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository;
/**
- @author wexiao
- @version 1.0 */
@Repository public class BookDaoImpl implements BookDao {
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
//添加
@Override
public void add(Book book) {
// 1.创建sql语句
String sql = "insert into t_book values(?,?,?)";
// 2.调用方法实现
//Object[] args = {book.getUserId(), book.getUserName(), book.getUstatus()};
int update = jdbcTemplate.update(sql, book.getUserId(), book.getUserName(), book.getUstatus());
System.out.println(update);
}
}
- BookService
```java
package com.wexiao.spring5.service;
import com.wexiao.spring5.dao.BookDao;
import com.wexiao.spring5.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author wexiao
* @version 1.0
*/
@Service
public class BookService {
//注入 dao
@Autowired
private BookDao bookDao;
//添加
public void addBook(Book book){
bookDao.add(book);
}
//修改
//删除
}
- TestBook ```java package com.wexiao.spring5.test;
import com.wexiao.spring5.entity.Book; import com.wexiao.spring5.service.BookService; import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
- @author wexiao
@version 1.0 */ public class TestBook {
@Test public void testJdbcTemplate(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setUserId("1");
book.setUserName("1");
book.setUstatus("1");
//添加 book 一条实例
bookService.addBook(book);
} }
> 1
<a name="pfMnF"></a>
### JdbcTemplate 操作数据库 (查询)
[查询](https://www.bilibili.com/video/BV1Vf4y127N5?p=36&spm_id_from=pageDriver)
1. **查询表记录数**
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645865970282-e78e7c80-98d9-418c-b52a-fa5eb7a8c12f.png#clientId=u22b5ae5b-033a-4&from=paste&height=230&id=ue29f3005&margin=%5Bobject%20Object%5D&name=image.png&originHeight=273&originWidth=886&originalType=binary&ratio=1&size=146389&status=done&style=none&taskId=u3a01d51b-7ce5-4062-907f-f6ff184ce7e&width=745.9942626953125)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645865809025-96c994fe-83c1-4bdb-a6a0-00caef49dd7c.png#clientId=u22b5ae5b-033a-4&from=paste&height=51&id=u0bc4ad3e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=51&originWidth=997&originalType=binary&ratio=1&size=79955&status=done&style=none&taskId=u455ced2a-43ae-4f9f-a215-5e5bd3aed05&width=997)
- 有两个参数
- 第一个参数:sql 语句
- 第二个参数:返回类型 . Class (String.class)
2. **查询返回对象**
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645866547449-95fe65e3-995c-4e13-ba78-f61c2598c0c1.png#clientId=u22b5ae5b-033a-4&from=paste&height=254&id=u6cba4c50&margin=%5Bobject%20Object%5D&name=image.png&originHeight=320&originWidth=1354&originalType=binary&ratio=1&size=234442&status=done&style=none&taskId=ued062bbd-70d2-4d80-84fa-129ef91dd26&width=1076.1817626953125)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645866241027-37b4cd8a-6c68-426c-9fba-14e3f79b1638.png#clientId=u22b5ae5b-033a-4&from=paste&height=46&id=ub0a7a251&margin=%5Bobject%20Object%5D&name=image.png&originHeight=46&originWidth=1087&originalType=binary&ratio=1&size=77274&status=done&style=none&taskId=ub2158eeb-2d41-4893-bb64-a2ca273180c&width=1087)
- 有三个参数
- 第一个参数:sql 语句
- 第二个参数:RowMapper,是接口,针对 返回不同类型数据,使用这个接口里面实现类完成数据封装
- 第三个参数:sql 语句值(?)
3. **查询返回集合**
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645866828088-d4438fb4-03d4-4ef2-9ce5-9db44ad2b851.png#clientId=u22b5ae5b-033a-4&from=paste&height=266&id=u165bff51&margin=%5Bobject%20Object%5D&name=image.png&originHeight=315&originWidth=1271&originalType=binary&ratio=1&size=175784&status=done&style=none&taskId=u158b53b3-d920-418b-adc1-9a96dc3f389&width=1071.9942626953125)
query<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645866758110-37100393-e3b3-44b6-b102-21ba5f526b88.png#clientId=u22b5ae5b-033a-4&from=paste&height=52&id=u7ba9c100&margin=%5Bobject%20Object%5D&name=image.png&originHeight=52&originWidth=1085&originalType=binary&ratio=1&size=82131&status=done&style=none&taskId=ua45005c8-cb3c-479a-86e4-23aa22ca0d8&width=1085)
- 有三个参数
- 第一个参数:sql 语句
- 第二个参数:RowMapper,是接口,针对 返回不同类型数据,使用这个接口里面实现类完成数据封装
- 第三个参数:sql 语句值(?)
<a name="uHmTy"></a>
### JdbcTemplate 操作数据库 (批量操作)
<a name="fXWf3"></a>
#### 批量添加
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645867271811-93d0b733-767c-4281-9f2e-17a6ac758daa.png#clientId=u22b5ae5b-033a-4&from=paste&height=274&id=u9f1d3849&margin=%5Bobject%20Object%5D&name=image.png&originHeight=294&originWidth=811&originalType=binary&ratio=1&size=179401&status=done&style=none&taskId=udc9f6b0d-a5e5-4618-bb7d-489bda47044&width=756.9942626953125)
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645866983282-03752139-1fba-4e88-90b3-bde3f40536e3.png#clientId=u22b5ae5b-033a-4&from=paste&height=50&id=u1c69e56c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=50&originWidth=986&originalType=binary&ratio=1&size=88591&status=done&style=none&taskId=u7c70ead8-4d95-4e0b-b4c4-72785c0d4cb&width=986)
- 有两个参数
- 第一个参数:sql 语句
- 第二个参数:List 集合,添加多条记录数据
**测试:**<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645867391049-11c02240-e8fa-46b9-8bb7-33a01e758bc5.png#clientId=u22b5ae5b-033a-4&from=paste&height=385&id=ud4387068&margin=%5Bobject%20Object%5D&name=image.png&originHeight=385&originWidth=659&originalType=binary&ratio=1&size=184421&status=done&style=none&taskId=u6240f0bf-0176-472e-ad71-b09b21a0670&width=659)
> [1, 1, 1]
<a name="ZQwx4"></a>
#### 批量修改
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645867653632-cd636451-d4d8-45b8-b54c-154179f81e2a.png#clientId=u22b5ae5b-033a-4&from=paste&height=232&id=u8ddf652e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=271&originWidth=956&originalType=binary&ratio=1&size=166744&status=done&style=none&taskId=u314ec37e-e364-47f0-a119-f6580736906&width=818.9942626953125)
**测试:**<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645867715406-e09ca85e-d8e3-4cef-9cae-294ddba761c9.png#clientId=u22b5ae5b-033a-4&from=paste&height=331&id=uc8e15325&margin=%5Bobject%20Object%5D&name=image.png&originHeight=397&originWidth=629&originalType=binary&ratio=1&size=218006&status=done&style=none&taskId=ue03f2277-7f5c-46c2-9ddc-e252d992eab&width=524.991455078125)
<a name="EJCDa"></a>
#### 批量删除
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645867753162-359daa2e-368e-42bd-81d8-7d3e82568549.png#clientId=u22b5ae5b-033a-4&from=paste&height=239&id=u4fef1a50&margin=%5Bobject%20Object%5D&name=image.png&originHeight=276&originWidth=829&originalType=binary&ratio=1&size=155028&status=done&style=none&taskId=u4a007be1-b2b0-4d14-8787-2f2666f17eb&width=716.991455078125)
**测试:**<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645867796187-a7e83522-604b-449f-9ed7-9108e59e76c6.png#clientId=u22b5ae5b-033a-4&from=paste&height=247&id=u44dc404d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=370&originWidth=708&originalType=binary&ratio=1&size=152349&status=done&style=none&taskId=u84b2033a-e69d-4b72-a64a-cc627de091b&width=472.98858642578125)
<a name="Ib30w"></a>
## 事务
<a name="zDv4W"></a>
### 什么是事务
- 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败,所有操作都会失败
- 典型场景:银行转账
<a name="XbE6p"></a>
### 事务的四个特性(ACID)
**1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一 样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。**<br />**2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。**<br />**3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。**<br />**4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。**
<a name="Bybta"></a>
### 事务操作(搭建事务操作环境(转账环境))
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645929731107-6387a4fc-cad5-4605-b21d-acdc6fbd3c20.png#clientId=u22b5ae5b-033a-4&from=paste&height=338&id=u9f66faa3&margin=%5Bobject%20Object%5D&name=image.png&originHeight=576&originWidth=1595&originalType=binary&ratio=1&size=146739&status=done&style=none&taskId=u30ec161a-fa34-461e-8660-f1a04cfa4c8&width=935.1817626953125)
1. **创建数据库表,添加记录**
> CREATE TABLE `t_account` (
> `id` INT,
> `username` VARCHAR(255),
> `money` VARCHAR(255)
> ) ;
![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1645930265049-2bffa5f0-595c-4b22-9d51-d585854b1c47.png#clientId=u22b5ae5b-033a-4&from=paste&height=84&id=u678046f4&margin=%5Bobject%20Object%5D&name=image.png&originHeight=97&originWidth=343&originalType=binary&ratio=1&size=5404&status=done&style=none&taskId=u8ebb2971-1e33-4148-bbd8-5c028cdc387&width=296.9971618652344)
2. **创建 service,搭建 dao ,完成对象创建和注入关系**
service 注入 dao,在dao 中注入 JdbcTemplate,在JdbcTemplate 注入 DateSource
3. **在dao创建两个方法 : 多钱和少钱的方法,在service创建方法(转账的方法),**
事务:<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1646145133052-81827591-f090-4759-82a2-69cd0d33b72e.png#clientId=u375fe5d6-f29b-4&from=paste&height=425&id=ue4627f0c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=774&originWidth=804&originalType=binary&ratio=1&size=299572&status=done&style=none&taskId=uc81a9dd9-0f54-4ea4-9928-58fed4abc3c&width=440.991455078125)<br />(编程式)
<a name="zm5Bl"></a>
### Spring 事务管理介绍
- 事务添加到JavaEE.三层结构里面Service层(业务逻辑层) [ web service dao ]
- 在 Spring进行事务管理操作有两种方式 : **编程式事务管理** 和 **声明式事务管理(使用)**
- 声明式事务管理
- **基于注解方式(使用)**
- 基于xml配置文件方式
- 在Spring进行声明式事务管理,底层**使用AOP原理**
<br />
- **Spring 事务管理API**
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2755207/1646146323342-cff085f6-4ebf-4a43-acfd-d2f866b33f6d.png#clientId=u9d6b3035-17b1-4&from=paste&height=233&id=ude3817da&margin=%5Bobject%20Object%5D&name=image.png&originHeight=217&originWidth=624&originalType=binary&ratio=1&size=267750&status=done&style=none&taskId=uc6f7ad5f-d651-4de3-96fe-ed26d7af6b1&width=670.991455078125)
<a name="FN95t"></a>
### 声明式事务管理-----注解
1. **在 Spring 配置文件配置事务管理器**
```xml
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
- 在 spring 配置文件,开启事务注解
1、在 spring 配置文件引入名称空间 tx
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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/context http://www.springframework.org/schema/context/spring-context.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">
2、开启事务注解
<!--开启事务注解,导入事务管理器-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在 service 类上面(或者 service类里面的方法上面)添加事务注解
- @Transactional,这个注解可以添加到类上面,也可以添加到方法上面。
- 如果把这个注解添加到类上面,会为这个类里面的所有的方法都添加事务。
- 如果把这个注解添加到方法上面,会为这个方法添加事务。
声明式事务管理——-@Transactional 注解参数配置
- propagation:事务传播行为
@Transactional (propagation = Propagation.REQUIRED)
1、传播行为:多事务方法直接进行调用,这个过程中事务是如何进行管理的。
2、事务方法:对数据库表数据进行变化的操作。
Spring 7 种事务传播行为:
- isolation:事务的隔离级别
@Transactional (isolation= Isolation.REPEATABLE_READ)
1、事务有隔离性,多事务操作之间不会产生影响。
2、不考虑隔离性有三个问题:脏读,不可重复读,虚(幻)读。
- 脏读(dirty read):当一个事务读取另一个事务尚未提交的改变(update,insert,delete)时,产生脏读
- 不可重复读(nonrepeatable read):同一查询在同一事务中多次进行,由于其他提交事务所做 (commit,已提交的) 的修改或删除,每次返回不同的结果集,此时发生不可重复读。
- 幻读(phantom read):同一查询在同一事务中多次进行,由于其他提交事务所做 (commit,已提交的)的插入操作,每次返回不同的结果集,此时发生幻读。
解决:
通过设置事务隔离级别,解决读问题。
mysql 默认事务隔离级别:REPEATABLE_READ
- timeout:超时时间
@Transactional (time= -1)
1、事务需要在一定时间内进行提交,如果不提交进行回滚。
2、默认值是-1,设置时间以秒单位进行计算。
- readOnly:是否只读
@Transactional (readOnly = false)
1、读 : 查询操作, 写 : 添加修改删除操作
2、readOnly 默认值 false,表示可以查询,可以添加修改删除操作,
3、设置readOnly 值是true,只能查询
- rollbackFor:回滚
@Transactional (rollbackFor= 异常class)
设置出现哪些异常进行事务回滚。
- norollbackFor:不回滚
设置出现哪些异常不进行事务回滚。
声明式事务管理——-完全注解
代理类
package com.wexiao.spring5.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* @author wexiao
* @version 1.0
*/
@Configuration //配置类
@ComponentScan(basePackages = "com.wexiao") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl("");
dataSource.setUsername("");
dataSource.setUrl("");
dataSource.setPassword("");
return dataSource;
}
//创建 JdbcTemplate对象
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
//到 ioc 容器中 根据类型找到 DataSource (自动注入)(自动装配)
JdbcTemplate jdbcTemplate = new JdbcTemplate();
//注入dataSource
jdbcTemplate.setDataSource(dataSource);
//jdbcTemplate.setDataSource(getDruidDataSource());
return jdbcTemplate;
}
//创建事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
//注入数据源
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
这个在配置类中应该怎么表现呢???????????????????????????
视频中没有表现也成功了。。。。。
声明式事务管理——-XML
在 Spring 配置文件中进行配置
配置事务管理器 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
<!--创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
2. 配置通知
```xml
<!--2. 配置通知-->
<tx:advice id="txadvice">
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="addBook" />
<!--<tx:method name="add*"/>-->
</tx:attributes>
</tx:advice>
- 配置切入点和切面
<!--3. 配置切入点和切面-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.wexiao.spring5.service.BookService.*(..))"/>
<!--配置切面,将事务添加到方法上-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
</aop:config>
Spring5 框架新功能
新功能
- 整个 Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除,
- Spring 5.0框架自带了通用的日志封装;
(1) Spring5已经移除 Log4jConfigListener,官方建议使用Log4j2
(2) Spring5框架整合 Log4j2
………………………
……
..
整合 Log4j2
第一步 引入 jar包
第二步 创建 log4j2.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--⽇志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后⾯的status,这个⽤于设置log4j2⾃⾝内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出-->
<!--monitorInterval:Log4j能够⾃动检测修改配置⽂件和重新配置本⾝,设置间隔秒数-->
<configuration status="WARN" monitorInterval="30">
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<console name="Console" target="SYSTEM_OUT">
<!--输出⽇志的格式-->
<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
</console>
</appenders>
<!--然后定义logger,只有定义了logger并引⼊的appender,appender才会⽣效-->
<!--root:用于指定项目的根日志,如果没有单独指定 Logger,则会使用root作为默认的日志输出-->
<loggers>
<root level="info">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
测试 log4j2
package com.wexiao.spring5.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author wexiao
* @version 1.0
*/
public class UserLog {
//package org.slf4j
private static final Logger log = LoggerFactory.getLogger(UserLog.class);
public static void main(String[] args) {
log.info("hello log4j");
log.warn("hello log4j");
}
}
[21:09:27:708] [INFO] - com.wexiao.spring5.test.UserLog.main(UserLog.java:16) - hello log4j [21:09:27:710] [WARN] - com.wexiao.spring5.test.UserLog.main(UserLog.java:17) - hello log4j
Spring5 框架核心容器支持@Nullable注解
@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空
- 使用在方法上,方法返回值可以为空:
- 使用在方法的参数上,方法的参数可以为空:
- 使用在属性上面,属性可以为空
Spring5 核心容器支持函数式风格 GenericApplicationContext
package com.wexiao.spring5.test;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.lang.Nullable;
/**
* @author wexiao
* @version 1.0
*/
public class TestTest {
//函数式风格创建对象,交给 spring进行管理
@Test
public void testGenericApplicationContext(){
//1. 创建GenericApplicationContext对象
GenericApplicationContext context = new GenericApplicationContext();
//2. 调用context的方法对象注册
context.refresh();
context.registerBean(User.class,() -> new User());
context.registerBean("user1",User.class,() -> new User()); //@Nullable beanName
//3. 获取在spring注册的对象
User user = (User) context.getBean("com.wexiao.spring5.test.User");
//User user = (User) context.getBean("user1"); //也可以填写上面的beanName
System.out.println(user);
}
}
Spring5 支持整合 JUnit5
整合 JUnit4
第一步 引入 Spring 相关针对测试依赖
第二步 创建测试类,使用注解方式完成
package com.wexiao.spring5.test;
import com.wexiao.spring5.entity.Book;
import com.wexiao.spring5.service.BookService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author wexiao
* @version 1.0
*/
@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class JTest4 {
@Autowired
private BookService bookService;
@Test
public void test1(){
bookService.addBook(new Book());
}
}
<?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"
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/context http://www.springframework.org/schema/context/spring-context.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">
<!--开启组件扫描 扫描注解-->
<context:component-scan base-package="com.wexiao"></context:component-scan>
</beans>
@Service
public class BookService{
}
整合 JUnit5
第一步 引入 JUnit5 的 jar包
第二步 创建测试类,使用注解
package com.wexiao.spring5.test;
import com.wexiao.spring5.entity.Book;
import com.wexiao.spring5.service.BookService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* @author wexiao
* @version 1.0
*/
//@ExtendWith(SpringExtension.class) //单元测试框架
//@ContextConfiguration("classpath:bean1.xml") //加载配置文件
@SpringJUnitConfig(locations = "classpath:bean1.xml") //复合注解,替代上面的两个注解,完成Junit5整合
public class JTest5 {
@Autowired
private BookService bookService;
@Test
public void test1(){
bookService.addBook(new Book());
}
}
@ExtendWith(SpringExtension.class) //单元测试框架
@ContextConfiguration(“classpath:bean1.xml”) //加载配置文件
@SpringJUnitConfig(locations = “classpath:bean1.xml”) //复合注解,替代上面的两个注解,完成Junit5整合
Webflux
基于 SpringMVC、SpringBoot、Maven、Java8新特性。(补知识点去了,2022年3月3日10:55:18)
06:13
SpringWebfiux 介绍
(1)是Spring5添加新的模块,用于web开发的,功能和SpringMVC类似的,Webflux使用当前一种比较流程响应式编程出现的框架。
(2)使用传统 web框架,比如SpringMVC,这些基于Servlet,容器,Webflux是一种异步非阻塞的框架,异步非阻塞的框架在Servlet3.1以后才支持,核心是基于Reactor的相关API实现的。
(3)