Spring源码学习(6)——容器的功能扩展
之前的随笔中借BeanFactory介绍了bean的解析和加载的完整过程,实际上,除了BeanFactory,spring还提供了一种功能更加强大的容器:ApplicationContext
ApplicationContext不但具备了BeanFactory的完整功能,还提供了一些扩展功能。因此,除非是在一些限制场合下,spring通常建议我们使用ApplicationContext这一容器。
我们首先进入到ClassPathXmlApplicationContext的构造函数中
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if(refresh) {
this.refresh();
} }
这里简单调用了父类的构造函数,并且设置了配置的位置,具体的逻辑在refresh()方法中
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory); try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
} this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
} }
}
这个方法写的还是比较整洁的,我们一个一个方法来看
首先是prepareRefresh()
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if(this.logger.isInfoEnabled()) {
this.logger.info("Refreshing " + this);
} this.initPropertySources();
this.getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet();
}
这里的逻辑十分简单,做了一些环境的初始化操作,值得一提的是这里的initPropertySources()方法,如果点开这个方法的话,我们会发现这个方法的方法体是空的。说明这个方法是为了支持扩展用的,当我们想要在容器启动前做一些特殊操作时,例如做一些依赖的校验,如果没有校验通过,那么可以直接停止启动容器。如果想要做这个特殊处理,只需要继承一下这个容器,并重写一下这个方法就可以了。从这里我们也可以看到spring支持扩展方面做得还是很好的。
接下来我们来看obtainFreshBeanFactory()
ApplicationContext之所以能包含BeanFactory的所有功能,就是在这里实现的。实现的具体逻辑在refreshBeanFactory方法中。
protected final void refreshBeanFactory() throws BeansException {
if(this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
} try {
DefaultListableBeanFactory ex = this.createBeanFactory();
ex.setSerializationId(this.getId());
this.customizeBeanFactory(ex);
this.loadBeanDefinitions(ex);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = ex;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
简单的说就是,ApplicationContext中持有了一个DefaultListableBeanFactory(也就是BeanFactory的父类)的一个全局变量,在这个方法中主要做了几件事情:
1、创建DefaultListableBeanFactory
2、指定序列化ID
3、定制Beanfactory
4、加载BeaDefinition
5、使用全局变量记录BeanFactory类实例。
到这里位置,ApplicationContext已经包含了BeanFactory的完整功能了,接下来就是ApplicationContext的扩展功能了。
我们进入到prepareBeanFactory中
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.setBeanClassLoader(this.getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
if(beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
} if(!beanFactory.containsLocalBean("environment")) {
beanFactory.registerSingleton("environment", this.getEnvironment());
} if(!beanFactory.containsLocalBean("systemProperties")) {
beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
} if(!beanFactory.containsLocalBean("systemEnvironment")) {
beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
} }
1、增加SPEL语言支持
首先在
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
ApplicationContext注册了语言解析器,这个解析器支持容器对SPEL语言提供了支持。
所谓的SPEL语言就是使用#{...}作为定界符,大括号里的就是spel
例如
<bean id="normalUser" class="com.wuzhe.spring.test.UserFactory" factory-method="getUser"/>
<bean id="admin" class="com.wuzhe.spring.test.User">
<property name="user" value="#{normalUser}"></property>
</bean>
其实就相当于
<bean id="normalUser" class="com.wuzhe.spring.test.UserFactory" factory-method="getUser"/>
<bean id="admin" class="com.wuzhe.spring.test.User">
<property name="user" ref="normalUser"></property>
</bean>
使用好这个语言可以提高开发效率。
2、增加属性注册编辑器
在
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
这个方法本身并没有什么好说的,只是简单注册了ResourceEditorRegistrer
更重要的方法实际上是
public void registerCustomEditors(PropertyEditorRegistry registry) {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
this.doRegisterEditor(registry, Resource.class, baseEditor);
this.doRegisterEditor(registry, ContextResource.class, baseEditor);
this.doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
this.doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
this.doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
if(pathClass != null) {
this.doRegisterEditor(registry, pathClass, new PathEditor(baseEditor));
} this.doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
this.doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
this.doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
this.doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
this.doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if(this.resourceLoader instanceof ResourcePatternResolver) {
this.doRegisterEditor(registry, Resource[].class, new ResourceArrayPropertyEditor((ResourcePatternResolver)this.resourceLoader, this.propertyResolver));
} } private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if(registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport)registry).overrideDefaultEditor(requiredType, editor);
} else {
registry.registerCustomEditor(requiredType, editor);
} }
在这里我们可以实现自定义的属性编辑器。
我们知道在Spring DI的时候会将普通的属性注入到bean中,但只支持一些类型,像Date类型就无法被识别出来,这时候就可以通过
1)定义属性编辑器
public class DatePropertyEditor implements PropertyEditorRegistrar { public void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
propertyEditorRegistry.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("YYYY-MM-dd"), true));
}
}
2)注册到Spring中
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.wuzhe.spring.test.DatePropertyEditor"></bean>
</list>
</property>
</bean>
这样就可以实现解析String为Date类型,并注入到Bean中
3、添加ApplicationContextAwareProcessor处理器
接下来这条
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
这里注册了BeanPostProcessor,我们知道在BeanFactory实例化Bean之后,在调用init-method左右会依次调用所有注册的BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法
这里注册的BeanPostProcessor主要干了一件事情,我们从ApplicationContextAwareProcessor的postProcessBeforeInitialization可以看出
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if(System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
} if(acc != null) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
ApplicationContextAwareProcessor.this.invokeAwareInterfaces(bean);
return null;
}
}, acc);
} else {
this.invokeAwareInterfaces(bean);
} return bean;
} private void invokeAwareInterfaces(Object bean) {
if(bean instanceof Aware) {
if(bean instanceof EnvironmentAware) {
((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
} if(bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
} if(bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
} if(bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
} if(bean instanceof MessageSourceAware) {
((MessageSourceAware)bean).setMessageSource(this.applicationContext);
} if(bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
} }
这里对于实现了Aware接口的bean,在实例化之后会获得相应的一些资源。这个扩展挺有用的,例如在SpringMVC中,我想要拿到应用启动时加载的容器ApplicationContext,那么我就可以让某个bean继承ApplicationContextAware接口,这样这个bean就能拿到当前的容器了,接下来就可以使用这个容器做一些自定义的业务逻辑。
看完了prepareBeanFactory()接下来是
this.postProcessBeanFactory(beanFactory);
这里面是一段空代码,spring为了支持扩展,可以通过重写这个方法,实现BeanFactory的后处理。
再来看,还有一种方式可以实现BeanFactory的后处理
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
HashSet processedBeans = new HashSet();
int postProcessorName;
ArrayList var20;
ArrayList var23;
if(beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry postProcessorNames = (BeanDefinitionRegistry)beanFactory;
LinkedList priorityOrderedPostProcessors = new LinkedList();
LinkedList orderedPostProcessorNames = new LinkedList();
Iterator nonOrderedPostProcessorNames = beanFactoryPostProcessors.iterator(); while(nonOrderedPostProcessorNames.hasNext()) {
BeanFactoryPostProcessor orderedPostProcessors = (BeanFactoryPostProcessor)nonOrderedPostProcessorNames.next();
if(orderedPostProcessors instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor nonOrderedPostProcessors = (BeanDefinitionRegistryPostProcessor)orderedPostProcessors;
nonOrderedPostProcessors.postProcessBeanDefinitionRegistry(postProcessorNames);
orderedPostProcessorNames.add(nonOrderedPostProcessors);
} else {
priorityOrderedPostProcessors.add(orderedPostProcessors);
}
} String[] var18 = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
var20 = new ArrayList();
String[] var22 = var18;
postProcessorName = var18.length; int postProcessorName1;
for(postProcessorName1 = 0; postProcessorName1 < postProcessorName; ++postProcessorName1) {
String ppName = var22[postProcessorName1];
if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
var20.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
} sortPostProcessors(beanFactory, var20);
orderedPostProcessorNames.addAll(var20);
invokeBeanDefinitionRegistryPostProcessors(var20, postProcessorNames);
var18 = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
var23 = new ArrayList();
String[] var26 = var18;
postProcessorName1 = var18.length; int var30;
for(var30 = 0; var30 < postProcessorName1; ++var30) {
String ppName1 = var26[var30];
if(!processedBeans.contains(ppName1) && beanFactory.isTypeMatch(ppName1, Ordered.class)) {
var23.add(beanFactory.getBean(ppName1, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName1);
}
} sortPostProcessors(beanFactory, var23);
orderedPostProcessorNames.addAll(var23);
invokeBeanDefinitionRegistryPostProcessors(var23, postProcessorNames);
boolean var27 = true; while(var27) {
var27 = false;
var18 = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
String[] var28 = var18;
var30 = var18.length; for(int var33 = 0; var33 < var30; ++var33) {
String ppName2 = var28[var33];
if(!processedBeans.contains(ppName2)) {
BeanDefinitionRegistryPostProcessor pp = (BeanDefinitionRegistryPostProcessor)beanFactory.getBean(ppName2, BeanDefinitionRegistryPostProcessor.class);
orderedPostProcessorNames.add(pp);
processedBeans.add(ppName2);
pp.postProcessBeanDefinitionRegistry(postProcessorNames);
var27 = true;
}
}
} invokeBeanFactoryPostProcessors((Collection)orderedPostProcessorNames, (ConfigurableListableBeanFactory)beanFactory);
invokeBeanFactoryPostProcessors((Collection)priorityOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
} else {
invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
} String[] var15 = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
ArrayList var16 = new ArrayList();
ArrayList var17 = new ArrayList();
ArrayList var19 = new ArrayList();
String[] var21 = var15;
int var24 = var15.length; String var29;
for(postProcessorName = 0; postProcessorName < var24; ++postProcessorName) {
var29 = var21[postProcessorName];
if(!processedBeans.contains(var29)) {
if(beanFactory.isTypeMatch(var29, PriorityOrdered.class)) {
var16.add(beanFactory.getBean(var29, BeanFactoryPostProcessor.class));
} else if(beanFactory.isTypeMatch(var29, Ordered.class)) {
var17.add(var29);
} else {
var19.add(var29);
}
}
} sortPostProcessors(beanFactory, var16);
invokeBeanFactoryPostProcessors((Collection)var16, (ConfigurableListableBeanFactory)beanFactory);
var20 = new ArrayList();
Iterator var25 = var17.iterator(); while(var25.hasNext()) {
String var31 = (String)var25.next();
var20.add(beanFactory.getBean(var31, BeanFactoryPostProcessor.class));
} sortPostProcessors(beanFactory, var20);
invokeBeanFactoryPostProcessors((Collection)var20, (ConfigurableListableBeanFactory)beanFactory);
var23 = new ArrayList();
Iterator var32 = var19.iterator(); while(var32.hasNext()) {
var29 = (String)var32.next();
var23.add(beanFactory.getBean(var29, BeanFactoryPostProcessor.class));
} invokeBeanFactoryPostProcessors((Collection)var23, (ConfigurableListableBeanFactory)beanFactory);
beanFactory.clearMetadataCache();
}
这段代码比较长,但总的来说这个方法实现的功能就是一个:找到BeanFactoryPostProcessor,并调用它的后处理方法。
这里把BeanFactoryPostProcessor分成了三类:
1)通过硬编码的方式注册在容器中的BeanDefinitionRegistryPostProcessor
2)通过硬编码的方式注册在容器中的BeanFactoryPostProcessor
3) 配置中的BeanFactoryPostProcessor bean
分别读取这三类之后,这个方法会对BeanFactoryPostProcessor 进行排序,排序的依据是这个bean是否继承了PriorityOrdered或是Ordered的getOrder()方法,如果getOrder方法返回的int值越大,则这个处理器的排序更靠前,排序完后,spring就会依次调用处理器的方法。
这一功能可扩展性非常强,可以让我们在BeanFactory解析好配置文件之后,灵活地改变容器中的配置例如BeanDefinition等,像之前介绍的自定义属性编辑器的注册也是一种BeanFactoryPostProcessor,通过这一功能我们还可以对配置中一些属性进行过滤或是做特殊处理。
当所有BeanFactoryPostProcessor处理完之后,接下来spring会注册BeanPostProcessor,BeanPostProcessor会在bean实例化后,init-method前后被调用。看一下注册代码
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
ArrayList priorityOrderedPostProcessors = new ArrayList();
ArrayList internalPostProcessors = new ArrayList();
ArrayList orderedPostProcessorNames = new ArrayList();
ArrayList nonOrderedPostProcessorNames = new ArrayList();
String[] orderedPostProcessors = postProcessorNames;
int nonOrderedPostProcessors = postProcessorNames.length; String ppName1;
BeanPostProcessor pp;
for(int ppName = 0; ppName < nonOrderedPostProcessors; ++ppName) {
ppName1 = orderedPostProcessors[ppName];
if(beanFactory.isTypeMatch(ppName1, PriorityOrdered.class)) {
pp = (BeanPostProcessor)beanFactory.getBean(ppName1, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if(pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
} else if(beanFactory.isTypeMatch(ppName1, Ordered.class)) {
orderedPostProcessorNames.add(ppName1);
} else {
nonOrderedPostProcessorNames.add(ppName1);
}
} sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, (List)priorityOrderedPostProcessors);
ArrayList var13 = new ArrayList();
Iterator var14 = orderedPostProcessorNames.iterator(); while(var14.hasNext()) {
String var16 = (String)var14.next();
BeanPostProcessor var18 = (BeanPostProcessor)beanFactory.getBean(var16, BeanPostProcessor.class);
var13.add(var18);
if(var18 instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(var18);
}
} sortPostProcessors(beanFactory, var13);
registerBeanPostProcessors(beanFactory, (List)var13);
ArrayList var15 = new ArrayList();
Iterator var17 = nonOrderedPostProcessorNames.iterator(); while(var17.hasNext()) {
ppName1 = (String)var17.next();
pp = (BeanPostProcessor)beanFactory.getBean(ppName1, BeanPostProcessor.class);
var15.add(pp);
if(pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
} registerBeanPostProcessors(beanFactory, (List)var15);
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, (List)internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
这里spring的处理方式和处理BeanFactoryPostProcessor极为相似,连排序的接口也是一样的,区别就是
这里只需将BeanPostProcessor分为两种情况:
1)硬编码的BeanPostProcessor
2) 配置文件中的BeanPostProcessor
拿到所有的BeanPostProcess然后分别排序,最后注册到容器中。
说完了BeanPostProcessor,接下来说一下Spring的事件监听。Spring可以通过注册监听器,对容器中的事件监听并实现用户自定义的业务逻辑。
首先Spring会初始化ApplicationEventMulticaster
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
} else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [" + this.applicationEventMulticaster + "]");
}
} }
这段代码的逻辑比较清晰,无非就是如果用户在容器中实现了自定义的事件广播器的话,就使用用户的自定义事件广播器;如果没有,那么Spring会使用默认的事件广播器SimpleApplicationEventMulticaster
我们走到这个类中去看一下这个广播器的实现机制
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Iterator var4 = this.getApplicationListeners(event, type).iterator(); while(var4.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
this.invokeListener(listener, event);
}
} }
在SimpleApplicationEventMulticaster类的multicastEvent方法中可以看出Spring默认广播器的实现机制:
首先Spring会在内存中缓存所有的监听器,以Map的形式,key为监听事件和事件的source类型,value就是对应的监听器列表。
在getApplicationListeners方法中,Spring可以拿到所有属于当前时间的监听器。
然后遍历所有监听器,并调用监听器的接口,也就是ApplicationListener接口的onApplicationEvent()方法。
接下来this.onRefresh()这个方法又是一个空的方法,为了方便扩展。
到了registerListeners()这个方法,这个方法就是实现注册监听器。
protected void registerListeners() {
Iterator var1 = this.getApplicationListeners().iterator(); while(var1.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var1.next();
this.getApplicationEventMulticaster().addApplicationListener(listener);
} String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false);
String[] var7 = listenerBeanNames;
int var3 = listenerBeanNames.length; for(int var4 = 0; var4 < var3; ++var4) {
String listenerBeanName = var7[var4];
this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
} Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
Iterator var9 = earlyEventsToProcess.iterator(); while(var9.hasNext()) {
ApplicationEvent earlyEvent = (ApplicationEvent)var9.next();
this.getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
} }
可以看到同之前说的后处理器一样,Spring在这里也先考虑注册了硬编码实现的监听器,然后再对容器中配置文件中定义的所有实现ApplicationListener接口的bean一一注册到广播器中。
然后对一些容器中的earlyApplicationEvents做广播。
就这样到了ApplicationContext容器初始化的尾声了。
this.finishBeanFactoryInitialization(beanFactory);
在这个方法里主要实现了一些初始化非延迟加载单例的工作,这边就不一一赘述了
this.finishRefresh();
在这个方法里,Spring会广播ContextRefreshedEvent事件,说明容器初始化已经完成了。
容器的初始化就到这了结束了,至于ApplicationContext是如何获取bean的呢?
public Object getBean(String name) throws BeansException {
this.assertBeanFactoryActive();
return this.getBeanFactory().getBean(name);
}
从上面这段代码中可以看出,ApplicationContext获取bean的方式完全和BeanFactory一致。之前的随笔已经讲过了,这边就不在重复了。
Spring源码学习(6)——容器的功能扩展的更多相关文章
- 创建ApplicationContext与BeanFactory时的区别-Spring源码学习之容器的基本实现
传送门 可以加载XML两种方法 使用 BeanFactory 加载 XML BeanFactory bf = new XmlBeanFactory(new ClassPathResource(&quo ...
- spring源码学习之容器的基本实现
最近想拿出一部分时间来学习一下spring的源码,还特意买了一本书结合来看,当然主要是学习并跟着作者的思路来踏上学习spring的源码的道路,特意在此记录一下,<spring源码深度解析> ...
- Spring源码学习之容器的基本实现(一)
前言 最近学习了<<Spring源码深度解析>>受益匪浅,本博客是对学习内容的一个总结.分享,方便日后自己复习或与一同学习的小伙伴一起探讨之用. 建议与源码配合使用,效果更嘉, ...
- spring源码学习之容器的扩展(二)
六 BeanFactory的后处理BeanFactory作为spring容器的基础,用于存放所有已经加载的bean,为了保证程序上的高扩展性,spring针对BeanFactory做了大量的扩展,比如 ...
- spring源码学习之容器的扩展(一)
在前面的章节,我们一直以BeanFactory接口以及它的默认实现XmlBeanFactory为例进行解析,但是,spring还提供了另一个接口ApplicationContext,用于扩展BeanF ...
- Spring 源码学习(一)-容器的基础结构
关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料 展示的代码摘取了一些核心方法,去掉一些默认设置和日志输出,还有大多数错误异常也去掉了,小伙伴想看详细代码 ...
- spring源码学习之:xml标签扩展配置例子
在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的 时候,会显得非常笨拙.一般的做法会用原生态的方式去解析定义好 ...
- Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签
写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...
- Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件
写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...
- Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md
写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...
随机推荐
- .Net Core 管道中的ConfigureServices 和Configure
ConfigureServices 就是配置服务器的DI容器 把需要的中间件等一些东西添加到DI容器 最后都是添加到IServiceCollection里面 比如 services.AddI ...
- 又谈T检验
今天有同学的论文被指摘了,就是又用了T检验,又用了ANOVA,reviewer直接说用ANOVA就行了.所以回想下了T检验. 简而言之,T检验就是用来比较均值的,样本均值和已知总体均值是否有差异.(也 ...
- 使用http服务提供yum源
1.安装httpd yum -y install httpd systemctl start httpd systemctl enable httpd 2.镜像资源目录拷贝至http的网站根目录 /v ...
- vue 双向绑定 数据修改但页面没刷新
在数据改动的代码后加 this.$forceUpdate(); 若是在某个特定方法中 则将this改为方法中设定的名称
- 常见的eclipse和真机出现的问题
1.eclipse和手机连接时间过断导致运行时报错(时间,,,) 2.adk中文件夹中文件遗失错乱: tools下的zipalign丢失(打包时出现提示the zipalign tool was no ...
- Robot Framework自动化测试(1)
Python: https://www.python.org/ RF框架是基于python 的,所以一定要有python环境. Robot framework : https://pypi.pytho ...
- springmvc请求参数异常统一处理
1.ExceptionHandlerController package com.oy.controller; import java.text.MessageFormat; import org.s ...
- 微信小程序笔记
1.文件的作用 js,wxml,wxss,json 所有页面中要用到的变量,都放在可了pages目录下 wxml:类似于html文件 wxss:类似于css文件(类, id, 标签,子代,后代,bef ...
- nginx 出现504 Gateway Time-out的解决方法
本文介绍nginx出现504 Gateway Time-out问题的原因,分析问题并提供解决方法. 1.问题分析nginx访问出现504 Gateway Time-out,一般是由于程序执行时间过长导 ...
- mysql innodb 唯一键里的字段为什么不能为NULL
mysql 唯一键失效 CREATE TABLE `studnet_unique` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100 ...