文章目录
IOC加载
IOC加载过程就是bean的创建过程
- 通过
@Bean
<bean/>
@Component
去定义一个bean (概念态) - 实例化ApplicationContext对象,读取Bean的定义信息
@Bean
<bean/>
@Component
- 创建Bean工厂
- 调用bean工厂的后置处理器,可自定义修改bean定义,注册成
BeanDefinition
(定义态)
invokeBeanFactoryPostProcessors(beanFactory)
- 判断beanDefiniton是否符合生产标准(是不是抽象的,单例,懒加载)
- 通过反射实例化对象(纯净态)(循环依赖)
- 生命周期钩子函数
- 创建完成,put到单例池子 ConcurrentHashMap<String,Object>
Bean生命周期
-
Bean的实例化阶段
-
Bean的设置属性阶段
- 循环依赖
- 在设置属性阶段后,
postProcessBeforeInitialization
方法执行前,会执行很多Aware类型的接口,这种类型接口作用是加载资源到Spring容器中,Aware前面的名字就对应哪种资源,依次加载的是:
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
EnvironmentAware
ResourceLoaderAware
ApplicationEventPublisherAware
ApplicationContextAware
-
Bean的 初始化阶段
- InitializingBean的afterPropertiesSet方法
- @PostConstruct注解标注的方法
- 配置的init-method
- 上面的三个方法效果都是一样的
-
Bean的销毁阶段
- preDestroy注解标注的方法
- DisposableBean接口的destroy方法
- 配置的destroy-method
初始化阶段,有个特别重要的接口BeanPostProcessor,在初始化前、后调用。
Demo
借用一个博主的demo
测试类
public class BeanLifeTest {
@Test
public void test(){
System.out.println("Spring容器初始化===========================");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("Spring容器初始化完毕========================");
System.out.println("从容器中获取Bean");
IocBeanLifeService service = context.getBean("iocBeanLifeService", IocBeanLifeService.class);
System.out.println(service.toString());
System.out.println("Spring容器准备关闭==========================");
context.close();
System.out.println("Spring容器完成关闭===========================");
}
}
所有Bean在初始化前后都会执行
public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【步骤10】执行BeanPostProcessor中postProcessBeforeInitialization方法,beanName=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("【步骤14】执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
return bean;
}
}
Demo Bean
public class IocBeanLifeService implements InitializingBean,DisposableBean,ApplicationContextAware,
ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
private String name;
private String sex;
public void setName(String name) {
System.out.println("【步骤2】执行Bean的set方法,设置name属性值:" + name);
this.name = name;
}
public void setSex(String sex) {
System.out.println("【步骤2】执行Bean的set方法,设置sex属性值:" + sex);
this.sex = sex;
}
public IocBeanLifeService(){
System.out.println("【步骤1】执行Bean的无参构造函数");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("【步骤12】执行InitializingBean的afterPropertiesSet方法");
}
@Override
public void destroy() throws Exception {
System.out.println("【步骤16】执行DisposableBean接口的destroy方法");
}
//通过<bean>的destroy-method属性指定的销毁方法
public void destroyMethod() throws Exception {
System.out.println("【步骤17】执行配置的destroy-method");
}
//通过<bean>的init-method属性指定的初始化方法
public void initMethod() throws Exception {
System.out.println("【步骤13】执行配置的init-method");
}
@PostConstruct
public void initPostConstruct(){
System.out.println("【步骤11】执行PostConstruct注解标注的方法");
}
@PreDestroy
public void preDestroy(){
System.out.println("【步骤15】执行preDestroy注解标注的方法");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("【步骤4】执行BeanClassLoaderAware中setBeanClassLoader,ClassLoader的name = " + classLoader.getClass().getName());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("【步骤5】执行BeanFactoryAware中setBeanFactory,beanFactory中是否包含IocBeanLifeService:" + beanFactory.containsBean("iocBeanLifeService"));
}
@Override
public void setBeanName(String s) {
System.out.println("【步骤3】执行BeanNameAware中setBeanName方法,beanName值:"
+ s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("【步骤9】执行ApplicationContextAware的setApplicationContext方法,Bean Definition Names="
+ Arrays.toString(applicationContext.getBeanDefinitionNames()));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("【步骤8】执行ApplicationEventPublisherAware中setApplicationEventPublisher方法");
}
@Override
public void setEnvironment(Environment environment) {
System.out.println("【步骤6】执行EnvironmentAware的setEnvironment方法");
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
Resource resource = resourceLoader.getResource("classpath:applicationContext.xml");
System.out.println("【步骤7】执行ResourceLoaderAware的setResourceLoader方法,Resource File Name="
+ resource.getFilename());
}
@Override
public void setImportMetadata(AnnotationMetadata annotationMetadata) {
System.out.println("执行setImportMetadata");
}
}
Spring拓展点
XxxAware
上面的demo有
Bean初始化前后:BeanPostProcessor
场景:所有Bean在初始化前后,都会执行上面说到的BeanPostProcessor
的Before和After方法。
所有BeanDefinition注册后:BeanFactoryPostProcessor
如下,将已经注册的Definition设置为懒加载。
@Component
public class A implements BeanFactoryPostProcessor {
//在所有BeanDefinition注册完之后调用。
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
//所有BeanDefinition名
for (String beanDefinitionName : factory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
//设置懒加载
BeanDefinition beanDefinition = factory.getBeanDefinition("userService");
beanDefinition.setLazyInit(true);
}
}
@PostConstruct失效
主页文章:@PostConstruct 失效之(Bean实现了BeanFactoryPostProcessor)
所有Bean就绪后:ApplicationListener、CommandLineRunner
场景:在所有Bean就绪之后,执行。
是通过监听接口方式启动
两种方式
1.
@Component
public class B implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("所有Bean已经准备就绪");
}
}
或者
@Component
public class B{
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshed(ContextRefreshedEvent contextRefreshedEvent){
System.out.println("BBB");
}
}
2.
@Component
public class StartPingService implements CommandLineRunner{
@Override
public void run(String... args) throws Exception {
System.out.println("所有Bean已经准备就绪");
}
}
@Import
@Import的几种用法
找到多个Bean时不报错
Bean不唯一的时候,如有两个不同的Bean继承同一接口,都在容器中。
这时候获取bean报错,说bean不唯一
解决:
添加@Primary
注解,将它设为主Bean
@Autowared和@Resources
一个是Spring提供,一个是JDK提供
前者先按照类型匹配,再按照名称
后者先按照名称匹配,再按照类型
@Autowared自动装配过程
@Configuration
加了@Configuration会为配置类创建cglib动态代理(保证配置类@Bean方法只执行一次来实现单例)
Spring注册Mybatis的Mapper为Bean
Mapper都是接口且没有实现类,怎么注册为Bean?
SpringMVC处理json
SSM中的父子容器
SpringBoot
是个啥
Spring和SpringBoot
Spring是一个框架,而SpringBoot是快速构建基于Spring的脚手架,为开发Spring及其它框架铺平了道路