Spring Framework系统架构
原因
耦合度偏高
- 解决方案
使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象 - IOC(Inversion of Control)控制反转
对象的创建控制权由程序转移到外部,这种思想称为控制反转
即使用对象时,由主动new产生对象转为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转 - Spring技术对IOC思想进行实现
Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的 “外部”
IOC容器负责对象的创建、初始化等一些列工作,被创建或被管理的对象在IOC容器中同称为Bean - DI(Dependency Injection) 依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
目的: 充分解耦
- 使用IOC容器管理bean(IOC)
- 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
最终 - 使用对象不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置bean-->
<!-- bean标签 表示 配置bean-->
<!-- id属性 表示 给bean起名字-->
<!-- class属性表示 给benad定义类型-->
<bean id="bookDao" class="com.shanks.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.shanks.service.impl.BookServiceImpl"/>
</beans>
初始化IOC容器,通过容器获取bean
package com.shanks;
import com.shanks.dao.BookDao;
import com.shanks.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//获取IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
System.out.println("-----------------");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
实例化bean的三种方式----构造方法
- 无参构造方法如果不存在,将抛出异常BeanCreationException
—静态工厂
—实例工厂
bean生命周期
- 生命周期:从创建到消亡的完整过程
- bean生命周期:bean从创建到销毁的整体过程
- bean生命周期控制:在bean创建后到销毁前做一些事情
bean生命周期控制
- 使用接口实现 InitializingBean, DisposableBean接口
初始化容器 - 创建对象(内存分配)
- 执行构造方法
- 执行属性注入(set操作)
- 执行bean初始化方法
使用bean
1、执行业务操作
关闭/销毁容器
1、执行bean销毁方法
bean销毁时机
容器关闭前出发bean的销毁
关闭容器方式;
- 手工关闭容器
ConfigurableApplicationContext接口close()操作 - 注册关闭钩子,在虚拟机退出前先关闭容器在退出虚拟机
ConfigurableApplicationContext接口registerShutdownHook()操作
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
向一个类中传递数据的方式有几种
- set方法
- 构造方法
依赖注入方式 - setter注入
简单类型
引用类型
- 构造器注入
简单类型
引用类型
依赖注入方式选择
1、强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2、可选依赖使用setter注入进行,灵活性强
3、Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化、相对严谨
4、如果有必要可以两者同时使用,使用构造器注入完成强制依赖注入,使用setter注入完成可选依赖的注入
5、实际开发过程中还需要根据实际情况分析,如果受控对象没有提供setter方法就是必须使用构造器注入
依赖自动装配
IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
- 自动装配用于引用类型依赖注入,不能对简单类型进行操作
- 使用按类型装配必须保障容器中相同类型的bean唯一,推荐使用
- 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配失效
- 使用按名称装配必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
properties文件
创建容器
获取bean
- BeanFactory是IOC容器的顶层接口,初始化BeanFactory对象,加载的bean延迟加载
- ApplicationContext接口是Spring容器的核心接口,初始化bean立即加载
- ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展功能
- ApplicationContext接口常用初始化类
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
注解
- @Configguration注解用于设定当前类为配置类
- @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({"com.shanks.service","com.shanks.dao"}
- 使用@Autowired注解开启自动装配模式(按类型)
- 自动装配基于反射设计创建对象并暴力反射对应属性为私有初始化数据,因此无需要提供setter方法
- 自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
@Qualifier注解开启指定指定名称装配
@Service
public void BookService implements BookService{
@Autowired
@Qualifier("bookDao")
private BookDao bookDao;
}
@Qualifer注解无法单独使用,必须配合@Autowired注解使用
使用@PropertySource注解加载properties文件
@Configurantion
@ComponetScan("com.shanks")
@PropertySource("classpath:xxxx.properties")
public class SpringConfig{
}
路径仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符 *
AOP
AOP面向切面编程,一种编程范式
- 作用:在不惊动原始设计的基础上为其进行功能增强
Spring理念:无侵入式/无入侵式
- 连接点(JioinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
在SpringAOP中,理解为方法的执行 - 切入点(Pointcut):匹配连接点的式子
在SpringAOP中,一个切入点可以描述一个具体方法,也可以匹配多个方法- 一个具体方法中: com.shanks.dap包下的BookDao接口中的无形参返回值的save方法
- 匹配多个方法:所有的save方法,所有get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 通知(Advice) :切入点 处执行的操作,也就是共性功能
-
- 在SpringAOP中,功能最终以方法的形式呈现
- 通知类:定义通知类
- 切面(Aspect):描述通知与切点的对应关系
AOP工作流程
1、Spring容器启动
2、读取所有切面配置中的切入点
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.shanks.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
3、初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
- 匹配失败,创建对象
- 匹配成功,创建原始对象(目标对象)的代理对象
4、获取bean执行方法 - 获取bean,调用方法并执行,完成操作
- 获取bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作
目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现
AOP本质就是:代理
- 切入点:要进行增强的方法
- 切入点表达式:要进行增强的方法的描述方式
AOP通知类型
- AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加到合理的位置
- AOP通知共分为5种类型
package com.shanks.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.shanks.dao.BookDao.update())")
private void pt(){}
@Pointcut("execution(int com.shanks.dao.BookDao.select())")
private void pt2(){}
//@Before("pt()")
public void before(){
System.out.println("before....");;
}
//@After("pt()")
public void after(){
System.out.println("before....");;
}
// @Around("pt()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice");
//表示对原始操作的调用
pjp.proceed();
System.out.println("around after advice");
}
//@Around("pt2()")
public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice");
//表示对原始操作的调用
Object proceed = pjp.proceed();
System.out.println("around after advice");
return proceed;
}
//@AfterReturning("pt2()")
public void afterReturning(){
System.out.println("afterReturning...");
}
@AfterThrowing("pt2()")
public void afterThrowing(){
System.out.println("afterThrowing .. advice");
}
}
- 前置通知
- 后置通知
- 环绕通知
1、环绕通知必须依赖ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
2、通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
3、对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
4、原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
5、由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象 - 返回后通知
- 抛出异常后通知
Spring事务
事务作用:在数据层保障一系列的数据库操作同成功同失败
Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败
Spring事务角色
事务管理员:发起事务方法,在Spring中通常指代业务层开启事务的方法
事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法