一、 Spring 简介
1. 官网:Spring | Home
2. 作用:
2.1 简化开发: 实现解耦,降低企业级开发复杂性,由手动new对象转换为外部提供对象
2.2 框架整合: 高效整合其他技术,提高企业级应用开发与运行效率
二、 核心概念
1. IOC(Inversion of Control ):
控制反转,由主动new对象,转换为外部提供对象,在该过程中的控制权由程序交给了spring进行管理,我们需要时可以直接向spring获取,该思想称为控制反转,底层实现原理是反射,无参构造方法;为实现该思想,spring提供了一个ioc容器,该容器负责对象的创建,初始化,等一系类工作,被ioc容器管理的对象称之为bean。
2. DI(Dependency Injection):
依赖注入,ioc容器在管理bean时,在容器中将有依赖关系的bean进行绑定的过程,称为依赖注入。
三、 基础分析
1. IOC
1.1 实现步骤:
1.1.1 导入Spring坐标
1.1.2 定义Spring管理的接口类
1.1.3 创建Spring配置文件
1.1.4 初始化IOC容器,通过容器获取bean
1.2.代码实现:
1.2.1 导入Spring坐标
<!--导入spring的坐标,版本是5.2.10.RELEASE-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
1.2.2 定义UserDao接口和UserDaoImpl实现类
//定义UserDao接口
public interface UserDao {
public void save();
}
//编写UserDaoImpl实现类
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
1.2.3 定义UserService接口和UserServiceImpl实现类
//定义UserService接口
public interface UserService {
public void save();
}
//编写UserServiceImpl实现类
public class UserServiceImpl implements UserService {
private UserkDao userDao = new UserDaoImpl();
public void save() {
System.out.println("user service save ...");
userDao.save();
}
}
1.2.4 创建Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--bean标签:表示配置一个bean
id属性:表示给bean起名字,不能重复
class属性:表示给bean定义类型-->
<bean id="userService" class="com.service.UserServiceImpl"></bean>
</beans>
1.2.5 初始化IOC容器,通过容器获取bean
public class Test {
public static void main(String[] args) {
//1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext acc = new ClassPathXmlApplicationContext("applicationContext.xml");
//2 从IOC容器中获取Bean对象
UserService userService= (UserService)acc.getBean("userService");
//3 调用Bean对象的方法
userService.save();
}
}
1.2.6 运行结果
user service save ...
user dao save ...
2. DI
2.1 实现步骤:
2.1.1 删除new形式创建对象
2.1.2 提供依赖对象,对应的setter方法
2.1.3 配置service与dao之间的关系
2.2 代码实现
2.2.1 删除new形式创建对象,提供依赖对象,对应的setter方法
public class UserServiceImpl implements UserService {
// 2.2.1 删除new形式创建对象
private UserDao userDao;
public void save() {
System.out.println("user service save ...");
userDao.save();
}
// 2.2.2 提供对应的setter方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
2.2.2 配置service与dao之间的关系
<?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标签:表示配置一个bean
id属性:表示给bean起名字,不能重复
class属性:表示给bean定义类型-->
<bean id="userService" class="com.service.UserServiceImpl"></bean>
<!--配置server与dao的关系
property标签:表示配置当前bean的属性
name属性:表示配置哪一个具体的属性
ref属性:表示参照哪一个bean-->
<bean id="userService" class="com.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
</beans>
2.3 DI依赖注入的方式
2.3.1 构造器注入:
构造器注入:被依赖的对象,通过构造函数的参数,注入给依赖对象,并且在初始化对象时候注入。其优点是对象初始化完成后便可获得可使用的对象。缺点是当需要注入的对象很多时,构造器参数列表将会很长;不够灵活。若有多种注入方式,每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函数,麻烦。
2.3.2 setter方法注入:
setter方法注入: IOC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。其优点是灵活,可以选择性地注入需要的对象。缺点是依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。
2.3.3 接口注入:
接口注入: 依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。其优点是接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。缺点是侵入行太强,不建议使用。
2.4 依赖注入方式选择
2.4.1 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.4.2 可选依赖使用setter注入进行,灵活性强
2.4.3 Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
2.4.4 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
2.4.5 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
2.4.6 自己开发的模块推荐使用setter注入
2.5 依赖自动装配
2.5.1 IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配。自动装配方式有,按类型(常用)、按名称、按构造方法、不启用自动装配。配置中使用bean标签autowire属性设置自动装配的类型。
2.5.2 依赖自动装配特征
A: 自动装配用于引用类型依赖注入,不能对简单类型进行操作
B: 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
C: 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
D: 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
2.6 集合注入
2.6.1 注入数组类型数据
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
2.6.2 注入List类型数据
<property name="list">
<list>
<value>listone</value>
<value>listtwo</value>
</list>
</property>
2.6.3 注入Set类型数据
<property name="set">
<set>
<value>one</value>
<value>two</value>
</set>
</property>
2.6.4 注入Map类型数据
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="liuyang"/>
</map>
</property>
2.6.5 注入Properties类型数据
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">liuyang</prop>
</props>
</property>
说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
3. Bean
3.1 基础配置
3.2 实例化Bean的四种方式
3.2.1 构造方法方式 //常用
3.2.2 静态工厂方式 //了解
3.2.3 实例工厂方式 //了解
3.2.4 实现FactoryBean<T>方式 //扩展
附:( (3条消息) bean的四种实例化方法_篆愁君的烦恼的博客-CSDN博客_bean实例化 )
3.3 Bean的生命周期
3.3.1 总体可以分为六个阶段:Bean定义、实例化、属性设置、初始化、生成期、销毁
3.3.2 在传统的Java应用中,bean的生命周期很简单,使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了。一旦bean不再被使用,则由Java自动进行垃圾回收。相比之下,Spring管理Bean的生命周期就复杂多了,正确理解Bean 的生命周期非常重要,因为Spring对Bean的管理可扩展性非常强,下面展示了一个Bean的构造过程。
附:( (3条消息) Spring生命周期_穿城大饼的博客-CSDN博客 )
3.4 Bean销毁时机
容器关闭前触发bean的销毁,关闭容器有手工关闭容器(ConfigurableApplicationContext
接口close()
操作 )、注册关闭钩子,在虚拟机退出前先关闭容器在退出虚拟机(ConfigurableApplicationContext
接口registerShutdownHook()
操作)
附:(spring中的bean销毁时间 - 知乎 (zhihu.com)
3.5 第三方资源配置管理
四、Spring容器
1. Spring核心容器介绍
1.1 创建容器方式
方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("C:\\applicationContext.xml");
方式三:加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
1.2 获取bean对象
方式一:使用bean名称获取,需要自己强制类型转换
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
方式二:使用bean名称获取并指定类型,推荐使用
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
方式三:使用bean类型获取,如果IOC容器中同类型的Bean对象有多个,此处获取会报错
BookDao bookDao = ctx.getBean(BookDao.class);
2. Spring注解开发
2.1 衍生体注解:
@Component("bean的id") / 任意层bean的定义
@Controller("bean的id") / 表现层bean的定义
@Service("bean的id") / 业务层bean的定义
@Repository("bean的id") / 数据层bean的定义
2.2 纯注解开发:
@Configuration / 声明该类为配置类
@ComponentScan("包扫描路径") / 设置包扫描路径
2.3 Bean作用范围
@Scope / 定义bean作用范围
2.4 Bean生命周期
@PostConstruct / 后
@PreDestroy / 前
2.5 Bean依赖注入
@Autowired / 开启自动装
@Qualifier("bean的名称") / 按bean名称装备
@Value("需要注入的值") / 简单类型,值类型注入
@PropertySource("属性文件名") / 加载属性源
2.6 第三方Bean
@Import / 注解导入式
@ComponentScan / 扫描式
@Bean / 声明管理bean对象
五、AOP
1. AOP简介和作用
1.1 简介:
AOP(Aspect Oriented Programming)面向切面编程
OOP(Object Oriented Programming)面向对象编程
1.2 作用:
在不惊动原始设计的基础上为其进行功能增强,简单的说就是在不改变方法源代码的基础上对方法进行功能增强,无入侵式/无侵入式。
2. 核心概念
2.1 连接点(JoinPoint):
正在执行的方法,例如:update()、delete()、select()等都是连接点。
2.2 切入点(Pointcut):
进行功能增强了的方法,例如:update()、delete()方法,select()方法没有被增强所以不是切入点,但是是连接点。
2.3 通知(Advice):
在切入点前后执行的操作,也就是增强的共性功能
2.4 通知类:
通知方法所在的类叫做通知类
2.5 切面(Aspect):
描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。
3. 注解开发
@EnableAspectJAutoProxy / 配置类中开启AOP功能
@Aspect / 告知该类为切面类
@Pointcut("execution(返回值 切入点方法路径)") / 定义切入点
@Before("定义的切入点") / 前置通知
@After("定义的切入点") / 后置通知
@Around / 环绕通知
@AfterReturning / 返回后通知
@AfterThrowning / 异常通知
4.入门流程
4.1 入门流程
4.2 代码实现
4.2.1 导入aop相关坐标
<dependencies>
<!--spring核心依赖,会将spring-aop传递进来-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--切入点表达式依赖,目的是找到切入点方法,也就是找到要增强的方法-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
4.2.2定义dao接口与实现类
public interface BookDao {
public void save();
public void update();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(System.currentTimeMillis());
System.out.println("book dao save ...");
}
public void update(){
System.out.println("book dao update ...");
}
}
4.2.3.定义通知类,制作通知方法
//通知类必须配置成Spring管理的bean
@Component
public class MyAdvice {
public void method(){
System.out.println(System.currentTimeMillis());
}
}
4.2.4.定义切入点表达式、配置切面(绑定切入点与通知关系)
//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
//设置切入点,@Pointcut注解要求配置在方法上方
@Pointcut("execution(void com.BookDao.update())")
private void pt(){}
//设置在切入点pt()的前面运行当前操作(前置通知)
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
4.2.5.在配置类中进行Spring注解包扫描和开启AOP功能
@Configuration
@ComponentScan("com")
//开启注解开发AOP功能
@EnableAspectJAutoProxy
public class SpringConfig {
}
4.2.6.测试类和运行结果
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.update();
}
}
4.3 AOP切入点表达式
附:((3条消息) Spring-AOP切入点表达式详解_夏志121的博客-CSDN博客_aop切入点表达式)
六、Spring事务管理
1.事务简介:
将多个sql语句作为一个整体,统一执行。编程式事务,编写较复杂,申明式事务,实现事务的功能只需要添加一个注解,搞定了:@Transaction。
2.事务作用:
事务作用是在数据层保障一系列的数据库操作同成功同失败,Spring事务作用是在数据层或业务层保障一系列的数据库操作同成功同失败。
3.事务四大特性:ACID
A:原子性,一个事务中的多个sql语句作为一个整体,同成功,同失败
C: 一致性,事务操作前后,数据是一致的
I: 隔离性,多个事务之间的关系
D: 持久性,一旦事务成功提交,对数据库数据的修改就是永久的
4.Spring事务角色
事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法
5.
5. Spring事务相关配置
对于RuntimeException类型异常或者Error错误,Spring事务能够进行回滚操作。但是对于编译器异常,Spring事务是不进行回滚的,所以需要使用rollbackFor来设置要回滚的异常。