Spring容器中的一些组件:
- BeanPostProcessor:bean的后置处理器,创建对象初始化前后进行拦截工作。
通过实现BeanPostProcessor接口在bean的初始化前后进行一些操作。
// 将后置处理器加入到容器
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization" + "=>" + beanName + "=>" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization" + "=>" + beanName + "=>" + bean);
return bean;
}
}
给两个方法打上断点,我们来调试。
查看方法调用栈:
bean的第一次创建是采用createBean,又由于createBean调用了doCreateBean,所以我们直接进入doCreateBean方法。
populateBean是对bean的属性进行赋值,然后再调用initializeBean。我们进入initializeBean。
- applyBeanPostProcessBeforeInitialization:循环遍历得到容器中所有的beanPostProcessor并执行postProcessBeforeInitialization。
- invokeInitMethods:执行自定义初始化方法。
- applyBeanPostProcessAfterInitialization:该方法作用同applyBeanPostProcessBeforeInitialization。
- Spring底层对BeanPostProcessor的使用:
如果我们要在Dog中使用到容器,我们可以实现ApplicationContextAware接口,然后将该容器传入。那么在dog实例创建的时候,是如何知道该bean是否实现了ApplicationContextAware接口呢?那就是通过ApplicationContextAwareProcessor。
可以看到,在ApplicationContextAwareProcessor的postProcessBeforeInitialization方法中,判断了bean实例是否为ApplicationContextAware的实现类,如果是,则调用相应的方法(invokeAwareInterface)注入值。
@Autowired,@PostConstruct,@PreDestroy,bean的赋值,生命周期的注解功能等等,都用到了BeanPostProcessor…
- BeanFactoryPostProcessor:BeanFactory的后置处理器
在BeanFactory标准初始化之后调用,即beanFactory已经保存所有的bean定义,但bean实例还未创建。
写我们自己的BeanFactoryPostProcessor:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor->postProcessBeanFactory...");
int count = beanFactory.getBeanDefinitionCount();
String[] names = beanFactory.getBeanDefinitionNames();
System.out.println(count);
System.out.println(Arrays.asList(names));
}
}
给postProcessBeanFactory方法打上断点,我们来调试,查看什么时候执行BeanFactoryPostProcessors。
在refresh中可以看到:
而初始化方法在这之后执行,所以我们通过源码验证了BeanFactory的后置处理器在BeanFactory标准初始化之后调用。
从bean工厂中加载所有的BeanFactoryPostProcessor:
有优先级的基础上,分别排序,执行排过序的BeanFactoryPostProcessors。如果没有分类的话,那么会发生某个bean依赖另外一个bean创建失败的情况。
没有优先级的在这里执行:
具体的执行方法:遍历出所有的后置处理器并调用相应的方法。
分别实现了BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean,BeanPostProcessor,BeanFactoryPostProcessor接口后,各个方法的执行顺序…
- BeanDefinitionRegistryPostProcessor:在bean的定义信息将要被加载(还未加载),但bean实例还未创建的时候执行。
BeanDefinitionRegistry:bean定义信息的保存中心,BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例的。
优先于BeanFactoryPostProcessor执行,利用BeanDefinitionRegistryPostProcessor给容器中额外注册组件。
/* 此方法优先于postProcessBeanFactory()执行 */
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("postProcessBeanDefinitionRegistry...bean的数量:" + registry.getBeanDefinitionCount());
// 注册bean定义
RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
// 或者AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
registry.registerBeanDefinition("hello",beanDefinition);
}
BeanDefinitionRegistry后置处理器优先于BeanFactory后置处理执行。
- ApplicationListener:监听容器中发布的事件,进行事件开发。
自定义事件监听器步骤:
- 写一个监听器来监听某事件(ApplicationEvent此类型的事件)
- 把监听器加入到容器
- 容器中有相应类型事件(ApplicationEvent)的发布,就能被我们监听到
ContextRefreshedEvent:容器创建完成(所有bean都创建)会发布此事件
ContextClosedEvent:容器关闭会发布此事件
ioc容器的创建过程:ClassPathXmlApplicationContext为例
note:使用注解创建spring容器的话,beanFactory在GenericApplicationContext中实例化
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
可以看到该构造器调用了参数configLocations为数组类型的构造器,即可以传入多个的spring文件,并且设置refresh为true。
调用了父类的空参构造器,
AbstractXmlApplicationContext->
AbstractRefreshableConfigApplicationContext->
AbstractRefreshableApplicationContext->
AbstractApplicationContext
最终来到这里,我们进去看看到底它要做什么
可以发现,在这里面对spring容器的属性进行一些设置…
如果父环境是非空且其环境是ConfigurableEnvironment的实例,则将父环境与此(子)应用程序上下文环境合并。
以上是 super(parent); 的调用过程,接下来看看 setConfigLocations(configLocations);
设置此应用程序上下文的配置位置。如果没有设置,则实现可以适当地使用默认值。
因为我只写了一个spring配置文件,所以可以看到configLocations的参数列表只有一个,配置文件以数组的形式存储。
接下来进入refresh,可以发现该方法被synchronized修饰,即该方法是同步的。
以下为refresh中调用的方法
进入prepareRefresh
prepareRefresh:对之前定义的属性进行初始化,如设置上下文的启动时间…
initPropertySources:该方法什么也没做(maybe)…留下的注释是默认什么都不做?让子类去实现?我们可以在子类中重写该方法。
该方法的作用暂时不清楚…
涉及到的类和方法:ConfigurableEnvironment,public void validateRequiredProperties()…
接下来对上下文的监听器进行设置…具体还没弄清楚…
进入obtainFreshBeanFactory:刷新bean factory
如果存在之前的beanFactory则关闭,并为该上下文创建一个新的beanFactory(DefaultListableBeanFactory)。
进入prepareBeanFactory:配置bean factory,例如context’s ClassLoader and post-processors
进入invokeBeanFactoryPostProcessors:实例化并调用所有注册的BeanFactoryPostProcessor bean,必须在单例的bean之前调用。
进入initApplicationEventMulticaster:初始化事件多播器(派发器),监听的事件存在于此。
进入onRefresh:在特定的上下文子类中初始化其他特殊的bean