总体流程
- AbstractBeanDefinitionReader 通过 ResourceLoader 将资源文件路径转换成对应的 Resource 文件
- DocumentLoader 将 Resource 文件转换成 Document 文件
- 通过实现接口 BeanDefinitionDocumentReader 的 DefaultBeanDefinitionDocumentReader 类对 Document 进行解析,并使用 BeanDefinitionParserDelegate 对 Element 进行解析
ClassPathResource
作用:将文件路径处理成 Resource
测试代码
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.File;
import java.net.URL;
public class ClassPathResourceDemo {
public static void main(String[] args) throws Exception {
newClassPathResource();
classLoaderTest();
}
public static void newClassPathResource() throws Exception {
// 在 classpath 下准备任意一个文件, 可以是 xml/properties 等
Resource resource = new ClassPathResource("person.properties");
// 这里相当于将前面的 "/" 去掉
File file = resource.getFile();
String path = file.getAbsolutePath();
System.out.println(path);
}
public static void classLoaderTest() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource("");
String protocol = url.getProtocol();
String file = url.getFile();
System.out.println("protocol = " + protocol);
System.out.println("file = " + file);
}
public static void clazzTest() {
// 这里必须使用 "/" 开头
URL url2 = ClassPathResourceDemo.class.getResource("/person.properties");
String url2Protocol = url2.getProtocol();
String url2File = url2.getFile();
System.out.println("url2Protocol = " + url2Protocol);
System.out.println("url2File = " + url2File);
}
}
ClassPathResource 源码解析
public class ClassPathResource extends AbstractFileResolvingResource {
// 传入的文件路径: 会进行一个标准化处理
private final String path;
// 类加载器, 从getDefaultClassLoader()方法中可以看出其默认顺序:
// 1. Thread.currentThread().getContextClassLoader()
// 2. ClassUtils.class.getClassLoader()
// 3. ClassLoader.getSystemClassLoader()
@Nullable
private ClassLoader classLoader;
@Nullable
private Class<?> clazz;
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
// 使用"/person.properties"最终还是会被处理成"person.properties"
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
}
BeanDefinitionReader 接口
作用:加载上面处理好的 Resource 对象
// 读取资源文件并转换到 BeanDefinition
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
// ResourceLoader: 资源加载器, 根据给定的资源文件地址返回对应的 Resource
ResourceLoader getResourceLoader();
ClassLoader getBeanClassLoader();
BeanNameGenerator getBeanNameGenerator();
// 关键方法loadBeanDefinitions()
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
AbstractBeanDefinitionReader
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
protected final Log logger = LogFactory.getLog(getClass());
// 用于注册 BeanDefinition
// BeanDefinitionRegistry 约等于 BeanFactory
// @Getter
private final BeanDefinitionRegistry registry;
// 加载资源对象
// 缺省实现: PathMatchingResourcePatternResolver()
// @Setter
// @Getter
@Nullable
private ResourceLoader resourceLoader;
// @Setter
// @Getter
@Nullable
private ClassLoader beanClassLoader;
// 用于读取环境相关的信息
// 缺省实现: StandardEnvironment()
// @Setter
// @Getter
private Environment environment;
// 用于生成 Bean 的 name(id)
// 缺省实现
// @Setter(防止破坏默认值的设计)
// @Getter
private BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator.INSTANCE;
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// 如果传入的 registry 同时实现了 ResourceLoader 接口, 那么 resourceLoader 设置为 registry
// 如果传入的 registry 就是一个单纯的 BeanDefinitionRegistry 实现类对象, 那么 resourceLoader 设置为 PathMatchingResourcePatternResolver 对象
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// 动机同上, 缺省实现为 StandardEnvironment
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
// 具体加载单个 Resource 的方法由 XmlBeanDefinitionReader 等子类进行实现
count += loadBeanDefinitions(resource);
}
return count;
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
// 如果 ResourceLoader 是 ResourcePatternResolver 对象, 可以通过模式匹配批量加载 Source 对象
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
// 提供的是一个支持模式匹配的路径location, 可能对应多个Resource对象
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
return count;
}
else {
// Can only load single resources by absolute URL.
// 一般的 ResourceLoader 只能通过绝对路径来加载单个 Source
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
// 将 Resource 对象添加到 actualResources 集合中
actualResources.add(resource);
}
return count;
}
}
}
XmlBeanDefinitionReader
loadBeanDefinitions 方法
- 通过 Resource 对象加载,即
loadBeanDefinitions(Resource resource)
由子类(XmlBeanDefinitionReader等)实现 - 通过 String 路径加载,即
loadBeanDefinitions(String location, Set<Resource> actualResources)
- 如果 ResourceLoader 是 ResourcePatternResolver,那么支持 location 中使用模式匹配,可以解析 location,批量导入多个 Resource
- 如果 ResourceLoader 不是 ResourcePatternResolver,那么 location 只能使用绝对路径
- 解析出来的 Resource 对象都会被添加到传入的(形参) Set 集合(actualResources)中
- 通过 String 路径加载最后还是落实到通过 Resource 方式加载上
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// 当前正在被加载的 Resources
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
// 检查是否重复加载, 什么情况下会出现这种情况?
if (!currentResources.add(encodedResource)) {
throw e;
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
// 从encodedResource中获取InuptStream, 封装成InputStore
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 真正的处理操作doLoadBeanDefinitions()
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw e;
}
finally {
// resource处理完成, 从集合中删除
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
getEntityResolver 方法
主要考虑在没有设置 EntityResolver 的情况下,根据 ResourceLoader 有两种可能:
- 如果 ResourceLoader 为 null,那么
new DelegatingEntityResolver(getBeanClassLoader())
- 如果 ResourceLoader 不为 null,那么
new ResourceEntityResolver(resourceLoader)
// 自定义处理外部实体时, 需要向SAX驱动器注册一个EntityResolver
// EntityResolver的作用是由项目本身来提供一个如何寻找DTD声明的方法
protected EntityResolver getEntityResolver() {
if (this.entityResolver == null) {
// Determine default EntityResolver to use.
// 如果没有设置EntityResolver
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
this.entityResolver = new ResourceEntityResolver(resourceLoader);
}
else {
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
doLoadBeanDefinitions 方法
loadBeanDefinitions(Source source)
被包装成 loadBeanDefinitions(EncodedSource source)
,再进一步实际处理的是 doLoadBeanDefinitions(..)
方法,其中 InputStore 是从 Source 中获取的 InputStream 的一层包装。
doLoadBeanDefinition() 方法的步骤:
doLoadDocument(inputSource, resource)
:将 Resource 转变为 Document,通过调用documentLoader.loadDocument(..)
方法registerBeanDefinitions(doc, resource)
:解析 Document 并转化成 BeanDefinition 进行注册
// 核心方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
// Resource -> Document
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
return count;
}
registerBeanDefinitions 方法
- 创建一个 BeanDefinitionDocumentReader,默认是 DefaultBeanDefinitionDocumentReader 对象,由
private Class documentReaderClass
字段的默认值DefaultBeanDefinitionDocumentReader.class
决定 - 通过该 BeanDefinitionDocumentReader 对象的
registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
方法来进行注入 BeanDefinition
// 核心方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建一个 BeanDefinitionDocumentReader, 默认是DefaultBeanDefinitionDocumentReader对象, 由 private Class<? extends BeanDefinitionDocumentReader> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;决定
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取注入前BeanFactory中BeanDefinition的数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 调用documentReader中的方法完成
// 对resource再一次进行封装成XmlReaderContext
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 获取注入后BeanFactory中BeanDefinition的数量
// 二者相减, 返回当前注入BeanFactory中BeanDefinition的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
DefaultBeanDefinitionDocumentReader
doRegisterBeanDefinitions 方法
registerBeanDefinitions(..)
方法获取到 Document 的 root 节点后,调用 doRegisterBeanDefinitions(Element root)
方法进行真正的工作。
在 doRegisterBeanDefinitions 方法中:
createDelegate(..)
创建 BeanDefinitionParserDelegate 对象,对 ReaderContext 的包装(似乎还是对 Resource、Document 的包装)?或者含有什么方便的解析工具?- 处理了
<beans>
标签中的 profile 属性,(如果没有 profile 属性,则不进行额外处理)。处理完成后,调用parseBeanDefinitions(root, this.delegate)
进行根节点的解析 - 调用
parseBeanDefinitions(..)
方法 - 疑问:
BeanDefinitionParserDelegate parent = this.delegate;
和this.delegate = parent;
是为什么?
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
// 为readerContext进行赋值, 本质上是一个Source的包装
this.readerContext = readerContext;
// 对doc的根节点进行解析 (Spring配置文件的根节点: beans)
doRegisterBeanDefinitions(doc.getDocumentElement());
}
// 核心方法
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");
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
// preProcessXml(root) 和 postProcessXml(root) 这两个方法都是空实现, 什么都没有做
//preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//postProcessXml(root);
// 还原回去, 这是为什么?
this.delegate = parent;
}
parseDefaultElement 方法
parseBeanDefinitions(..)
方法是常规的 XML 解析技术,获取根节点 root 的非空白子元素,即获取 <beans>
标签的 <bean>
。
通过调用 parseDefaultElement(ele, delegate)
来解析 <beans>
的子标签,包括 <import>
、<alias>
、<bean>
以及嵌套的 <beans>
,针对前三种子标签,有对应专门的解析方法,对于嵌套的 <beans>
则采用递归处理。
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) {
// 上面都是常规的XML解析, 如果root对应<beans>标签, 那么ele就是一个<bean>标签
Element ele = (Element) node;
// TODO: XML解析技术中的Namespace需要再了解下, 应该是schema
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 自定义元素? 怎么解释?
// 例如 <tx:annotation> 这些标签
delegate.parseCustomElement(root);
}
}
// 核心方法: 解析单个bean标签
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, "import")) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, "alias")) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, "bean")) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, "beans")) {
// recurse
// 递归调用
doRegisterBeanDefinitions(ele);
}
}
importBeanDefinitionResource 方法
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute("resource");
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
// Resolve system properties: e.g. "${user.dir}"
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
Set<Resource> actualResources = new LinkedHashSet<>(4);
// Discover whether the location is an absolute or relative URI
boolean absoluteLocation = false;
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
// Absolute or relative?
if (absoluteLocation) {
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
} else {
// No URL -> considering resource location as relative to the current file.
int importCount;
Resource relativeResource = getReaderContext().getResource().createRelative(location);
if (relativeResource.exists()) {
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
} else {
String baseLocation = getReaderContext().getResource().getURL().toString();
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
}
Resource[] actResArray = actualResources.toArray(new Resource[0]);
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
processAliasRegistration 方法
protected void processAliasRegistration(Element ele) {
String name = ele.getAttribute("name");
String alias = ele.getAttribute("alias");
boolean valid = true;
if (!StringUtils.hasText(name)) {
getReaderContext().error("Name must not be empty", ele);
valid = false;
}
if (!StringUtils.hasText(alias)) {
getReaderContext().error("Alias must not be empty", ele);
valid = false;
}
if (valid) {
getReaderContext().getRegistry().registerAlias(name, alias);
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
}
}
processBeanDefinition 方法
<bean>
标签的解析- holder 的注册
- 利用事件机制通知监听器
// 处理bean标签
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 1. 委托delegate对象来解析bean标签, 返回一个holder, holder中包含bean标签中的各种属性: class/name/id/alias等
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 2. 如果bean标签下面还有自定义属性、标签, 还需要再次对自定义的标签进行解析
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
// 3. 对解析完成后的holder进行注册, 委托给BeanDefinitionReaderUtils
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
// 4. 发出事件, 通知相关的监听器EventListener
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionParserDelegate
parseBeanDefinitionElement 方法(解析Bean标签)
name 属性可以通过指定的分隔符来指定多个字段,这些字段都会被作为 alias
id 属性作为 beanName 的默认值。
但如果没有设置 id 属性,同时设置了 name 属性,就会将第一个 name 作为 beanName
检查是否有重复的 beanName
通过 parseBeanDefinitionElement 去进一步解析 bean 标签
考虑在 id 属性和 name 属性都没有设置的情况下,生成 beanName
- 如果
containingBean != null
,通过BeanDefinitionReaderUtils.generateBeanName()
来生成 beanName - 如果
containingBean == null
,通过readerContext.generateBeanName()
来生成 beanName
- 如果
通过 beanName、aliases、BeanDefinition 来创建一个 BeanDefinitionHolder。
换句话说,这是否意味着 BeanDefinition 中 beanName 是可以为 null 的,而 BeanDefinitionHolder 中 beanName 必须不为 null ?也许不是,但 BeanDefinition 中不包含 aliases
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute("id");
String nameAttr = ele.getAttribute("name");
// 1. name 属性可以通过指定的分隔符来指定多个字段,这些字段都会被作为 alias
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
// 根据StringTokenizer进行分词, 去除首尾空格和空元素, 例如, "a,,b"只会保留a和b
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
}
// 2. id 属性作为 beanName 的默认值
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
// 如果id属性为null, 并且name属性不为null, 就会将第一个name作为beanName
beanName = aliases.remove(0);
}
if (containingBean == null) {
// 3. 检查是否有重复的beanName
checkNameUniqueness(beanName, aliases, ele);
}
// 4. 得到BeanDefinition
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 正常的BeanDefinition处理流程
if (!StringUtils.hasText(beanName)) {
// 5. id属性和name属性都没有设置的情况下, beanName为null
if (containingBean != null) {
// 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);
}
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
// 解析出来是个不正常的Beandefinition(null), 直接返回null
return null;
}
parseBeanDefinitionElement 方法(重载、重点)
- 解析 class 和 parent 属性
- 通过 className(class属性值) 和 parent 来创建 BeanDefinition
- 各种真正的解析逻辑
- parseBeanDefinitionAttributes:设置 BeanDefinition 的各个属性值,没有设置的使用默认值
- parseMetaElements:
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 1. 解析class属性和parent属性
String className = null;
if (ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
String parent = null;
if (ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
try {
// 2. 通过 className(class属性值) 和 parent 来创建 BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 3. 各种解析逻辑
// 3.1 设置属性值
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 3.2
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
finally {
this.parseState.pop();
}
return null;
}
parseBeanDefinitionAttributes 方法(设置 BeanDefinition 属性)
- singleton 属性被 scope 属性取代,不能在 bean 标签中使用 singleton 属性
- 如果当前 bean 未定义 scope 属性, 但是内部的 bean 定义了 scope 属性, 那么使用内部 bean 的 scope 属性
- 设置 abstract 属性,默认值为 false
- 设置 lazy-init 属性
- 设置 autowire 属性,自动注入方式:
- AbstractBeanDefinition.AUTOWIRE_NO
- AbstractBeanDefinition.AUTOWIRE_BY_NAME
- AbstractBeanDefinition.AUTOWIRE_BY_TYPE
- AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR
- AbstractBeanDefinition.AUTOWIRE_AUTODETECT
- 设置 depends-on 属性,可以设置多个,使用分隔符分隔即可
- 设置 autowire-candidate 属性
- 设置 primary 属性
- 设置 init-method 属性
- 设置 destroy-method 属性
- 设置 factory-method 属性
- 设置 factory-bean 属性
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
// 1. 检查 scope 属性
if (ele.hasAttribute("singleton")) {
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) {
// 2. 如果当前 bean 未定义 scope 属性, 但是内部的 bean 定义了 scope 属性, 那么使用内部 bean 的 scope 属性
bd.setScope(containingBean.getScope());
}
// 3. 如果 abstract 属性设置为 true, 进行设置
if (ele.hasAttribute("abstract")) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute("abstract")));
}
// 4. 设置lazy-init
String lazyInit = ele.getAttribute("lazy-init");
if (isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
// 5. 设置autowire
String autowire = ele.getAttribute("autowire");
bd.setAutowireMode(getAutowireMode(autowire));
// 6. 设置depends-on
if (ele.hasAttribute("depends-on")) {
String dependsOn = ele.getAttribute("depends-on");
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, ",; "));
}
// 7. 设置autowire-candidate
String autowireCandidate = ele.getAttribute("autowire-candidate");
if (isDefaultValue(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
// TODO: 为什么获取到默认值后还判断是否为null呢?
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
} else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
// 8. 设置primary
if (ele.hasAttribute("primary")) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute("primary")));
}
// 9. 设置init-method 或默认的init-method
if (ele.hasAttribute("init-method")) {
String initMethodName = ele.getAttribute("init-method");
bd.setInitMethodName(initMethodName);
} else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
// 10. 设置destroy-method 或默认destroy-method
if (ele.hasAttribute("destroy-method")) {
String destroyMethodName = ele.getAttribute("destroy-method");
bd.setDestroyMethodName(destroyMethodName);
} else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
// 11. 设置factory-method
if (ele.hasAttribute("factory-method")) {
bd.setFactoryMethodName(ele.getAttribute("factory-method"));
}
// 12. 设置factory-bean
if (ele.hasAttribute("factory-bean")) {
bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
}
return bd;
}
parseMetaElements 方法(解析 bean 标签的 meta 子标签)
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
// 获取bean标签下的子标签
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 解析<bean>标签下面的<meta>标签
if (isCandidateElement(node) && nodeNameEquals(node, "meta")) {
Element metaElement = (Element) node;
String key = metaElement.getAttribute("key");
String value = metaElement.getAttribute("value");
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
// attributeAccessor 就是一个 BeanDefinition, AbstractBeanDefinition 继承于 BeanMetadataAttributeAccessor
// 但 BeanDefinition 是一个接口, 且和该父类没有关系, 似乎是一种设计模式, 适配器? 忘了!
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
parseLookupOverrideSubElements 方法
TODO
parseReplacedMethodSubElements 方法
TODO
parseConstructorArgElements 方法
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, CONSTRUCTOR_ARG_ELEMENT)) {
parseConstructorArgElement((Element) node, bd);
}
}
}
// 具体细节
public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(indexAttr)) {
try {
int index = Integer.parseInt(indexAttr);
if (index < 0) {
error("'index' cannot be lower than 0", ele);
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry(index));
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
error("Ambiguous constructor-arg entries for index " + index, ele);
}
else {
bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
}
}
finally {
this.parseState.pop();
}
}
}
}
else {
try {
this.parseState.push(new ConstructorArgumentEntry());
Object value = parsePropertyValue(ele, bd, null);
ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
if (StringUtils.hasLength(typeAttr)) {
valueHolder.setType(typeAttr);
}
if (StringUtils.hasLength(nameAttr)) {
valueHolder.setName(nameAttr);
}
valueHolder.setSource(extractSource(ele));
bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
}
finally {
this.parseState.pop();
}
}
}
parsePropertyElements 方法(复杂 TODO)
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd);
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
parseQualifierElements 方法
public void parseQualifierElements(Element beanEle, AbstractBeanDefinition bd) {
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, QUALIFIER_ELEMENT)) {
parseQualifierElement((Element) node, bd);
}
}
}