中文单页面网站模板/精准营销的三要素
Spring ioc主要职责为依赖进行处理(依赖注入、依赖查找)、容器以及托管的(java bean、资源配置、事件)资源声明周期管理;在ioc容器启动对元信息进行读取(比如xml bean注解等)、事件管理、国际化等处理;首先spring中定义的元信息为BeanDefinition,Spring BeanDefinition解析与注册不同的资源有不同的实现,
- XML资源
XmlBeanDefinitionReader
- Properties资源
PropertiesBeanDefinitionReader
- JAVA注解
AnnotationBeanDefinitionReader
在实际工作中,注解用的偏多,接下来使用AnnotationConfigApplicationContext来实例化我们spring ioc容器。并进行源码分析。
@Component
public class Demo {public static void main(String[] args) {AnnotationConfigApplicationContext annotationConfigApplicationContext =new AnnotationConfigApplicationContext();annotationConfigApplicationContext.register(Demo.class);annotationConfigApplicationContext.refresh();Person person = annotationConfigApplicationContext.getBean(Person.class);System.out.println(person);annotationConfigApplicationContext.close();}@Componentpublic static class Test {@Beanpublic Person createUser() {Person person = new Person();person.setName(UUID.randomUUID().toString());return person;}}public static class Person {private String name;// toString get set 省略}
}
输出结果:
Person{name='36874349-794b-4adf-b877-2666f54b8287'}
我们仅仅注册了Demo类,AnnotationConfigApplicationContext如何进行@Bean和@Component注解进行查找呢?
前面我们提到了注解类用到AnnotationBeanDefinitionReader类进行BeanDefinition的解析与注册,在我们初始化代码的是也可以看到创建了AnnotationBeanDefinitionReader对象,并在AnnotationBeanDefinitionReader构建方法中调用AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
进行注解BeanDefinition的默认后置处理。
...省略
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
...省略
ConfigurationClassPostProcessor.class类为重点关注类
然后调用注册我们的Demo.clss
解析我们该类,生成
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
最后通过调用BeanDefinitionReaderUtils#registerBeanDefinition()
方法进行注册BeanDefinition。
Spring context#refresh()方法
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// Prepare this context for refreshing.//准备刷新上下文prepareRefresh();// Tell the subclass to refresh the internal bean factory.//告诉子类刷新内部bean工厂ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.//将该BeanFactory应用于上下文,默认BeanFactory实现为DefaultListableBeanFactory。查看源码得知道context也是基础BeanFactory,但进行依赖查找的时候会调用getBeanFactory().getBean(xx)进行处理,可理解为context对象与BeanFactory是一种特殊的组合,也可以理解为context对象是对BeanFactory的一种封装。prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.//允许在上下文子类中对bean工厂进行后置处理postProcessBeanFactory(beanFactory);StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// Invoke factory processors registered as beans in the context.// 调用上下文中注册为bean的工厂处理器 完成对BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的后置处理器调用invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);//注册拦截器bean创建的bean处理器beanPostProcess.end();// Initialize message source for this context.//初始化此上下文的消息源,列如如国际化initMessageSource();// Initialize event multicaster for this context.//为此上下文初始化事件多播initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 初始化特定上下文子类中的其他特殊beanonRefresh();// Check for listener beans and register them.//检查监听器bean并注册registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//实例化非懒加载的单例 实例化beanfinishBeanFactoryInitialization(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();contextRefresh.end();}}}
先入为主,我们看到invokeBeanFactoryPostProcessors 方法为完成对BeanDefinitionRegistryPostProcessor
和BeanFactoryPostProcessor
的后置处理器调用,那我们直接跟踪源码
进入到
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(beanfactory,branfactoryPostProcessors)
方法。跟踪代码找相应的的bean 元信息注册的处理器。
特别注意,改方法可以分为两部分进行理解,第一次部分是对BeanDefinitionRegistryPostProcessor进行处理,第二部分是对BeanFactoryPostProcessor进行处理
首先按照类型BeanDefinitionRegistryPostProcessor.class
查找后置处理器的名字,在我们初始spring上线下文中,注入了ConfigurationClassPostProcessor
类,并行该类实现了BeanDefinitionRegistryPostProcessor.class
。如下uml图
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(registry) BeanDefinition解析与注册
顺利的拿到了ConfigurationClassPostProcessor
类,接下来进行排序,执行PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors()
方法。
/*** Invoke the given BeanDefinitionRegistryPostProcessor beans.*/
private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process").tag("postProcessor", postProcessor::toString);postProcessor.postProcessBeanDefinitionRegistry(registry);postProcessBeanDefRegistry.end();}
}
此时对应的BeanDefinitionRegistryPostProcessor
类型的processor是ConfigurationClassPostProcessor
,调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(registry)
/*** Derive further bean definitions from the configuration classes in the registry.*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);
}
接下来我们进入processConfigBeanDefinitions(registry)
方法
/*** Build and validate a configuration model based on the registry of* {@link Configuration} classes.*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();// 循环注入的BeanDefinition,前面我们demo已经注册了Demo类的 BeanDefinition。for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}//是否是配置类,是否包涵Component、ComponentScan、Import、ImportResource注解,以及最后检查是否带有@Bean的方法。最后打上标记else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}
...省略do {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");//进行配置类扫描,扫描成员类以及带有ComponentScans.class、PropertySources.class,ComponentScans.class、 ImportResource.classparser.parse(candidates);parser.validate();Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}//开始注册我们解析到的配置类,读取配置类,生成BeanDefinition,并注入到当前容器中this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();candidates.clear();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());}//对比新生成的BeanDefinition,执行ConfigurationClassUtils.checkConfigurationClassCandidate。进行标记for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}}...省略
ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
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;
}....public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {// Do not consider an interface or an annotation...if (metadata.isInterface()) {return false;}// Any of the typical annotations found?//是否匹配Component.class、ComponentScan.class、Import.class、ImportResource.class注解for (String indicator : candidateIndicators) {if (metadata.isAnnotated(indicator)) {return true;}}// Finally, let's look for @Bean methods...//查找是否含有注解bean的方法。return hasBeanMethods(metadata);
}
该方法解析注册BeanDefinition中是否包涵@Configuration
注解以及是否包含配置的选项,并进行如果BeanDefinition元信息中包涵Configuration.class
注解,并且proxyBeanMethods
配置不为false,设置BeanDefinition的configurationClass
属性为full,否则判断是否包涵配置候选bean 将该BeanDefinition的configurationClass
属性为lite。
该方法是用来判断一个是否是一个配置类,并为BeanDefinition设置属性为lite或者full。如果加了@Configuration,并且对应@Configuration注解的proxyBeanMethods配置不为false那么对应的BeanDefinition为full,如果加了@Bean,@Component,@ComponentScan,@Import,@ImportResource这些注解和@Configuration的proxyBeanMethods配置为false,则为lite。lite和full均表示这个BeanDefinition对应的类是一个配置类。
初次标记完后,然后继续跟踪到配置类的解析,通过ConfigurationClassParser.parse(candidates)
解析每一个配置类。对注入不同的BeanDefinition分别处理,我们优先看@Component注解类型的AnnotatedBeanDefinition,
开始对我们注册的BeanDefinition进行元信息进行解析ConfigurationClassParser#parse
最终到processConfigurationClass#processConfigurationClass(configClass,filter)
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}ConfigurationClass existingClass = this.configurationClasses.get(configClass);if (existingClass != null) {if (configClass.isImported()) {if (existingClass.isImported()) {existingClass.mergeImportedBy(configClass);}// Otherwise ignore new imported config class; existing non-imported class overrides it.return;}else {// Explicit bean definition found, probably replacing an import.// Let's remove the old one and go with the new one.this.configurationClasses.remove(configClass);this.knownSuperclasses.values().removeIf(configClass::equals);}}// Recursively process the configuration class and its superclass hierarchy.SourceClass sourceClass = asSourceClass(configClass, filter);do {//开始解析配置类 读取注解、成员和方法,应用处理并构建完整的配置类,新解析到的配置类 进行递归解析。sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);}while (sourceClass != null);this.configurationClasses.put(configClass, configClass);}
来到我们解析成员类
/*** Register member (nested) classes that happen to be configuration classes themselves.*/private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass,Predicate<String> filter) throws IOException {Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();if (!memberClasses.isEmpty()) {List<SourceClass> candidates = new ArrayList<>(memberClasses.size());for (SourceClass memberClass : memberClasses) {//排除非配置类,和防止重复引用的类if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {candidates.add(memberClass);}}OrderComparator.sort(candidates);for (SourceClass candidate : candidates) {if (this.importStack.contains(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));}else {this.importStack.push(configClass);try {//将SourceClass转换为ConfigurationClass类,此处标记该成员类的所属类processConfigurationClass(candidatenfigClass(configClass), filter);}finally {this.importStack.pop();}}}}}
跟踪到ConfigurationClassParser#doProcessConfigurationClass(configClass,sourceClass, filter)
方法,首先是判断是否包涵Component注解,然后开始解析成员类。然后继续递处理配置类。
回到processConfigBeanDefinitions方法中,调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(configClasses);
加载解析注册BeanDefinition
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}/*** Read a particular {@link ConfigurationClass}, registering bean definitions* for the class itself and all of its {@link Bean} methods.*/private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {if (trackedConditionEvaluator.shouldSkip(configClass)) {String beanName = configClass.getBeanName();if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}//解析到的类是否是导入进来的,所依赖进来的,示例代码中Test配置类是Demo的成员类if (configClass.isImported()) {//注册BeanDefinitionregisterBeanDefinitionForImportedConfigurationClass(configClass);}for (BeanMethod beanMethod : configClass.getBeanMethods()) {//加载带有@Bean方法的注解方法,并注册BeanDefinitionloadBeanDefinitionsForBeanMethod(beanMethod);}// 判断是否被导入进来的资源配置groovy以及xmlloadBeanDefinitionsFromImportedResources(configClass.getImportedResources());//(方便扩展)取出实现了ImportBeanDefinitionRegistrar接口的类,执行其registerBeanDefinitions方法。读取自定义实现的Registrar 注入到容器中。可以参考dubbo的DubboComponentScanRegistrar 实现loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}
回到processConfigBeanDefinitions方法中,最后将新的注册的BeanDefinition进行属性标记。
最终完成了我们BeanDefinition解析与注册。