我们在使用spring framework时一般都喜欢按照以下方式写启动
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
而我们的AnnotationConfigApplicationContext的内容如下
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
this();
register(componentClasses);
refresh();
}
在前面的文章中我们介绍了AnnotationConfigApplicationContext 里reader、scaner、AppConfig.class的beandefiniton如何建创,这里我主要介绍一下refresh()方法里主要逻辑
从以下代码内容看其实主要调用的各个方法,我们来深入了解一下具体功能,具体方法里的代码内容不展示,主要说明各个方法功能
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
contextRefresh.end();
}
}
}
1.initPropertySources
初始化系统属性信息,主要是向Environment中保存,如果我们启动的是webapplicationcontext的话主要生成MutablePropertySources对象StandardServletEnvironment的属性propertySources,主要向其中放如servlet的servletContextInitParams和servletConfigInitParams两种数据,数据是真正保存在MutablePropertySources的propertySourceList中,它的定义如下:
List
2.getEnvironment().validateRequiredProperties();
1.生成并设定beanfactory的serializationId
2.返回beanfactory
设定beanfactory的beanLassLoader
设定beanfactory的beanExpressionResolver,主要是 通过new SpelExpressionParser(new SpelParserConfiguration(null,beanClassLoader))
向beanfactory的属性propertyEditorRegistrars加入new
ResourceEditorRegistrar(this, getEnvironment(),主用于注册编辑转换器
向beanfactory的属性ignoredDependencyInterfaces加入EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、 ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、ApplicationStartupAware
主要用于忽略的依赖和自动注入的class,主要通过beanFactory.ignoreDependencyInterface个方法来实现,在系统开发时如果某个class不想作为自动依赖注入,可以将此作为扩展点
向beanfactory的属性resolvableDependencies加入BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
主要用于向beanfactory放入自动依赖注入时可以注入的类型,主要通过beanFactory.registerResolvableDependency方法实现,在系统开发也可以作为一个扩展点
向beanfactory的属性beanPostProcessors加入ApplicationListenerDetector对象
这个对象主要用于bean对像初始化后和销毁之前的事件广播,主要通过postProcessAfterInitialization、postProcessBeforeDestruction这两个方法调用,主要是从beanfactory的属性中applicationEventMulticaster加入或删除,这样前提条件如果bean集成了ApplicationListener接口类对象
向beanfactory的属性singletonObjects加入以下单例bean,及registeredSingletons放入已经实例的名字
ENVIRONMENT_BEAN_NAME: StandardEnvironment
SYSTEM_PROPERTIES_BEAN_NAME: getEnvironment().getSystemProperties()
SYSTEM_ENVIRONMENT_BEAN_NAME: getEnvironment().getSystemEnvironment()
APPLICATION_STARTUP_BEAN_NAME : getApplicationStartup()
这里主要用web有关的逻辑,主要功能如下:
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
.从beanfactory的属性beanFactoryPostProcessors获取BeanDefinitionRegistryPostProcessor对象并执行其postProcessBeanDefinitionRegistry方法
在启动阶段beanFactoryPostProcessors没有内容
从factory的属性中beanDefinitionNames、manualSingletonNames找出是BeanDefinitionRegistryPostProcessor类型的beanname
在启动阶段只有ConfigurationClassPostProcessor的beandefinition满足条件的
从2找中满足条件beanname,在判断这个是否为PriorityOrdered子类,若是调用beanfactory.getBean生成bean,并放入变量currentRegistryProcessors中,并在processedBeans加入beanname
这里getBean逻辑细节单节整理,主要是参考beandefinition的信息生成bean
对currentRegistryProcessors中的bean按照dependencyComparator进行排序,并加入registryProcessors变量中
调用执行postProcessBeanDefinitionRegistry方法
启动阶段主要是执行ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法,然后内部在调用processConfigBeanDefinitions方法
从factory的属性中beanDefinitionMap中得到有@Configuration的类,主要是通过ConfigurationClassUtils.checkConfigurationClassCandidate方法查找,并对beandefinition设定如下内容:
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
然后对找到所有@Configuration类进行排序,按照beandefinition的order值排序,如果order没有设定取Integer.MAX_VALUE
获取factory的属性singletonObjects获取org.springframework.context.annotation.internalConfigurationBeanNameGenerator类型bean,并赋给成员属性componentScanBeanNameGenerator、importBeanNameGenerator,在启动阶段factory中没有此类型的bean
给environment属性设定StandardEnvironment
创建ConfigurationClassParser类的对象parser
执行parser对象的parse()方法进行解析含有@Configuration类的beandefinition,在执行processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER)这个方法:
如果beandefinition的类有@condition注解,直接返回
调用asSourceClass方法生成SouceClass对象sourceClass
a) 解析beandefinition类上各个注解有效性,主要通过测试注解类包含的方法返回类型为(type == Class.class || type == Class[].class || type.isEnum())是否抛异常,主要是通过调用AttributeMethods.forAnnotationType(annotation.annotationType()).validate(annotation)来实现
b) 如果2中没有抛出异常,生成SourceClass对象
3.执行doProcessConfigurationClass(configClass, sourceClass, filter)方法
a). 判断注解类是否为Component.class,在通过执行processMemberClasses(configClass,sourceClass,filter)方法判断内部类是否不是接口、是否为@Component、@ComponentScan、@Import、@ImportResouce其中一个、是否有@Bean注解,若满足条件之一对内部注解类按照这里的1、2、3、4的步骤递归调用执行
b). 解析@PropertySource,通过通过以下方法
AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class))
i.获取@PropertySource和@PropertySources的value、encoding、name、ignoreResourceNotFoud属性数据
ii.根据value的内容,生成value内容的propertySource对象,放入parse对象environment属性中的propertySources属性
iii.将value内容放入parse对象的propertySourceNames属性中
c). 解析@CompoentScan
i. 通过调用AnnotationConfigUtils得到注解的属性值Set componentScans,主要有value、basePackages、basePackageClasses、resourcePattern(默认值:**/*.class)等相关属性
componentScan = {AnnotationAttributes@2077} size = 11
"basePackageClasses" -> {Class[0]@2092}
"basePackages" -> {String[1]@2094} ["com.test"]
"excludeFilters" -> {AnnotationAttributes[0]@2096}
"includeFilters" -> {AnnotationAttributes[0]@2098}
"lazyInit" -> {Boolean@2100} false
"nameGenerator" -> {Class@846} "interface org.springframework.beans.factory.support.BeanNameGenerator"
"resourcePattern" -> "**/*.class"
"scopeResolver" -> {Class@849} "class org.springframework.context.annotation.AnnotationScopeMetadataResolver"
"scopedProxy" -> {ScopedProxyMode@2106} "DEFAULT"
"useDefaultFilters" -> {Boolean@2108} true
"value" -> {String[1]@2109} ["com.test"]
如果useDefaultFilters为true,设定defaultFilter,可以为@Component、@Named、@ManagedBean
ii. 执行parse.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()),componentScanParser为ComponentScanAnnotationParser实例化对象,这部分逻辑单独整理,主要扫描类也生成beandefition有关逻辑
**找到相关类通过以下代码来扫描,主要根据basepackage属性**
*****************************************************************************
protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set result) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Searching directory [" + dir.getAbsolutePath() +
"] for files matching pattern [" + fullPattern + "]");
}
for (File content : listDirectory(dir)) {
String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
if (!content.canRead()) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +
"] because the application is not allowed to read the directory");
}
}
else {
doRetrieveMatchingFiles(fullPattern, content, result);
}
}
if (getPathMatcher().match(fullPattern, currPath)) {
result.add(content);
}
}
}
*****************************************************************
解析注解@Import,逻辑复杂单独整理 ConfigurationClassParser.processImports
主要处理Import的class是否为普通类、继承ImportSelecto、DeferredImportSelector、ImportBeanDefinitionRegistrar这些类,最终将import的类生成对象放入parse的importStack属性中
解析@ImportResource,将得到的文件信息加入到configclass对象属性importedResources
解析configuration类中含有@Bean注解的方法,读取到方法加入configClass属性beanMethods中
在读取含有@Bean注解时会在次读取一次,确认是否一致,具体的参考retrieveBeanMethodMetadata这个方法
分析configuration类的接口方法中是否含有@Bean注解方法,并加入到configclass对象属性importedResources
分析configuration的父类,如果不java基础类放入parse的knownSuperclasses属性中
执行完doProcessConfigurationClass方法后将其返回的父类
继续循环执行doProcessConfigurationClass方法,直到没有父类,并将解析过类放入parse的configurationClasses属性中
处理configuration类中@Import有关逻辑,后面单独和解析注解@Import一整理
ConfigurationClassParser.componentScanParser.process()
执行parse对象的validate()方法
检查parse对象中属性configurationClasses的class是有@Configuration注解属性proxyBeanMethods是否为true,且class为final类认为异常problemReporter.error(newFinalConfigurationProblem())
检查parse对象中属性configurationClasses的class是有@Configuration注解,对有@Bean注解的方法检查是否为不可覆盖方法,若是不可覆盖产生problemReporter.error(new
NonOverridableMethodError());
生成ConfigurationClassBeanDefinitionReader类对象reader
通过调用reader.loadBeanDefinitions方法,生成parse分析过的class的beandefinition并入beanfactory的beanDefinitionMap中
a. 判断是否需要skip,通过trackedConditionEvaluator.shouldSkip(configClass)
b.若class是被@Import进行的,生成beandefinition
c.若class中含有@注解方法,如果@Bean 注解没有设定值直接取方法名为beanname,主要是通过调用
ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod方法,细节单独整理
d.处理@ImportResource逻辑,主要是处理按照xml生成beandefinition, 调用XmlBeanDefinitionReader.loadBeanDefinitions(resource)方法,细节单独整理
判断经过parse.parse()解析过的类是否有新的有@Configuration注解类,若有重复以下过程,直到没有新的@Configuration类,这个通过注解@ComponentScan的basePackges可能扫到多个Configuration类
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
// 检查多出来的BeanDefinition是不是配置类,需不需要解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
在次从factory的属性中beanDefinitionNames、manualSingletonNames找出是BeanDefinitionRegistryPostProcessor类型的beanname,确认是否和2中找到是一样class,若不是执行3、4、5、6
在这里是个扩展点可以自定义BeanDefinitionRegistryPostProcessor接口实现对bean的初始化过程进行修改,或者对beanfactory进行各操作,
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry
在次重复6的过程
可能是为了防止在6过程中自定义实现BeanDefinitionRegistryPostProcessor的接口类
用2、6、7中找出BeanDefinitionRegistryPostProcessor实现类执行postProcessBeanFactory这个方法
在启动阶段如果没有实现BeanDefinitionRegistryPostProcessor自定义类只ConfigurationClassPostProcessor.postProcessBeanFactory
查找beanfactory中beandefinition中没有加载class的都只加载,主要是lite和full类及@Bean方法对应的方法
执行beanfactory.beanFactoryPostProcessors属性中实现了BeanFactoryPostProcessor接口的对象方法postProcessBeanFactory,除了实现BeanDefinitionRegistryPostProcessor接口的对象
启动阶段没有可以执行的,因为启动阶段beanFactoryPostProcessors里没有内容
从前面生成的beandefinition中找出所有实现了BeanFactoryPostProcessor接口类:
找出实现了PriorityOrdered类,排序后执行postProcessBeanFactory方法
找出实现了Ordered类,排序后执行postProcessBeanFactory方法
除了以上两种类,执行postProcessBeanFactory方法
扩展点:
1.可以自定义实现BeanFactoryPostProcessor接口类来对beanfactory的属性进行操作,大多情况下对beandefinition操作,
2.如果多个BeanFactoryPostProcessor这样类,可以实现PriorityOrder、Order接口来控制顺序
另外从代码上来看10是对9补充,可能随着版本升级加入@ComponentScan和@Configuration之后9可能有点问题
初始化MessageSouce Bean,并作为singleton bean名字messageSource放入容器中
如果系统开发时需要使用国际化功能,需要在@Configuration类中通@Bean方法生成messageSource的bean,否则无法使用国际化功能,原困如下:
1.在得到国际化信息时spring需要按照以下如下代码方进行
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
if (this.parentMessageSource != null) {
return this.parentMessageSource.getMessage(code, args, locale);
}
else {
throw new NoSuchMessageException(code, locale);
}
}
2.生成bean的逻辑如下,如果beanfactory没有messageSource bean,但是getInternalParentMessageSource()这个方法是没有值的
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
1.从beanfactory获取前beanname为applicationEventMulticaster的bean,如果beanfactory不存在生成SimpleApplicationEventMulticaster对象为
2.将1中得到的bean赋给beanfactory的属性applicationEventMulticaster
扩展点:
前面提到类ApplicationListenerDetector非常关键(调用beanfactory的addApplicationListener方法)
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationListener) {
// potentially not detected as a listener by getBeanNamesForType retrieval
Boolean flag = this.singletonNames.get(beanName);
if (Boolean.TRUE.equals(flag)) {
// singleton bean (top-level or inner): register on the fly
this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
}
else if (Boolean.FALSE.equals(flag)) {
if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
// inner bean with other scope - can't reliably process events
logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
"but is not reachable for event multicasting by its containing ApplicationContext " +
"because it does not have singleton scope. Only top-level listener beans are allowed " +
"to be of non-singleton scope.");
}
this.singletonNames.remove(beanName);
}
}
return bean;
}
他在bean初始化如查发现bean是ApplicationListener接口实现会通过beanfactory的属性applicationEventMulticaster的方法addApplicationListener让bean也可侦听事件,比如下类
@Component
public class UserService implements ApplicationListener {
public void test() {
System.out.println("test");
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println(this.getClass().getName()+" trigger event:"+event.getSource());
}
}
另外我们需要准备以下类(若不准备就利用spring内部的SimpleApplicationEventMulticaster来侦听所有事件,不能客制化侦听所需的事件):
@Component(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
public class MyApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
private ArrayList<ApplicationListener> applicationListeners=new ArrayList<ApplicationListener>();
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
applicationListeners.add(listener);
}
@Override
public void multicastEvent(ApplicationEvent event) {
System.out.println(this.getClass().getName()+" multicastEvent "+ event);
}
@Override
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
System.out.println(this.getClass().getName()+" multicastEvent+ResolvableType "+ event.getSource()+" "+applicationListeners.size());
for(ApplicationListener listener:applicationListeners){
listener.onApplicationEvent(event);
}
}
}
这样的话我们向beanfactory发布事件时@Compoent类才能侦听事件,上面的addApplicationListener方法必须实现,否则实现了ApplicationListener 接口bean无法侦听到事件
applicationContext.publishEvent(new ApplicationEvent(“test event”));
当然这里的事件你可以自定义一个ApplicationEvent接口实现类,然后在MyApplicationEventMulticaster.multicastEvent方法event是否为自定义类型来侦听自已的事件
这里没有用处,如果不是用于web,主要生成ResourceBundleThemeSource对象给beanfactory属性themeSource
registerListeners()逻辑
将beanfactory属性applicationListeners的ApplicationListener对对象放入beanfactory的applicationEventMulticaster.defaultRetriever.applicationListeners中,通过调用getApplicationEventMulticaster().addApplicationListener(listener)方来实现,如果beanfactory中的APPLICATION_EVENT_MULTICASTER_BEAN_NAME是AbstractApplicationEventMulticaster子类,得确认是否覆盖此方法,确认listener如何放
但是在启动阶段applicationListeners里没有数据
从beanforty里所有beandefinition里找出实现ApplicationListener类beanname放入applicationEventMulticaster.defaultRetriever.applicationListenerBeans中
这一步其实和ApplicationListenerDetector.postProcessAfterInitialization()方法其实是重复逻辑,搞不清为什么要进行两次
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
从上面整理的spring启动逻辑, invokeBeanFactoryPostProcessors至关重要,主要带有@Configuration的类比较重要,主要是得到整个系统需要生成的bean definition信息,主要是通过java的反射机制和cglib技术得到class的相关信息。