上篇我们讲过,Ioc有两种使用方式,一种是使用BeanFactory,另一种是ApplicationContext。这篇文章,我们就是来讲第二种的实现。ApplicationContext对比前面一种方式拓展了很多功能,实际应用中我们主要也是使用这种方式。
Example
public class ApplicationContextIoc {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
PropertyValue pv = new PropertyValue("name","Cat");
MutablePropertyValues mpvs = new MutablePropertyValues();
mpvs.addPropertyValue(pv);
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(Animal.class);
bd.setPropertyValues(mpvs);
context.registerBeanDefinition("animal",bd);
context.refresh();//整个流程主要多了这个方法
Animal animal = context.getBean(Animal.class);
animal.say();
}
public static class Animal {
private String name;
public Animal() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void say(){
System.out.println("Hello " + name);
}
}
}
这段代码大体上跟前面一篇类似,只是多出了一个refresh()方法。那么ApplicationContext和BeanFactory的异同在哪里?
GenericApplicationContext结构
先来看下GenericApplicationContext的结构。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
很明显,调用registerBeanDefinition()时其实还是由DefaultListableBeanFactory去实现,此处GenericApplicationContext它只是作为一个代理类存在而已。同样的getBean()方法也是由BeanFactory内部去实现的。
refresh()方法
来重点看下refresh()的逻辑,它是在父类AbstractApplicationContext定义,里面共有11个方法,在这里大致把这个方法的流程走一遍。
AbstractApplicationContext.class
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
prepareRefresh()
设置容器的激活、关闭状态以及做一些校验动作,如果未将容器状态设置为已激活就去获取bean则会抛出一个未激活的异常。
obtainFreshBeanFactory()
上面我们讲到过ApplicationContext只是一个代理类而已,它对bean的一些管理还是由BeanFactory去实现的,此处便是去获取BeanFactory。获取BeanFactory时是通过getBeanFactory()去操作的,这是一个抽象方法,具体的逻辑是由子类GenericApplicationContext去实现。代码如下:
AbstractApplicationContext.class
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
GenericApplicationContext.class
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
可以看出来,其实BeanFactory是通过子类去创建,如果需要其它不同的BeanFactory只需要在子类中创建合适的BeanFactory即可,而已不需要修改这部分的代码,符合了“开放-闭合原则”。此处的BeanFactory是GenericApplicationContext的构造方法创建的。
prepareBeanFactory(beanFactory)
对BeanFactory做相关的配置,为后续BeanFactory的一些操作做准备。
postProcessBeanFactory(beanFactory)
设置BeanFactory的后续处理,该方法用protected修饰,且默认实现为空,目前spring重写该方法的子类跟web环境有关,一般用于拓展web环境。
invokeBeanFactoryPostProcessors(beanFactory)
调用BeanFactory的后处理器,它运行的时机是在bean定义全部加载到容器之后,bean的创建之前。这个主要用于修改容器的bean定义。与它相关的两个接口如下:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
这两个接口其实是一个继承关系,两个实现的功能是相似的,前者通过BeanFactory去修改bean定义,而后者直接通过BeanDefinitionRegistry去修改而已。
registerBeanPostProcessors(beanFactory)
向容器注册bean的后处理器,这些后处理器在bean实例化后,运行初始化方法前、后分别进行回调。这里的初始化方法有两种形式:
- bean实现了InitializingBean接口所对应的afterPropertiesSet()方法
- bean里面通过init-method(xml或注解)标记的方法
与bean后处理器相关的接口如下
public interface BeanPostProcessor {
//初始化前方法回调
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//初始化后方法回调
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
initMessageSource()
初始化国际化工具类MessageSource
initApplicationEventMulticaster()
初始化事件广播器,用于事件的发布。
onRefresh()
该方法用protected修饰且默认实现为空,属于模板方法。目前重写该方法的都与web环境有关
registerListeners()
注册监听器,用于发布广播事件后的回调。
finishBeanFactoryInitialization(beanFactory)
这部分的主要内容是将非延迟加载的单例bean全部实例化
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// 冻结bean定义,表示不可再修改
beanFactory.freezeConfiguration();
// 实例化所有非懒加载的单实例bean
beanFactory.preInstantiateSingletons();
}
看最后一行代码,实例化bean的逻辑其实还是在BeanFactory中去实现,在此只是单纯的调用而已。所以说ApplicationContext只是作为 一个代理类去拓展BeanFactory的功能。
finishRefresh()
这个容器执行refresh()的最后一个方法,用于初始化容器生命周期的处理器,让容器启动、销毁等进行回调。并刷新容器的启动状态给生命周期处理回调,另外还发布ContextRefreshedEvent事件,让对应的监听器来进一步的处理。
总结
GenericApplicationContext作为BeanFactory的拓展容器,实现了更强大的功能,这些功能主要针对的是BeanFactory,bean及容器的生命周期进行拓展,提供了回调的入口让用户能进更细粒度的进行容器操作。但对于基础的bean定义管理,实例化这些实际上还是由BeanFactory去实现的,GenericApplicationContext只是作为一个代理类对BeanFactory去增强其功能而已。
其实refresh()这个方法里面内容的细节还很多,本文只是走了大概的流程。有时间再来具体分析啦。










网友评论