框架spring
一、概述
3.1 Spring是轻量级的开源JavaEE框架
3.2 Spring可以解决企业应用开发的复杂性
3.3 Spring有两个核心部分:IOC 和 AOP
(1)IOC:控制反转,把创建对象过程交给Spring管理
(2)AOP:面向切面,不修改源代码进行功能增强
3.4 Spring特点:
(1)方便解耦,简化开发
(2)Aop编程支持
(3)方便程序测试
(4)方便和其它框架进行整合
(5)方便进行事务操作
(6)降低API开发难度
二、入门案例
2.1 Spring下载
下载地址:repo.spring.io
2.2 创建普通java工程
2.3 导入jar包
Spring需要的基础核心包包括如下四个(还要加上commons-logging包 这个包不是Spring的包但是Spring需要依赖到这个包)
因为创建的是普通java项目所以需要在目录下创建一个lib文件夹,并把上述包导入到lib下
2.4 创建普通类 在类中创建普通方法

2.5 创建Spring配置文件,在配置文件中配置创建的对象

2.6 测试代码的编写

public class Spring5Test { @Test public void testAdd(){ // 1.加载Spring配置文件 ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml"); // 2. 获取对象 User user = classPathXmlApplicationContext.getBean("user",User.class); // 3. 测试 user.add(); } }
三、IOC
3.1 IOC基本概念和原理
1、什么是IOC:
(1)控制反转:把对象创建和对象之间的调用过程,交给Spring管理
(2)使用IOC目的:降低耦合度
(3)入门案例即为IOC实现
2、IOC底层原理
3.2.1 xml解析、工厂模式、反射



3.2.2 IOC接口
- IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
- Spring提供IOC容器两种实现方式:(两个接口)
- BeanFactory: IOC容器的基本实现接口,是Spring内部的使用接口,一般不提供给开发人员进行使用。
特点:加载配置文件时不会创建对象,在获取(使用)对象时才去创建 - ApplicationContext: BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用(因为把对象的创建放在项目启动过程会更好)。
特点:在加载配置文件时就会把配置文件的对象进行创建
- BeanFactory: IOC容器的基本实现接口,是Spring内部的使用接口,一般不提供给开发人员进行使用。
- ApplicationContext的实现类:
- FileSystemXmlApplicationContext : 路径需要用硬盘中的全路径
ApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("D:\\study\\Spring\\Spring5_JavaProjectTest\\src\\spring_bean1.xml"); - ClassPathXmlApplicationContext:路径用src资源下的类路径即可
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml");
- FileSystemXmlApplicationContext : 路径需要用硬盘中的全路径
3.2 IOC Bean管理
3.2.1 什么是Bean管理?
Bean管理指两个操作: 1)Spring创建对象 2)Spring注入属性
Bean管理的两种方式:1)基于xml配置文件方式实现 2)基于注解方式实现
3.2.2 基于xml方式的Bean管理
1、基于XML方式创建对象
<bean id="user" class="com.lili.spring.User"></bean>
(1)在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
(2)bean标签中的常用属性:
id: 唯一标识
class:类全路径
(3)创建对象时默认使用对象类的无参构造创建
2、基于XML方式注入属性
(1)DI:依赖注入,就是注入属性。
(2)注入属性方式一:用set注入
public class Book { private String bname; public void setBname(String bname){ this.bname = bname; } @Override public String toString() { return "Book{" + "bname='" + bname + '\'' + '}'; } } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.lili.spring.User"></bean> <bean id="book" class="com.lili.spring.pojo.Book"> <property name="bname" value="易经"></property> </bean> </beans> public void testBookDI(){ ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml"); Book book = classPathXmlApplicationContext.getBean("book", Book.class); book.toString(); }
(3)第二种注入方式:使用有参数构造进行注入
public class Orders { private String oname; private String address; public Orders(String oname, String address) { this.oname = oname; this.address = address; } @Override public String toString() { return "Orders{" + "oname='" + oname + '\'' + ", address='" + address + '\'' + '}'; } } <bean id="orders" class="com.lili.spring.pojo.Orders"> <constructor-arg name="oname" value="lili"></constructor-arg> <constructor-arg name="address" value="china"></constructor-arg> </bean> @Test public void testOrdersConstructorDI(){ ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml"); Orders orders = classPathXmlApplicationContext.getBean("orders", Orders.class); System.out.println(orders.toString()); }
(4) p名称空间注入: 简化xml注入方式 只做了解(使用不多)
a) 添加一行xml约束

b)进行属性注入
<bean id="pbook" class="com.lili.spring.pojo.Book" p:bname="lili"></bean>
(5)其它类型的属性注入
a)字面量
null值:
<!-- 属性注入为空值 -->
<bean id="nullBookName" class="com.lili.spring.pojo.Book">
<property name="bname">
<null/>
</property>
</bean>
属性值包含特殊符号:
<!-- 属性值中有特殊符号 -->
<bean id="specBookName" class="com.lili.spring.pojo.Book">
<property name="bname">
<value><![CDATA[<<南京>>]]></value>
</property>
</bean>
b)注入属性-外部bean
创建两个类 service类和dao类
在service类中调用dao类的方法
在配置文件中进行配置
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("dao update");
}
}
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("service....");
userDao.update();
}
}
<!-- 外部bean注入 -->
<bean id="userDaoImpl" class="com.lili.spring.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.lili.spring.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
@Test
public void testUserService(){
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml");
UserService userService = classPathXmlApplicationContext.getBean("userService", UserService.class);
userService.add();
}
c) 注入属性-内部bean
一对多关系:部门和员工
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"dname='" + dname + '\'' +
'}';
}
}
public class Emp {
private String ename;
private String gender;
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"ename='" + ename + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept.toString() +
'}';
}
}
<!-- 内部bean与级联赋值 -->
<bean id="emp" class="com.lili.spring.pojo.Emp">
<property name="ename" value="lili"></property>
<property name="gender" value="woman"></property>
<property name="dept">
<bean id="dept" class="com.lili.spring.pojo.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
@Test
public void testInnerDi(){
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml");
Emp emp = classPathXmlApplicationContext.getBean("emp", Emp.class);
System.out.println(emp.toString());
}
d) 注入属性--级联属性
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"dname='" + dname + '\'' +
'}';
}
}
public class Emp {
private String ename;
private String gender;
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public Dept getDept() {
return dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"ename='" + ename + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept.toString() +
'}';
}
}
<!-- 级联赋值 -->
<bean id="emp" class="com.lili.spring.pojo.Emp">
<property name="ename" value="lili"></property>
<property name="gender" value="woman"></property>
<property name="dept" ref="dept"></property>
<!-- 注意 这里需要emp bean类中需要提供getDept方法 -->
<property name="dept.dname" value="管理"></property>
</bean>
<bean id="dept" class="com.lili.spring.pojo.Dept">
<property name="dname" value="安保部"></property>
</bean>
e) 注入属性--集合属性
public class ListStudent {
private String[] courses;
private List<String> list;
private Map<String,String> maps;
private Set<String> sets;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
@Override
public String toString() {
return "ListStudent{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", maps=" + maps +
", sets=" + sets +
'}';
}
}
<!-- 集合注入 -->
<bean id="listStu" class="com.lili.spring.pojo.ListStudent">
<property name="courses">
<array>
<value>c</value>
<value>java</value>
</array>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="maps">
<map>
<entry key="lili" value="lilivalue"></entry>
</map>
</property>
<property name="sets">
<set>
<value>setvalye1</value>
<value>set2value</value>
</set>
</property>
</bean>
@Test
public void testListDi(){
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml");
Object listStu = classPathXmlApplicationContext.getBean("listStu");
System.out.println(listStu.toString());
}
在集合里面设置对象类型值
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
}
public class ListStudent {
private String[] courses;
private List<String> list;
private Map<String,String> maps;
private Set<String> sets;
private List<Course> courseList;
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
@Override
public String toString() {
return "ListStudent{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", maps=" + maps +
", sets=" + sets +
'}';
}
}
<!-- 在集合里面设置对象类型值 -->
<bean id="listStu" class="com.lili.spring.pojo.ListStudent">
<property name="courses">
<array>
<value>c</value>
<value>java</value>
</array>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<property name="maps">
<map>
<entry key="lili" value="lilivalue"></entry>
</map>
</property>
<property name="sets">
<set>
<value>setvalye1</value>
<value>set2value</value>
</set>
</property>
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="com.lili.spring.pojo.Course">
<property name="cname" value="c"></property>
</bean>
<bean id="course2" class="com.lili.spring.pojo.Course">
<property name="cname" value="java"></property>
</bean>
把集合注入部分提取出来
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:p="http://www.springframework.org/schema/p"
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"
>
2) 使用util标签完成list集合注入提取
public class Book {
private String bname;
private List<String> list;
public void setBname(String bname){
this.bname = bname;
}
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
'}';
}
}
<!-- 使用util标签完成list集合注入提取 -->
<util:list id="bookList">
<value>易经</value>
<value>九阳神功</value>
</util:list>
<bean id="bookList" class="com.lili.spring.pojo.Book">
<property name="list" ref="bookList"></property>
</bean>
(6)IOC操作Bean管理(FactoryBean)
Spring有两种bean类型,一种是普通bean另一种是工厂bean
普通bean:在配置文件中定义的bean类型就是返回类型
工厂bean:在配置文件定义bean类型可以和返回类型不一样。
第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
第二步:实现接口里面的方法,在实现方法中定义返回的bean类型
public class FactoryBean implements org.springframework.beans.factory.FactoryBean<Course> {
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("java");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return org.springframework.beans.factory.FactoryBean.super.isSingleton();
}
}
<!-- 实现接口里面的方法,在实现方法中定义返回的bean类型 -->
<bean id="factoryBean" class="com.lili.spring.pojo.factorybeans.FactoryBean"></bean>
@Test
public void factoryTest(){
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring_bean1.xml");
Course course = classPathXmlApplicationContext.getBean("factoryBean", Course.class);
System.out.println(course.toString());
}
(7)IOC操作Bean管理(bean作用域)
设置单实例和多实例:默认是单实例
<bean id="user" class="com.lili.spring.pojo.User" scope="prototype"></bean>
<bean id="user" class="com.lili.spring.pojo.User" scope="singleton"></bean>
singleton和prototype区别:
1) singleton创建单实例 prototype创建多实例
2)singleton时,ClassPathXmlApplicationContext加载spring配置文件时就会创建对象实例
prototype,ClassPathXmlApplicationContext加载spring配置文件时不会创建对象实例,在使用时创建
request,session
(8) IOC Bean生命周期
没有配置后置处理器共五步:
(1) 通过构造器创建bean对象(无参)
(2)为bean属性设置值和其它bean引用(set方法)
(3)调用bean的初始化方法(需要进行配置初始化方法)
(4)bean可用
(5)容器关闭时调用bean的销毁方法(需要配置销毁方法)
<bean id="user" class="com.lili.spring.pojo.User" scope="singleton" init-method="initMethod" destroy-method="destoryMethod"></bean>
配置后置处理器时共七步:
(1) 通过构造器创建bean对象(无参)
(2)为bean属性设置值和其它bean引用(set方法)
(3) 把bean的实例传递给bean后置处理器方法 (postProcessBeforeInitialization方法)
(4)调用bean的初始化方法(需要进行配置初始化方法)
(5) 把bean的实例传递给bean后置处理器方法 (postProcessAfterInitialization方法)
(6)bean可用
(7)容器关闭时调用bean的销毁方法(需要配置销毁方法)
演示:
1)创建类 实现接口BeanPostProcessor,创建后置处理器
3.IOC操作Bean管理(xml自动装配)
3.1 什么是自动装配? 根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行注入
public class Dept {
}
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
}
<!-- 实现自动装配
bean标签的autowire 配置自动装配
autowire属性:
byName:根据属性名称注入 注入值bean的id值和类属性名相同
byType:根据属性类型注入 但有两个相同类型的bean时报错 r如下 有dept1 dept2 emp1的autowire报错
-->
<bean id="emp1" class="com.lili.spring.autowire.Emp" autowire="byName"></bean>
<bean id="emp1" class="com.lili.spring.autowire.Emp" autowire="byType"></bean>
<bean id="dept1" class="com.lili.spring.autowire.Dept"></bean>
<bean id="dept2" class="com.lili.spring.autowire.Dept"></bean>
4.IOC操作Bean管理(外部属性文件)
4.1 引入druid的jar包
4.2 直接配置

4.3 创建properties文件

4.4 修改配置文件


3.2.3 基于注解方式的Bean管理

1、基于注解方式创建对象:
1)引入依赖
![]()
2)开启注解扫描
注意 要加上context约束

3)添加注解

2. 注解扫描配置


3. 基于注解方式注入属性
(1)@Autowired : 根据属性类型自动装配

(2) @Qualifier : 根据属性名称进行注入 (spring中提供的 建议)
和@Autowired一起使用。

(3) @Resource : 可以根据属性类型也可以根据属性名称进行注入 (javax中提供的 不建议使用)

(4)@Value : 注入普通类型
4. 纯注解开发
4.1 创建配置类 替代xml配置文件

4.2 编写测试类

四、AOP
4.1 AOP概述

AOP底层原理:
1、AOP底层使用动态代理
(1)有两种情况:
第一种:有接口情况,使用JDK动态代理

第二种:无接口情况,使用CGLIB动态代理

AOP使用
1、Proxy类(使用Proxy类里面的方法创建)


2、编写JDK动态代理代码



3、相关术语:
连接点:![]()
切入点:真正被增强的方法
通知/增强:实际增强的逻辑部分:
前置通知/后置~/环绕~/异常~最终~
切面:动作,把通知应用到切入点的过程
AOP操作(准备)




4.2 Aspect注解方式

3、进行通知的配置
1)添加配置aop context配置约束 开启注解扫描

2) 创建User UserProxy类

3) 在增强类上添加@Aspect

4) 开启Aspect生成代理对象

4、配置不同类型的通知




5、测试

6、相同切入点抽取


4.3Aspect配置文件方式


5、jdbcTemplate
5.1 配置jdbcTemplate




5.2 JdbcTemplate操作数据库
创建数据库对应实体


6. 事务
6.1 事务操作



![]()
![]()

5、解决方法 :使用事务

6.2 事务操作

6.3 注解实现-声明式事务

![]()


6.3.1 声明式事务管理参数配置

1、propagation:事务传播行为



2、isolation:事务隔离级别
(1)有三个读问题:脏读、不可重复读、幻读
脏读:一个未提交事务读到另一个未提交事务的数据

不可重复读:一个未提交事务读取到另一个提交事务修改数据

幻读:一个未提交事务读取到另一个提交事务添加数据
解决:设置事务的隔离级别


3、timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交则进行回滚
(2)默认值是-1,即不超时 。设置时间以秒为单位

4、readOnly:是否只读

5、rolllbackFor:回滚
设置出现哪些异常进行事务回滚
6、noRollbackFor:不回滚
设置出现哪些异常不进行事务回滚
6.4 XML实现-声明式事务
6.4.1 配置事务管理器

6.4.2 配置通知

6.4.3 配置切面

6.5 完全注解开发
1、创建配置类



7. Spring5新功能-整合日志框架
7.1 Spring5框架新功能

第二步:创建log4j2.xml配置文件



4、支持函数式风格

5、支持整合Junit5



















浙公网安备 33010602011771号