bean生命周期过程中扩展(Aware族和BeanProcessor系列):spring有哪些非常有用扩展点?
ApplicationListener 、ApplicationContextAware 扩展:聊一聊 Spring 中的扩展机制(一)
NamespaceHandler:聊一聊 Spring 中的扩展机制(二) - NamespaceHandler
InitialingBean和DisposableBean:Spring8:一些常用的Spring Bean扩展接口
另外还可以了解一下java体系中的SPI扩展机制:
-
AbstractBeanFactory
-
AOP作为OOP的补充
它有属于自己适合的使用场景,比如权限控制、缓存控制、事务控制、审计日志、性能监控、异常处理等等。 -
代理模式 和包装模式区别
//代理模式
public class Proxy implements Subject{
private Subject subject;
public Proxy(){
//关系在编译时确定
subject = new RealSubject();
}
public void doAction(){
….
subject.doAction();
….
}
}
//装饰器模式
public class Decorator implements Component{
private Component component;
public Decorator(Component component){
this.component = component
}
public void operation(){
….
component.operation();
….
}
}
面试题
Bean⽣命周期
- 单例对象: singleton
总结:单例对象的⽣命周期和容器相同 - 多例对象: prototype
出⽣:使⽤对象时spring框架为我们创建
活着:对象只要是在使⽤过程中就⼀直活着
死亡:当对象⻓时间不⽤且没有其它对象引⽤时,由java的垃圾回收机制回收
IOC容器初始化加载Bean流程:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 第⼀步:刷新前的预处理
prepareRefresh();
//第⼆步: 获取BeanFactory并注册到 BeanDefitionRegistry
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 第三步:加载BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
prepareBeanFactory(beanFactory);
try {
// 第四步:完成BeanFactory准备⼯作后的前置处理⼯作
postProcessBeanFactory(beanFactory);
// 第五步:实例化BeanFactoryPostProcessor接⼝的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 第六步:注册BeanPostProcessor后置处理器,在创建bean的后执⾏
registerBeanPostProcessors(beanFactory);
// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
initMessageSource();
// 第⼋步:注册初始化事件派发器
initApplicationEventMulticaster();
// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
onRefresh();
// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器
registerListeners();
//第⼗⼀步:初始化所有剩下的⾮懒加载的单例bean 初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
finishBeanFactoryInitialization(beanFactory);
//第⼗⼆步: 完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,完成创建
finishRefresh();
}
……
}
- 总结:
- 四个阶段
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
- 四个阶段
- 多个扩展点
- 影响多个Bean
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
- 影响单个Bean
- Aware
- 注解@PostConstruct 、@PreDestroy
- 影响多个Bean
- 完整流程
- 实例化⼀个Bean,也就是我们常说的new;
- 按照Spring上下⽂对实例化的Bean进⾏配置,也就是IOC注⼊;
- 如果这个Bean已经实现了BeanNameAware接⼝,会调⽤它实现的setBeanName(String)⽅法,也就是根据就是Spring配置⽂件中Bean的id和name进⾏传递
- 如果这个Bean已经实现了BeanFactoryAware接⼝,会调⽤它实现setBeanFactory(BeanFactory),也就是Spring配置⽂件配置的Spring⼯⼚⾃身进⾏传递;
- 如果这个Bean已经实现了ApplicationContextAware接⼝,会调⽤setApplicationContext(ApplicationContext)⽅法,和4传递的信息⼀样但是因为ApplicationContext是BeanFactory的⼦接⼝,所以更加灵活
- 如果这个Bean关联了BeanPostProcessor接⼝,将会调⽤postProcessBeforeInitialization()⽅法,BeanPostProcessor经常被⽤作是Bean内容的更改,由于这个是在Bean初始化结束时调⽤那个的⽅法,也可以被应⽤于内存或缓存技术
- 如果Bean在Spring配置⽂件中配置了init-method属性会⾃动调⽤其配置的初始化⽅法。
- 如果这个Bean关联了BeanPostProcessor接⼝,将会调⽤postProcessAfterInitialization(),打印⽇志或者三级缓存技术⾥⾯的bean升级
- 以上⼯作完成以后就可以应⽤这个Bean了,那这个Bean是⼀个Singleton的,所以⼀般情况下我们调⽤同⼀个id的Bean会是在内容地址相同的实例,当然在Spring配置⽂件中也可以配置⾮Singleton,这⾥我们不做赘述。
- 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接⼝,或者根据spring配置的destroy-method属性,调⽤实现的destroy()⽅法
保障线程安全⽅法
- 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
- 在类中定义⼀个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中
循环依赖问题
循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如:A 依赖于B,B⼜依赖于A
- Spring中循环依赖场景有:
- prototype 原型 bean循环依赖
- 构造器的循环依赖(构造器注⼊)
- Field 属性的循环依赖(set注⼊)其中,构造器的循环依赖问题⽆法解决,在解决属性循环依赖时,可以使⽤懒加载,spring采⽤的是提前暴露对象的⽅法。
- 解决方案
- 懒加载@Lazy解决循环依赖问题
Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个 BeanDefinition 进⾏处理。普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥第⼀次进⾏context.getBean() 时进⾏触发。 - 三级缓存解决循环依赖问题
- 懒加载@Lazy解决循环依赖问题
Spring Bean 的自动装配
自动装配有哪些局限性
Qualifier
当我们注入的依赖存在多个候选者,我们得使用一些方法来筛选出唯一候选者,否则就会抛出异常。
解决方法
- 在WhiteCar或者RedCar所在的类上加@Primary注解
- 将private Car car改成private Car redCar
- 使用@Qualifier注解