ClassPathXmlApplicationContext的启动
Spring将ApplicationContext启动的全过程,refresh函数中包含了几乎ApplicationContext中提供的全部功能,而且此函数中逻辑非常清晰明了,很容易分析对应的层次及逻辑。:
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证。
prepareRefresh();
//初始化BeanFactory,并进行XML文件读取,
//这一步之后,ClassPathXmlApplicationContext实际上就已经包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基础操作了。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//对BeanFactory进行各种功能填充,@Qualifier与@Autowired这两个注解正是在这一步骤中增加的支持。
//设置@Autowired和 @Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver
prepareBeanFactory(beanFactory);
try {
//子类覆盖方法做额外的处理,提供了一个空的函数实现postProcessBeanFactory来方便程序员在业务上做进一步扩展。
postProcessBeanFactory(beanFactory);
//激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean时候
registerBeanPostProcessors(beanFactory);
//为上下文初始化Message源,即不同语言的消息体进行国际化处理
initMessageSource();
//初始化应用消息广播器,并放入“applicationEventMulticaster”bean中
initApplicationEventMulticaster();
//留给子类来初始化其它的Bean
onRefresh();
//在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners();
//初始化剩下的单实例(非惰性的)
finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
环境准备
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
//留给子类覆盖
initPropertySources();
//验证需要的属性文件是否都已经放入环境中
getEnvironment().validateRequiredProperties();
//to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
假如现在有这样一个需求,工程在运行过程中用到的某个设置(例如classpath)是从系统环境变量中取得的,而如果用户没有在系统环境变量中配置这个参数,那么工程可能不会工作。这一要求可能会有各种各样的解决办法,当然,在Spring中可以这样做,你可以直接修改Spring的源码,例如修改ClassPathXmlApplicationContext。当然,最好的办法还是对源码进行扩展,我们可以自定义类:
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
public MyClassPathXmlApplicationContext(String... configLocations ){
super(configLocations);
}
protected void initPropertySources() {
//添加验证要求
getEnvironment().setRequiredProperties("classpath");
}
}
我们自定义了继承自ClassPathXmlApplicationContext的MyClassPathXmlApplicationContext,并重写了initPropertySources方法,在方法中添加了我们的个性化需求,那么在验证的时候也就是程序走到getEnvironment().validateRequiredProperties()代码的时候,如果系统并没有检测到对应classpath的环境变量,那么将抛出异常。
加载BeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化BeanFactory,并进行XML文件读取,并将得到的BeanFacotry记录在当前实体的属性中
refreshBeanFactory();
//返回当前实体的beanFactory属性
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
} AbstractRefreshableApplicationContext.java
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//在介绍BeanFactory的时候,声明方式为:BeanFactory bf = new XmlBeanFactory("beanFactoryTest.xml"),
//其中的XmlBeanFactory继承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性,
//也就是说DefaultListableBean Factory是容器的基础。必须首先要实例化,那么在这里就是实例化DefaultListableBeanFactory的步骤。
DefaultListableBeanFactory beanFactory = createBeanFactory();
//为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖以及
customizeBeanFactory(beanFactory);
//初始化DodumentReader,并进行XML文件读取及解析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
//使用全局变量记录BeanFactory类实例。
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
} protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性,
//此属性的含义:是否允许覆盖同名称的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,
//此属性的含义:是否允许bean之间存在循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
} @Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//为指定beanFactory创建XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); //对beanDefinitionReader进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //对BeanDefinitionReader进行设置,可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
//使用XmlBeanDefinitionReader的loadBeanDefinitions方法进行配置文件的加载及注册
loadBeanDefinitions(beanDefinitionReader);
}
功能扩展
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());
//设置beanFactory的表达式语言处理器,Spring3增加了表达式语言的支持,SPEL语言。
//默认可以使用#{bean.xxx}的形式来调用相关属性值。
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//为beanFactory增加了一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); //添加BeanPostProcessor
//ApplicationContextAwareProcessor实现了BeanPostProcessor接口,在bean实例化的时候会被调用
//postProcessBeforeInitialization方法中调用了invokeAwareInterfaces。从invokeAwareInterfaces方法中,
//我们可以看出来,实现这些Aware接口的bean在被初始化之后,可以取得一些对应的资源。
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//Spring将ApplicationContextAwareProcessor注册后,在invokeAwareInterfaces方法中间调用的Aware类已经不是普通的bean了,
//如ResourceLoaderAware,ApplicationEventPublisherAware等,需要在Spring做bean的依赖注入的时候忽略它们。
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class); //设置了几个自动装配的特殊规则
//当注册了依赖解析后,例如当注册了对BeanFactory.class的解析后,当bean的属性注入的时候,
//一旦检测到属性为BeanFactory类型便会将beanFactory的实例注入进去。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this); //增加对AspectJ的支持
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
} //将相关环境变量及属性注册以单例模式注册,environment,systemProperties,systemEnvironment
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
ResourceEditorRegistrar的registerCustomEditors的调用时机,就是AbstractBeanFactory类中的initBeanWrapper方法,这是在bean初始化时使用的一个方法,主要是在将BeanDefinition转换为BeanWrapper后用于对属性的填充。在bean的初始化后会调用ResourceEditorRegistrar的registerCustomEditors方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让Spring使用这些编辑器进行属性的解析了。
Spring中用于封装bean的是BeanWrapper类型,而它又间接继承了PropertyEditorRegistry类型,也就是我们之前反复看到的方法参数PropertyEditorRegistry,其实大部分情况下都是BeanWrapper,对于BeanWrapper在Spring中的默认实现是BeanWrapperImpl,而BeanWrapperImpl除了实现BeanWrapper接口外还继承了PropertyEditorRegistrySupport,在PropertyEditorRegistrySupport中有这样一个方法:createDefaultEditors,基本的属性编辑器就在此处被注册。
BeanFactory的后处理
BeanFactoryPostProcessor接口跟BeanPostProcessor类似,可以对bean的定义(配置元数据)进行处理。也就是说,Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个BeanFactoryPostProcessor。你还能通过设置“order”属性来控制BeanFactoryPostProcessor的执行次序(仅当BeanFactoryPostProcessor实现了Ordered接口时你才可以设置此属性,因此在实现BeanFactoryPostProcessor时,就应当考虑实现Ordered接口)。
如果你想改变实际的bean实例(例如从配置元数据创建的对象),那么你最好使用BeanPostProcessor。同样地,BeanFactoryPostProcessor的作用域范围是容器级的。它只和你所使用的容器有关。如果你在容器中定义一个BeanFactoryPostProcessor,它仅仅对此容器中的bean进行后置处理。BeanFactoryPostProcessor不会对定义在另一个容器中的bean进行后置处理,即使这两个容器都是在同一层次上。
在Spring中存在对于BeanFactoryPostProcessor的两种典型应用。
(1)比如PropertyPlaceholderConfigurer
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/mail.properties</value>
<value>classpath: conf/sqlmap/jdbc.properties</value>//注意这两种value值的写法
</list>
</property>
<property name="fileEncoding">
<value>UTF-8</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}"/>
<property name="password"value="${jdbc.password}" />
</bean> jdbc.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/mysqldb?useUnicode=true&characterEncoding=UTF-8&
jdbc.username=root
jdbc.password=123456
PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,也就是BeanFactoryPostProcessor接口的一个实现。PropertyPlaceholderConfigurer可以将上下文(配置文件)中的属性值放在另一个单独的标准java Properties文件中去。在XML文件中用${key}替换指定的properties文件中的值。这样的话,只需要对properties文件进行修改,而不用对xml配置文件进行修改。
在Spring中,使用PropertyPlaceholderConfigurer可以在XML配置文件中加入外部属性文件,当然也可以指定外部文件的编码,PropertyPlaceholderConfigurer如果在指定的Properties文件中找不到你想使用的属性,它还会在Java的System类属性中查找。可以通过System.setProperty(key, value)或者java中通过-Dnamevalue来给Spring配置文件传递参数。
查看层级结构可以看出PropertyPlaceholderConfigurer这个类间接继承了BeanFactoryPostProcessor接口。这是一个很特别的接口,当Spring加载任何实现了这个接口的bean的配置时,都会在bean工厂载入所有bean的配置之后执行postProcessBeanFactory方法。在PropertyResourceConfigurer类中实现了postProcessBeanFactory方法,在方法中先后调用了mergeProperties、convertProperties、processProperties这3个方法,分别得到配置,将得到的配置转换为合适的类型,最后将配置内容告知BeanFactory。正是通过实现BeanFactoryPostProcessor接口,BeanFactory会在实例化任何bean之前获得配置信息,从而能够正确解析bean描述文件中的变量引用。
(2)使用自定义BeanFactoryPostProcessor
实现一个BeanFactoryPostProcessor,实现一个简单的回调处理器,它能去除潜在的"流氓"属性值,例如bean定义中留下bollocks这样的字眼。
<bean id="bfpp" class="com.spring.ch04.ObscenityRemovingBeanFactoryPostProcessor">
<property name="obscenties">
<set>
<value>bollocks</value>
<value>winky</value>
<value>bum</value>
<value>Microsoft</value>
</set>
</property> </bean>
<bean id="simpleBean" class="com.spring.ch04.SimplePostProcessor">
<property name="connectionString" value="bollocks"/>
<property name="password" value="imaginecup"/>
<property name="username" value="Microsoft"/>
</bean>
java代码
public class ObscenityRemovingBeanFactoryPostProcessor implements
BeanFactoryPostProcessor {
private Set<String> obscenties;
public ObscenityRemovingBeanFactoryPostProcessor(){
this.obscenties=new HashSet<String>();
}
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames=beanFactory.getBeanDefinitionNames();
for(String beanName:beanNames){
BeanDefinition bd=beanFactory.getBeanDefinition(beanName);
StringValueResolver valueResover=new StringValueResolver() {
public String resolveStringValue(String strVal) {
if(isObscene(strVal)) return "*****";
return strVal;
}
};
BeanDefinitionVisitor visitor=new BeanDefinitionVisitor(valueResover);
visitor.visitBeanDefinition(bd);
}
}
public boolean isObscene(Object value){
String potentialObscenity=value.toString().toUpperCase();
return this.obscenties.contains(potentialObscenity);
}
public void setObscenties(Set<String> obscenties) {
this.obscenties.clear();
for(String obscenity:obscenties){
this.obscenties.add(obscenity.toUpperCase());
}
} }
测试类
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
public class PropertyConfigurerDemo {
public static void main(String[] args) {
ConfigurableListableBeanFactory bf=new XmlBeanFactory(new ClassPathResource("/META-INF/BeanFactory.xml"));
BeanFactoryPostProcessor bfpp=(BeanFactoryPostProcessor)bf.getBean("bfpp");
bfpp.postProcessBeanFactory(bf);
System.out.println(bf.getBean("simpleBean")); }
}
SimplePostProcessor{connectionString=*****,username=*****,password=imaginecup
激活BeanFactoryPostProcessor
1)从invokeBeanFactoryPostProcessors的方法中我们看到,对于BeanFactoryPostProcessor的处理主要分两种情况进行,一个是对于BeanDefinitionRegistry类的特殊处理,另一种是对普通的BeanFactoryPostProcessor进行处理。而对于每种情况都需要考虑硬编码注入注册的后处理器以及通过配置注入的后处理器。
对于硬编码注册的后处理器的处理,主要是通过AbstractApplicationContext中的添加处理器方法addBeanFactoryPostProcessor进行添加。
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
}
添加后的后处理器会存放在beanFactoryPostProcessors中,而在处理BeanFactoryPostProcessor时候会首先检测beanFactoryPostProcessors是否有数据。当然,BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,不但有BeanFactoryPostProcessor的特性,同时还有自己定义的个性化方法,也需要在此调用。所以,这里需要从beanFactoryPostProcessors中挑出BeanDefinitionRegistryPostProcessor的后处理器,并进行其postProcessBeanDefinitionRegistry方法的激活。
(2)记录后处理器主要使用了三个List完成。
registryPostProcessors:记录通过硬编码方式注册的BeanDefinitionRegistryPostProcessor类型的处理器。
regularPostProcessors:记录通过硬编码方式注册的BeanFactoryPostProcessor类型的处理器。
registryPostProcessorBeans:记录通过配置方式注册的BeanDefinitionRegistryPostProcessor类型的处理器。
(3)对以上所记录的List中的后处理器进行统一调用BeanFactoryPostProcessor的postProcessBeanFactory方法。
(4)对beanFactoryPostProcessors中非BeanDefinitionRegistryPostProcessor类型的后处理器进行统一的BeanFactoryPostProcessor的postProcessBeanFactory方法调用。
(5)普通beanFactory处理。BeanDefinitionRegistryPostProcessor只对BeanDefinitionRegistry类型的ConfigurableListableBeanFactory有效,所以如果判断所示的beanFactory并不是BeanDefinitionRegistry,那么便可以忽略BeanDefinitionRegistryPostProcessor,而直接处理BeanFactoryPostProcessor,当然获取的方式与上面的获取类似。
对于硬编码方式手动添加的后处理器是不需要做任何排序的,但是在配置文件中读取的处理器,Spring并不保证读取的顺序。所以,为了保证用户的调用顺序的要求,Spring对于后处理器的调用支持按照PriorityOrdered或者Ordered的顺序调用。
注册BeanPostProcessor
来探索下BeanPostProcessor,但是这里并不是调用,而是注册。真正的调用其实是在bean的实例化阶段进行的。这是一个很重要的步骤,也是很多功能BeanFactory不支持的重要原因。Spring中大部分功能都是通过后处理器的方式进行扩展的,这是Spring框架的一个特性,但是在BeanFactory中其实并没有实现后处理器的自动注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。
对于BeanPostProcessor的处理与BeanFactoryPostProcessor的处理极为相似,但是似乎又有些不一样的地方。经过反复的对比发现,对于BeanFactoryPostProcessor的处理要区分两种情况,一种方式是通过硬编码方式的处理,另一种是通过配置文件方式的处理。那么为什么在BeanPostProcessor的处理中只考虑了配置文件的方式而不考虑硬编码的方式呢?对于BeanFactoryPostProcessor的处理,不但要实现注册功能,而且还要实现对后处理器的激活操作,所以需要载入配置中的定义,并进行激活;而对于BeanPostProcessor并不需要马上调用,再说,硬编码的方式实现的功能是将后处理器提取并调用,这里并不需要调用,当然不需要考虑硬编码的方式了,这里的功能只需要将配置文件的BeanPostProcessor提取出来并注册进入beanFactory就可以了。
对于beanFactory的注册,也不是直接注册就可以的。在Spring中支持对于BeanPostProcessor的排序,比如根据PriorityOrdered进行排序、根据Ordered进行排序或者无序,而Spring在BeanPostProcessor的激活顺序的时候也会考虑对于顺序的问题而先进行排序。
初始化消息资源
在initMessageSource中的方法主要功能是提取配置中定义的messageSource,并将其记录在Spring的容器中,也就是AbstractApplicationContext中。当然,如果用户未设置资源文件的话,Spring中也提供了默认的配置DelegatingMessageSource。
在initMessageSource中获取自定义资源文件的方式为beanFactory.getBean(MESSAGE_ SOURCE_BEAN_NAME, MessageSource.class),在这里Spring使用了硬编码的方式硬性规定了子定义资源文件必须为message,否则便会获取不到自定义资源配置。
protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//messageSource
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
//如果在配置中已经配置了messageSource,那么将messageSource提取并记录在this.messageSource中
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
else {
//如果用户并没有定义配置文件,那么使用临时的DelegatingMessageSource以便于作为调用getMessage方法的返回。
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"': using default [" + this.messageSource + "]");
}
}
}
初始化ApplicationEventMulticaster
initApplicationEventMulticaster的方式比较简单,无非考虑两种情况:
如果用户自定义了事件广播器,那么使用用户自定义的事件广播器。
如果用户没有自定义事件广播器,那么使用默认的ApplicationEventMulticaster。
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//applicationEventMulticaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
"': using default [" + this.applicationEventMulticaster + "]");
}
}
}
按照之前介绍的顺序及逻辑,作为广播器,一定是用于存放监听器并在合适的时候调用监听器,那么进入默认的广播器实现SimpleApplicationEventMulticaster来一探究竟。
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
} protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
listener.onApplicationEvent(event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
listener.onApplicationEvent(event);
}
}
可以推断,当产生Spring事件发生的时候会默认使用SimpleApplicationEventMulticaster的multicastEvent来广播事件,遍历所有监听器,并使用监听器中的onApplicationEvent方法来进行监听器的处理。而对于每个监听器来说其实都可以获取到产生的事件,但是是否进行处理则由事件监听器来决定。
注册监听器
protected void registerListeners() {
//硬编码方式注册的监听器处理
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
//配置文件注册的监听器处理
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
//广播早期的事件进行广播和事件处理
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
初始化非延迟加载单例
finishBeanFactoryInitialization完成BeanFactory的初始化工作,其中包括ConversionService的设置、配置冻结以及非延迟加载的bean的初始化工作。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//conversionService的bean会被注册
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));
}
// 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定义,说明注册的bean定义将不被修改或任何进一步的处理。
beanFactory.freezeConfiguration();
//初始化剩下的单实例(非惰性的)
beanFactory.preInstantiateSingletons();
}
ConversionService的设置,之前我们提到过使用自定义类型转换器从String转换为Date的方式,使用属性编辑器,那么,在Spring中还提供了另一种转换方式:使用Converter。
ApplicationContext实现的默认行为就是在启动时将所有单例bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的单例bean。通常情况下这是一件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。而这个实例化的过程就是在finishBeanFactoryInitialization中完成的,详细流程见Spring框架的设计理念章节。
finishRefresh
在Spring中还提供了Lifecycle接口,Lifecycle中包含start/stop方法,实现此接口后Spring保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对MQ进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
//lifecycleProcessor的bean会被注册
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
initLifecycleProcessor
当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean周期做状态更新,而在LifecycleProcessor的使用前首先需要初始化。
onRefresh
启动所有实现了Lifecycle接口的bean。
publishEvent
当完成ApplicationContext初始化的时候,要通过Spring中的事件发布机制来发出ContextRefreshedEvent事件,以保证对应的监听器可以做进一步的逻辑处理。
ClassPathXmlApplicationContext的启动的更多相关文章
- Dubbo认识
Dubbo提供了服务注册.RPC服务调用.调用均衡.服务监控和服务failover等功能 Dubbo框架中有两个重要角色:(服务)提供者和(服务)消费者,这里为了简单起见,将包含了dubbo提供者或消 ...
- 项目中dubbo的使用
导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...
- Spring_01 spring容器、控制反转(IOC)、依赖注入(DI)
目录 1 什么是spring框架 2 spring框架的特点 3 spring容器 3.1 什么是spring容器 3.2 spring容器创建对象的编程步骤 3.4 spring容器创建对象的方式 ...
- Dubbo的应用
导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...
- 篇六:项目使用Dubbo
导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...
- Dubbo入门到精通学习笔记(二):Dubbo管理控制台、使用Maven构建Dubbo的jar包、在Linux上部署Dubbo privider服务(shell脚本)、部署consumer服务
文章目录 Dubbo管理控制台 1.Dubbo管理控制台的主要作用: 2.管理控制台主要包含: 3.管理控制台版本: 安装 Dubbo 管理控制台 使用Maven构建Dubbo服务的可执行jar包 D ...
- Dubbo入门到精通学习笔记(一):Dubbo对传统工程进行改造、注册中心安装(Zookeeper-3.4.6)、工程结构优化
文章目录 改造思路 样例工程:传统的单工程项目(edu-demo) 模型结构 思路 改成dubbo调用方式后的工程结构 部署环境规划 改造 愚公移山 迁移包 迁移页面: 迁移配置相关 新项目的主要作用 ...
- 面试:Spring面试知识点总结
Spring知识点总结 1. 简介一下Spring框架. 答:Spring框架是一个开源的容器性质的轻量级框架.主要有三大特点:容器.IOC(控制反转).AOP(面向切面编程). 2. Spring框 ...
- [bigdata] 启动CM出现 “JDBC Driver class not found: com.mysql.jdbc.Driver” 以及“Error creating bean with name 'serverLogFetcherImpl'”问题的解决方法
问题:“JDBC Driver class not found: com.mysql.jdbc.Driver” 通过以下命令启动cm [root@hadoop1 ~]# /etc/init.d/cl ...
随机推荐
- 八大常见内排序java实现
虽然排序算法烂大街了,但是哥依然用java实现了一遍,只为自己练练手,后面可以时不时的回头看看...仅此而已,各位可以提意见,莫喷!! 一.冒泡排序 基本思想:在要排序的一组数中,对当前还未排好序的范 ...
- POJ 1260 Pearls
Pearls Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6670 Accepted: 3248 Description In ...
- 淘宝(阿里百川)手机客户端开发日记第七篇 Service,Handler和Thread
现在我们已经已经知道android有Service,Handler和Thread这些内容了,但是我想应该还有很多人对此并不是很清楚他们之间的区别! (1)Service 是运行在后端的程序,不与UI直 ...
- [Effective JavaScript 笔记] 第10条:避免使用with
with特性,提供的任何“便利”都更让其变得不可靠和低效率. with语句的用法,可以很方便地避免对对象的重复引用.上面的代码整理成下面的形式 function status(info){ var w ...
- 第9章 使用ssh服务管理远程主机。
章节简述: 学习使用nmtui命令配置网卡参数.手工将多块网卡做绑定.使用nmcli命令查看网卡信息和使用ss命令查看网络及端口状态. 完整演示sshd服务配置方法并详细讲述每个参数的作用,实战基于密 ...
- 深入了解PooledConnectionFactory CachingConnectionFactory Sin
深入理解PooledConnectionFactory CachingConnectionFactory SingleConnectionFactory PooledConnectionFactory ...
- springMVC 上传文件
spring mvc(注解)上传文件的简单例子,这有几个需要注意的地方1.form的enctype=”multipart/form-data” 这个是上传文件必须的2.applicationConte ...
- 【转】JSP中的相对路径和绝对路径
1.首先明确两个概念: 服务器路径:形如:http://192.168.0.1/的路径 Web应用路径:形如:http://192.168.0.1/yourwebapp的路径 2.关于相对路径与绝对路 ...
- tesseract3.02识别验证码需要注意的问题
1.安装tesseract3.02后,在命令行里输入tesseract,看能否出现使用方法,不出现则是环境变量问题,可调整其顺序. 2.找到如下文件 C:\Python27\Lib\site-pack ...
- 43. 动态规划求解n个骰子的点数和出现概率(或次数)[Print sum S probability of N dices]
[题目] 把N个骰子扔在地上,所有骰子朝上一面的点数之和为S.输入N,打印出S的所有可能的值出现的概率. [分析] 典型的动态规划题目. 设n个骰子的和为s出现的次数记为f(n,s),其中n=[1-N ...