bean 完整生命周期的 BeanDefinition 阶段,这一阶段主要发生了以下几件事情:
1.加载配置文件、配置类
2.解析配置文件、配置类并封装为 BeanDefinition
3.编程式注入额外的 BeanDefinition
4.BeanDefinition 的后置处理
加载xml配置文件
保存xml配置文件的加载会使用ClassPathXmlApplicationContext
的setConfigLocation
方法。
点进入发现调用的是AbstractRefreshabelConfigApplicationContext
类中的setConfigLocation
方法。将路径存储到数组变量configLocations
中。
debug发现已经放到xml配置文件路径configLocations中。
加载配置文件并解析
当执行 ApplicationContext 的 refresh 方法后,会开始刷新(初始化)IOC 容器。加载xml配置文件就发生在下面的2步骤:obtainFreshBeanFactory。
//AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
// 2. 初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
// ......
}
}
1.进入obtainFreshBeanFactory:
//AbstractApplicationContext#obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
方法内两个动作:
1.刷新BeanFactory
2.返回BeanFactory
那么加载和解析就包含在刷新BeanFactory里面。refreshBeanFactory
方法是一个抽象方法,目前研究xml配置文件的解析。
2.进入AbstractRefreshableApplicationContext中:
//AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {
// 存在BeanFactory则先销毁
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 【1.3】加载配置文件
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
} // catch ......
}
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(this.getInternalParentBeanFactory());
}
基于 xml 配置文件的 ApplicationContext
可以反复刷新加载 IOC 容器,所以此处有已经存在的判断:如果当前 ApplicationContext
中组合的 BeanFactory
已经存在,则销毁原来的 BeanFactory
,并重新创建。
加载配置文件的动作是loadBeanDefinitions
。
3.进入loadBeanDefinition
方法:
loadBeanDefinitions
方法也是一个抽象方法。在AbstractXmlApplicationContext
中可以找到对应的实现:
//AbstractXmlApplicationContext
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// xml配置文件由XmlBeanDefinitionReader解析
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 配置上下文环境、资源加载器等
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader);
// 使用xml解析器 解析xml配置文件
loadBeanDefinitions(beanDefinitionReader);
}
它内部创建了一个XmlBeanDefinitionReader
(Spring框架解析xml文件的核心API)。最后把这个XmlBeanDefinitionReader
作为参数传入重载的loadBeanDefinitions
方法:
//AbstractXmlApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 【1.4】加载配置文件资源路径的xml配置文件
reader.loadBeanDefinitions(configLocations);
}
}
这里面的逻辑分两部分:
1.处理已经加载好的现成的Resource(Spring的资源模型,代表文件或者类的资源)
2…处理制定好的配置文件资源路径
Debug 至此处,同样也能发现 reader 与 configLocations 都准备好了:
4.XmlBeanDefinitionReader加载配置文件
测试代码没有指定Resource,进入loadBeanDefinitions(configLocations)
。
//AbstractBeanDefinitionReader
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
// assert ......
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
可以看到,这个方法是循环遍历资源文件路径,进行解析。
5.进入AbstractBeanDefinitionReader类的loadBeanDefinitions
//AbstractBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
//AbstractBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
// throw ex ......
}
if (resourceLoader instanceof ResourcePatternResolver) {
try {
// 根据传入的路径规则,匹配所有符合的xml配置文件
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
// logger ......
return count;
} // catch ......
}
else {
// 每次只能解析一个xml配置文件
Resource resource = resourceLoader.getResource(location);
// 【解析】
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
// logger ......
return count;
}
}
这个方法中的2个核心步骤:
1.根据传入的资源路径,获取xml配置文件资源对象
2.解析xml配置文件
//XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
//XmlBeanDefinitionReader#loadBeanDefinitions
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// assert logger ......
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
// throw ex ......
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 【真正干活的】
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} // catch ......
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
InputSource:XML实体的单个输入源。
InputSource对象属于应用程序:SAX解析器。
6.进入doLoadBeanDefinitions
//XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
// logger ......
return count;
} // catch ......
}
这个方法的两个核心步骤:
1.将xml输入流转换为Document(文档对象)
2.解析文档对象并注册BeaDefinitions对象。
7.进入registerBeanDefinitions 方法。
//XmlBeanDefinitionReader#doLoadBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 【解析】
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
此处构建了一个DefaultBeanDefinitionDocumentReader
,调用它的registerBeanDefinitions
方法。
//DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
//DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
// 取<beans>上的profile属性
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
// logger ......
return;
}
}
}
preProcessXml(root);
// 【解析xml】
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
这块代码先把 xml 配置文件中声明的 profile 取出来,并根据 Environment 中配置好的 profile 决定是否继续解析( profile 的过滤)
接下来,后面就是 xml 配置文件的解析动作了,在这前后有一个预处理和后处理动作,不过默认情况下这里是没有实现的(模板方法罢了),所以我们只需要看 parseBeanDefinitions 就可以。
8.进入parseBeanDefinitions 解析
//DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
// 解析<beans>中的元素
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
// 解析其它命名空间中的元素
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
Spring 如何解析 xml ,我们不关心,但是如何从解析完的 xml 中获取关键信息,以及封装 BeanDefinition ,这才是我们要关注的。
OK ,继续回到源码,源码中可以看到,每次循环出来的 Node 都会尝试着转成 Element 去解析,而解析的动作主要是 parseDefaultElement
,它会解析 标签下的 xml 元素。
//DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
这里它会解析 <import>
标签、<alias>
标签、<bean>
标签,以及递归解析嵌套的 <beans>
标签!
9.processBeanDefinition-解析<bean>
标签
//DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析xml元素为BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 解析<bean>中嵌套的自定义标签
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// BeanDefinition注册到BeanDefinitionRegistry
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
} // catch ......
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
第一个步骤会把 xml 元素封装为 BeanDefinitionHolder(内部组合了一个BeanDefiniton)
//BeanDefinitionParserDelegate#parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
//BeanDefinitionParserDelegate#parseBeanDefinitionElement
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
// 取出bean的id
String id = ele.getAttribute(ID_ATTRIBUTE);
// 取出bean的name
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// 取出bean的alias
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
// 如果没有给bean赋name,则第一个alias视为name
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
// logger ......
}
// 检查bean的name是否有重复
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 解析其余的bean标签元素属性
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 如果没有给bean赋name,且没有alias,则生成默认的name
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
} else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
// logger ......
} // catch ......
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
只有 id 和 name ,class 呢?scope 呢?lazy-init 呢?莫慌,看到中间还有一个封装好的 parseBeanDefinitionElement 方法了.
10.parseBeanDefinitionElement
//BeanDefinitionParserDelegate#parseBeanDefinitionElement
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 解析class的全限定名
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
// 解析parent的definition名称
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
// 构造BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析其余的<bean>标签属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析property属性
parseMetaElements(ele, bd);
// 解析其它的属性 ......
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
} // catch finally ......
return null;
}
调用 createBeanDefinition 方法创建了一个 BeanDefinition。之后把 <bean>
标签中的其它属性、<bean>
的子标签的内容都封装起来,而封装 <bean>
其它属性的 parseBeanDefinitionAttributes
方法中,已经把这些内容都解析到位了
//BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
if (ele.hasAttribute("singleton")) {
this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
} else if (ele.hasAttribute("scope")) {
bd.setScope(ele.getAttribute("scope"));
} else if (containingBean != null) {
bd.setScope(containingBean.getScope());
}
if (ele.hasAttribute("abstract")) {
bd.setAbstract("true".equals(ele.getAttribute("abstract")));
}
String lazyInit = ele.getAttribute("lazy-init");
if (this.isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit("true".equals(lazyInit));
String autowire = ele.getAttribute("autowire");
bd.setAutowireMode(this.getAutowireMode(autowire));
String autowireCandidate;
if (ele.hasAttribute("depends-on")) {
autowireCandidate = ele.getAttribute("depends-on");
bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
}
autowireCandidate = ele.getAttribute("autowire-candidate");
String destroyMethodName;
if (this.isDefaultValue(autowireCandidate)) {
destroyMethodName = this.defaults.getAutowireCandidates();
if (destroyMethodName != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
} else {
bd.setAutowireCandidate("true".equals(autowireCandidate));
}
if (ele.hasAttribute("primary")) {
bd.setPrimary("true".equals(ele.getAttribute("primary")));
}
if (ele.hasAttribute("init-method")) {
destroyMethodName = ele.getAttribute("init-method");
bd.setInitMethodName(destroyMethodName);
} else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
if (ele.hasAttribute("destroy-method")) {
destroyMethodName = ele.getAttribute("destroy-method");
bd.setDestroyMethodName(destroyMethodName);
} else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
if (ele.hasAttribute("factory-method")) {
bd.setFactoryMethodName(ele.getAttribute("factory-method"));
}
if (ele.hasAttribute("factory-bean")) {
bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
}
return bd;
}
xml 配置文件中的 标签就可以转换为 BeanDefinition 了。
BeanDefinitionHolder的意义
它是持有 BeanDefinition 的一个包装而已,不过它除了持有之外,还包含了另外的重要信息:bean 的名称。
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
总结:
首先 ClassPathXmlApplicationContext
在 refresh
之前,会指定传入的 xml
配置文件的路径,执行 refresh
方法时,会初始化 BeanFactory
,触发 xml
配置文件的读取、加载和解析。其中 xml
的读取需要借助 XmlBeanDefinitionReader
,解析 xml
配置文件则使用 DefaultBeanDefinitionDocumentReader
,最终解析 xml
中的元素,封装出 BeanDefinition
,最后注册到 BeanDefinitionRegistry
。
加载注解配置类
注解配置类的加载时机会晚一些,它用到了一个至关重要的 BeanDefinitionRegistryPostProcessor
。而且无论如何,这个后置处理器都是最最优先执行的,它就是 ConfigurationClassPostProcessor
。
BeanDefinitionRegistryPostProcessor的调用时机
这次我们要看的是 BeanFactoryPostProcessor
和 BeanDefinitionRegistryPostProcessor
的执行时机,而它们的执行都在下面所示的第 5 步 invokeBeanFactoryPostProcessors
中执行:
//AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ......
try {
//web环境下重写这个方法
postProcessBeanFactory(beanFactory);
// 5. 执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
// ......
}
// catch finally .....
}
}
进来这个方法,发现核心的方法就一句话:
//AbstractApplicationContext
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors;
//AbstractApplicationContext#invokeBeanFactoryPostProcessors
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 交给代理执行
//getBeanFactoryPostProcessors()返回一个List<BeanFactoryPostProcessor>集合
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 下面是支持AOP的部分(暂时不读)
}
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
return this.beanFactoryPostProcessors;
}
它又是交给一个 Delegate 执行。
PostProcessorRegistrationDelegate的实现
invokeBeanFactoryPostProcessors 方法的篇幅实在太长了,只截取关键的部分。
//PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 该部分会将BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor分离开
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 首先,执行实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 接下来,执行实现了Ordered接口的BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 最后,执行所有其他BeanDefinitionRegistryPostProcessor
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 执行BeanFactoryPostProcessor ......
}
逻辑梳理:
1.先处理BeanDefinitionRegistryPostProcessor
。
2.定义两个集合分别收集BeanFactoryPostProcessor
与BeanDefinitionRegistryPostProcessor
。
3…将编程注入(ApplicationContext调用addBeanFactoryPostProcessor方法增加的后置处理器)BeanFactoryPostProcessor
集合遍历,执行BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry
方法。将后置处理器分别放到不同的集合中。
4.遍历beanDefinitionNames
集合中(DefaultListableBeanFactory
中定义的集合属性),找到类型是BeanDefinitionRegistryPostProcessor
的beanDefinitionNames
。处理实现了PriorityOrdered
接口的BeanDefinitionRegistryPostProcessors。
(1)getBean方法根据beandefinition创建后置处理器对象。
(2)排序这些BeanDefinitionRegistryPostProcessors
后置处理器。
(3)调用BeanDefinitionRegistryPostProcessors
的postProcessBeanDefinitionRegistry
方法。
5.逻辑和4类似。处理实现Order
接口的BeanDefinitionRegistryPostProcessors
后置处理器。
6.处理普通的BeanDefinitionRegistryPostProcessor
后置处理器。普通的beanDefinitonRegistryPostProcessor(postProcessBeanDefinitionRegistry
方法调用)处理完后。
(1)调用收集beanDefinitonRegistryPostProcessor集合中所有后置处理器的postProcessBeanFactory方法。
(2)调用收集beanFactoryPostProcessor集合中所有后置处理器的postProcessBeanFactory方法。
7.处理BeanFactoryPostProcessor
。逻辑同上。
ConfigurationClassPostProcessor的处理
ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口。
直接定位到 postProcessBeanDefinitionRegistry 方法吧:
//ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
// check throw ex ......
this.registriesPostProcessed.add(registryId);
// 【解析配置类】
processConfigBeanDefinitions(registry);
}
可以发现,在这个方法的最后一行,就是解析配置类中定义的 bean ,并封装为 BeanDefinition 。
进入processConfigBeanDefinitions 方法
//ConfigurationClassPostProcessor#processConfigBeanDefinitions
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 筛选出所有的配置类
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
// logger ......
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// 配置类排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 构造默认的BeanNameGenerator bean的名称生成器
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 真正解析配置类的组件:ConfigurationClassParser
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 【解析配置类】
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 【加载配置类的内容】
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
// 一些额外的处理动作
}
while (!candidates.isEmpty());
// 一些额外的处理 ......
}
它初始化了一个 ConfigurationClassParser
,这个家伙是用来解析注解配置类的核心 API 。
ConfigurationClassParser#parse – 解析注解配置类
//ConfigurationClassParser#parse
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 注解配置类
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
// 编程式注入配置类
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
// 其他情况
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} // catch ......
}
// 回调特殊的ImportSelector
this.deferredImportSelectorHandler.process();
}
整体看一下这个方法,它会把配置类的全限定名拿出来,扔进重载的 parse 方法中(注意无论是执行 if-else-if 的哪个分支,最终都是执行重载的 parse 方法);or 循环调用完成后,最底下会让 deferredImportSelectorHandler 执行 process 方法。
deferredImportSelectorHandler
是ImportSelector
接口的扩展。它的执行时机比 ImportSelector
更晚,它会在注解配置类的所有解析工作完成后才执行。
进入deferredImportSelectorHandler的处理逻辑:
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
deferredImports.forEach(handler::register);
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
它会取出所有解析中存储好的 DeferredImportSelector ,并依次执行。由于 DeferredImportSelector 的执行时机比较晚,对于 @Conditional 条件装配的处理也会更有利,所以这个设计还是不错的。
parse解析配置类
上面的 ConfigurationClassParser
中最终都会把配置类传入重载的 parse
方法中,参数类型注意是 ConfigurationClass
:
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
// 如果配置类已经被@Import过了,则跳过
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
else {
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
SourceClass sourceClass = asSourceClass(configClass);
do {
// 【真正干活的】
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass - 解析配置类
处理@Component注解
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
processMemberClasses(configClass, sourceClass);
}
// ........
它就会判断这个类是否有标注 @Component 注解。因为所有的 @Configuration 类必定是 @Component ,所以该逻辑必进。而内部执行的 processMemberClasses 方法如下:
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) {
// 防止循环@Import的处理:如果两个配置类互相@Import,则视为错误
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
} else {
this.importStack.push(configClass);
try {
// 递归解析内部的配置类
processConfigurationClass(candidate.asConfigClass(configClass), filter);
}
finally {
this.importStack.pop();
}
}
}
}
}
这个方法是处理内部类的啊,而且还是递归处理。
处理@PropertySource注解
// ............
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
// else logger ......
}
// ............
接下来是处理 @PropertySource 注解了,可以发现借助 AnnotationConfigUtils
可以很容易的取出配置类上标注的所有注解信息,然后筛选出指定的注解属性即可。而内部的 processPropertySource 方法就在真正的封装 PropertySource 导入的资源文件:
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
// 解析@PropertySource注解的属性
String name = propertySource.getString("name");
if (!StringUtils.hasLength(name)) {
name = null;
}
String encoding = propertySource.getString("encoding");
if (!StringUtils.hasLength(encoding)) {
encoding = null;
}
String[] locations = propertySource.getStringArray("value");
// ......
for (String location : locations) {
try {
// 处理路径,加载资源文件,并添加进Environment中
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
Resource resource = this.resourceLoader.getResource(resolvedLocation);
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
} // catch ......
}
}
前面的一大堆操作都是拿 @PropertySource 的一些属性等等,最后的 for 循环中才是封装资源文件,存放进 Environment 的部分。
处理@ComponentScan注解
// ............
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 如果有@ComponentScans,则要取出里面所有的@ComponentScan依次扫描
for (AnnotationAttributes componentScan : componentScans) {
// 【复杂】借助ComponentScanAnnotationParser扫描
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 是否扫描到了其它的注解配置类
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 如果扫描到了,递归解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// ............
中间的部分,它使用 ComponentScanAnnotationParser 来委托处理包扫描的工作,
ComponentScanAnnotationParser 的 parse 方法中,看一看内部的实现:最开始就创建了ClassPathBeanDefinitionScanner
对象。
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
// 构造ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
// 解析@ComponentScan中的属性 ......
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
// 整理要扫描的basePackages
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 没有声明basePackages,则当前配置类所在的包即为根包
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
// ......
// 【扫描】执行包扫描动作
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
1.构造 ClassPathBeanDefinitionScanner ,并封装 @ComponentScan 注解中的属性
2.整理要进行包扫描的 basePackages ,以及 include 和 exclude 的过滤器
3.执行包扫描的动作
真正的包扫描那还得看 ClassPathBeanDefinitionScanner :
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
// assert ......
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
// 【真正的包扫描动作在这里】
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
// 处理scope(默认情况下是singleton)
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
// 生成bean的名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
// 处理bean中的@Lazy、@Primary等注解
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
// 设置AOP相关的属性(如果支持的话)
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册进BeanDefinitionRegistry
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
从上往下的逻辑条理还是很清晰的,只要扫描到了符合的类(默认被 @Component 注解标注的类),就会包装为 BeanDefinition ,然后对这些 BeanDefinition 进行一些额外的处理,最终注册进 BeanDefinitionRegistry 。
findCandidateComponents 方法:
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
} else {
return scanCandidateComponents(basePackage);
}
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 此处可处理 [/**/service/*Service.class] 这样的表达式
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
try {
// 加载.class字节码
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// 如果符合匹配规则,则封装为ScannedGenericBeanDefinition
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
} // catch .......
}
}
} // catch ......
return candidates;
}
它会将带有通配符的 Ant 风格(诸如 /xxx/**/*.class )的路径解析出来,并加载到对应的类,封装为 ScannedGenericBeanDefinition ,完事。
处理@Import注解
// ............
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);
// ............
就一句话啊,那咱直接点进去:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
// 防止循环@Import导入
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// 处理ImportSelector
if (candidate.isAssignable(ImportSelector.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
// DeferredImportSelector的执行时机后延
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
} else {
// 执行ImportSelector的selectImports方法,并注册导入的类
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
// 处理ImportBeanDefinitionRegistrar
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 导入普通类 / 配置类
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
} // catch ......
finally {
this.importStack.pop();
}
}
}
整体逻辑非常有序,它分别对 ImportSelector 、ImportBeanDefinitionRegistrar 、普通类 / 配置类都做了处理,并递归解析其中存在的配置类。
处理@ImportResource注解
// ............
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// ............
@ImportResource 可以导入 xml 配置文件,而解析这些 @ImportResource 的逻辑就在这里。
处理@Bean注解
// ............
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// ............
合着 @Bean 的处理也只是存起来。它是如何把这些 @Bean 方法都拿出来的,我们还得去看看 retrieveBeanMethodMetadata 方法:
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
AnnotationMetadata original = sourceClass.getMetadata();
// 获取被@Bean注解标注的方法
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
try {
AnnotationMetadata asm =
this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
if (asmMethods.size() >= beanMethods.size()) {
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
// 筛选每个方法
for (MethodMetadata asmMethod : asmMethods) {
for (MethodMetadata beanMethod : beanMethods) {
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
selectedMethods.add(beanMethod);
break;
}
}
}
if (selectedMethods.size() == beanMethods.size()) {
beanMethods = selectedMethods;
}
}
} // catch ......
}
return beanMethods;
}
这里 Spring 使用 ASM 读取字节码的目的,是为了保证加载配置类中 @Bean 方法的从上到下的顺序与源文件 .java 中一致。
处理父接口
// ............
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// .......
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
for (SourceClass ifc : sourceClass.getInterfaces()) {
// 寻找接口中标注了@Bean的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
for (MethodMetadata methodMetadata : beanMethods) {
if (!methodMetadata.isAbstract()) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
processInterfaces(configClass, ifc);
}
}
它会把配置类实现的所有接口都拿出来,并且遍历所有标注了 @Bean 的方法,并添加到 bean 的注册信息中。跟上面一样,它只是存起来,并没有封装为 BeanDefinition ,所以这里只是解析动作而已。
loadBeanDefinitions - 加载BeanDefinition
到这里,配置类的解析就完成了,回到 ConfigurationClassPostProcessor
中,解析完那些 @Bean 后还要注册为 BeanDefinition 呢,而这个方法的核心在 loadBeanDefinitions 中。
this.reader.loadBeanDefinitions(configClasses)
; 的执行会来到 ConfigurationClassBeanDefinitionReader
中:
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
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;
}
// 如果当前配置类是被@Import的,要把自己注册进BeanFactory
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 注册@Bean注解方法
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 注册来自xml配置文件的bean
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 注册来自ImportBeanDefinitionRegistrar的bean
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
// 如果条件装配将其跳过,则该@Bean标注的方法,对应的BeanDefinition不会注册进BeanDefinitionRegistry
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
// 检查方法上真的有@Bean注解吗
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
// assert ......
// 如果bean指定了多个name,则第1个为唯一标识,其余的都是alias别名
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
// 注解中配置了@Bean,与xml中的bean撞车了,会抛出异常
if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
// throw ex ......
}
return;
}
// 构造BeanDefinition
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
// 【复杂】解析@Bean所在方法的修饰符
if (metadata.isStatic()) {
// static @Bean method
if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
} else {
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
}
beanDef.setUniqueFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
// 处理@Bean的属性(name、initMethod等)、额外的注解(@Lazy、@DependsOn等) ......
// 注册进BeanDefinitionRegistry
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
一样标准的套路:检查 → 构造 BeanDefinition → 封装信息 → 注册进 BeanDefinitionRegistry 。
metadata.isStatic() ,它的判断逻辑下面,会给 BeanDefinition 封装两个属性:setBeanClassName / setFactoryBeanName 、setUniqueFactoryMethodName ,它们俩分别指定了当前 @Bean 方法所在的配置类,以及方法名。
前面 @Component 注解标注的类形成的 BeanDefinition ,以及 xml 配置文件转换出来的 BeanDefinition 有个什么特点?它们都指定了 bean 的全限定名、属性注入等,而且最终创建的对象一定是通过反射创建。而在注解配置类中的 @Bean
方法是有实际的代码执行,属于编程式创建,无法使用(也不适合用)反射创建 bean 对象,所以为了在后面能正常创建出 bean 对象,此处就需要记录该 bean 的定义源(包含注解配置类和方法名),以保证在创建 bean 对象时,能够使用反射调用该注解配置类的方法,生成 bean 对象并返回。
loadBeanDefinitionsFromImportedResources
这部分是解析从注解配置类上取到的 xml 配置文件的路径,有了前面的分析,我们马上就能猜到,它又要用 XmlBeanDefinitionReader 那一套来搞了,点开源码,发现果然如此:
private void loadBeanDefinitionsFromImportedResources(
Map<String, Class<? extends BeanDefinitionReader>> importedResources) {
Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
importedResources.forEach((resource, readerClass) -> {
if (BeanDefinitionReader.class == readerClass) {
if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
readerClass = GroovyBeanDefinitionReader.class;
}
else {
// 创建XmlBeanDefinitionReader,以备下面的解析
readerClass = XmlBeanDefinitionReader.class;
}
}
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
// reader的缓存等等
// 调用XmlBeanDefinitionReader解析资源文件
reader.loadBeanDefinitions(resource);
});
}
loadBeanDefinitionsFromRegistrars
最后一部分是执行 ImportBeanDefinitionRegistrar ,这个就更简单了,既然是接口,那执行它们的话,只需要调用 registerBeanDefinitions 方法就可以吧,进到方法内部,发现真就是这么简单:
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
}
总结
注解配置类的解析发生在 BeanDefinitionRegistryPostProcessor
的执行阶段,它对应的核心后置处理器是 ConfigurationClassPostProcessor
。
它主要负责两个步骤三件事情:
1.解析配置类
2.注册 BeanDefinition 。
三件事情包括:
1) 解析 @ComponentScan 并进行包扫描,实际进行包扫描的组件是 ClassPathBeanDefinitionScanner ;
2) 解析配置类中的注解(如 @Import 、@ImportResource 、@PropertySource 等)并处理,工作的核心组件是 ConfigurationClassParser ;
3) 解析配置类中的 @Bean 并封装 BeanDefinition ,实际解析的组件是 ConfigurationClassBeanDefinitionReader 。
BeanDefinition的后置处理
BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 的执行,而它们的执行时机还是上面的。
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors 方法中。
执行完这些后置处理器之后,BeanDefinition 的后置处理也就算结束了。
BeanDefinition部分的生命周期
首先,bean 的生命周期分为 BeanDefinition 阶段和 bean 实例阶段。
BeanDefinition 阶段分为加载 xml 配置文件、解析注解配置类、编程式构造 BeanDefinition 、BeanDefinition 的后置处理,一共四个部分。
1.加载 xml 配置文件 发生在基于 xml 配置文件的 ApplicationContext 中 refresh 方法的 BeanFactory 初始化阶段,此时 BeanFactory 刚刚构建完成,它会借助 XmlBeanDefinitionReader
来加载 xml 配置文件,并使用 DefaultBeanDefinitionDocumentReader
解析 xml 配置文件,封装声明的 <bean>
标签内容并转换为 BeanDefinition
。
2.解析注解配置类 发生在 ApplicationContext 中 refresh 方法的 BeanDefinitionRegistryPostProcessor 执行阶段,该阶段首先会执行 ConfigurationClassPostProcessor
的 postProcessBeanDefinitionRegistry
方法。ConfigurationClassPostProcessor
中会找出所有的配置类,排序后依次解析,并借助 ClassPathBeanDefinitionScanner
实现包扫描的 BeanDefinition
封装,借助 ConfigurationClassBeanDefinitionReader
实现 @Bean
注解方法的 BeanDefinition
解析和封装。
3.编程式构造 BeanDefinition 也是发生在 ApplicationContext 中 refresh 方法的 BeanDefinitionRegistryPostProcessor 执行阶段,由于 BeanDefinitionRegistryPostProcessor
中包含 ConfigurationClassPostProcessor
,而 ConfigurationClassPostProcessor
会执行 ImportBeanDefinitionRegistrar
的逻辑,从而达到编程式构造 BeanDefinition
并注入到 BeanDefinitionRegistry
的目的;另外,实现了 BeanDefinitionRegistryPostProcessor
的类也可以编程式构造 BeanDefinition
,注入 BeanDefinitionRegistry
。