Spring底层原理(五)
本章内容
介绍Aware接口与InitializingBean接口、Bean的初始化与销毁、Scope
Aware接口
作用:用于注入一些与容器相关的信息
类名 | 作用 |
---|---|
BeanNameAware | 注入Bean的名称 |
BeanFactoryAware | 注入BeanFactory容器 |
ApplicationContextAware | 注入ApplicationContext容器 |
EmbeddedValueResolverAware | ${} |
🔖 注入功能使用@Autowired
就能实现,为什么还要用Aware
接口呢?
@Autowired
的解析需要用到bean后处理器,属于扩展行为- 用
Aware
接口属于内置功能,不加任何扩展,Spring
就能识别
某些情况下,扩展功能会失效,而内置功能不会失效
InitializingBean接口
该接口提供了一种内置的初始化手段,内置的注入和初始化不受拓展功能的影响,总会被执行,因此Spring框架内部的类常用它
@Autowired
失效分析
Java配置类不包含BeanFactoryPostProcessor的情况
Java配置类包含BeanFactoryPostProcessor的情况,创建其中的BeanFactoryPostProcessor
必须提前创建Java配置类,而此时的BeanPostProcessor
还未准备好,导致@Autowired
等注解失效
解决办法:不要使用@Autowired
与@PostConstruct
注解,而是使用InitializingBean
接口
案例代码
@Slf4j
@Configuration
public class Config2 {
@Autowired
public void app(ApplicationContext context) {
log.info("===== 注入容器:{}", context);
}
@PostConstruct
public void init(){
log.info("===== 初始化");
}
@Bean
public BeanFactoryPostProcessor processor1(){
return beanFactory->{
log.info("执行processor1");
};
}
}
public class A05Application {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
context.registerBean(CommonAnnotationBeanPostProcessor.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.registerBean("config2",Config2.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
context.close();
}
}
更正后
@Slf4j
@Configuration
public class Config2 implements InitializingBean, ApplicationContextAware {
@Bean
public BeanFactoryPostProcessor processor1(){
return beanFactory->{
log.info("执行processor1");
};
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("===== 初始化");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.info("===== 注入容器:{}", applicationContext);
}
}
Bean的初始化与销毁
初始化
- 使用
@Bean(initMethod="")
- 使用
@PostConstruct
注解 - 使用
InitializingBean
接口
执行顺序:@PostConstruct
@Bean(initMethod="")
InitializingBean
销毁
- 使用
@Bean(distoryMethod="")
- 使用
@PreDistory
注解 - 使用
DisposableBean
接口
执行顺序:@PreDistory
@Bean(distoryMethod="")
DisposableBean
注意:Aware接口的执行时机在(初始化/销毁)注解和接口之间
Scope
Scope的类型有哪些
- singleton:单例对象
- prototype:原型,每次获取会创建一个新的对象
- request:作用于Web的request作用域中,每次请求会创建一个新的对象
- session:作用于Web的session作用域中,每个新的会话会创建一个新的对象
- application:作用域Web的applicaion作用域中
Scope的销毁
- singleton:当容器关闭时销毁
- prototype:不受容器管控
- request:每次请求结束
- session:会话超时
- application:没有被spring正确实现
指定Bean的作用域可以使用@Scope
注解指定
Web作用域演示
Scope失效问题
当在singleton
作用域调用其他作用域的对象时会导致其他作用域失效,原因是因为依赖注入只会注入一次
解决方案
- 在注入的对象上使用
@Lazy
注解,SpringIoC容器会在启动的时候实例化所有单实例 bean 。如果我们想要实现 Spring 在启动的时候延迟加载 bean,即在首次调用bean的时候再去执行初始化 - 指定
@Scope(proxyMode=ScopedProxyMode.TARGET_CLASS)
- 使用
ObjectFactory
来创建对象 - 使用ApplicationContext获取对象
原理:都是延迟其他scope bean的获取时机