xml配置:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="false">
<bean id="user" class="com.morris.spring.entity.User">
<description>这是一个描述信息,没什么卵用</description>
<meta key="str" value="I'm a meta attribute."/>
<property name="username" value="morris"/>
<property name="age" value="18"/>
</bean>
</beans>
使用ClassPathXmlApplicationContext来创建容器:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xml/spring-bean.xml");
User user = (User) context.getBean("user");
System.out.println(user);
运行结果如下:
User(username=morris, age=18)
源码分析
xml解析的入口:
org.springframework.context.support.AbstractApplicationContext#refresh
-> org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
-> org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
-> org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
下面只会展示一些源码以及关键流程节点:
AbstractXmlApplicationContext#loadBeanDefinitions
创建了一个XmlBeanDefinitionReader对象,将解析XML的工作委托给他:
// org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
/**
* 委托模式,委托XmlBeanDefinitionReader解析xml
*/
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
/**
* 真正的解析
*/
loadBeanDefinitions(beanDefinitionReader);
}
XmlBeanDefinitionReader.doLoadBeanDefinitions
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions
使用JDK提供的DOM解析xml为Document对象:
// org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 使用JDK提供的DOM解析xml为Document对象
Document doc = doLoadDocument(inputSource, resource);
// 注册BD
int count = registerBeanDefinitions(doc, resource);
... ...
}
XmlBeanDefinitionReader.registerBeanDefinitions
又使用委托模式,将从Document对象中解析BD的任务交给BeanDefinitionDocumentReader:
// org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
/**
* 又使用委托模式,将从Document对象中解析BD的任务交给BeanDefinitionDocumentReader
*/
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
/**
* @see DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(org.w3c.dom.Document, org.springframework.beans.factory.xml.XmlReaderContext)
*/
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
开始解析Bean标签:
// org.springframework.beans.factory.xml.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;
if (delegate.isDefaultNamespace(ele)) {
// 解析默认标签
parseDefaultElement(ele, delegate);
}
else {
// 解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 解析自定义标签
delegate.parseCustomElement(root);
}
}
DefaultBeanDefinitionDocumentReader.parseDefaultElement
何为默认标签:上面例子中的<bean>标签。
解析默认标签:
// org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
// 处理import标签
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
// 处理alias标签
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
// 处理Bean标签
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 处理beans标签
// recurse
doRegisterBeanDefinitions(ele);
}
}
BeanDefinitionParserDelegate.parseBeanDefinitionElement
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)
解析<bean>元素:
// org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element, java.lang.String, org.springframework.beans.factory.config.BeanDefinition)
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
... ...
try {
// GenericBeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 解析Bean标签的属性,只是简单的将xml中属性的值设置到BD,没有任何处理逻辑
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
// 处理Bean标签的description子标签
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 解析子元素meta
parseMetaElements(ele, bd);
// 解析look-up子元素
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// 解析replaced-method子元素
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
// 解析constructor-arg子元素
parseConstructorArgElements(ele, bd);
// 解析property子元素
parsePropertyElements(ele, bd);
// 解析qualifier子元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
... ...
BeanDefinitionParserDelegate.createBeanDefinition
创建GenericBeanDefinition:
// org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}
BeanDefinitionParserDelegate.parseBeanDefinitionAttributes
解析Bean标签的属性,只是简单的将xml中属性的值设置到BD,没有任何处理逻辑:
// org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionAttributes
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
@Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
... ...
BeanDefinitionParserDelegate.parseMetaElements
meta子元素的的使用:
<bean id="user" class="com.morris.spring.entity.User">
<description>这是一个描述信息,没什么卵用</description>
<meta key="str" value="I'm a meta attribute."/>
</bean>
这段代码并不会直接体现在User的属性当中,而是一个额外的声明,当需要使用里面的信息的时候可以通过BeanDefinition的getAttribute(key)方法进行获取。
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
NodeList nl = ele.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) {
Element metaElement = (Element) node;
String key = metaElement.getAttribute(KEY_ATTRIBUTE);
String value = metaElement.getAttribute(VALUE_ATTRIBUTE);
BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
attribute.setSource(extractSource(metaElement));
// meta放入到bd的attribute中
attributeAccessor.addMetadataAttribute(attribute);
}
}
}
总结:Bean默认标签解析后的结果就是生成一个BeanDefinition添加到Spring容器当中。
BeanDefinitionParserDelegate.parseCustomElement
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
解析自定义标签,自定义标签类似下面的context:component-scan
:
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="false">
<context:component-scan base-package="com.morris.spring"/>
</beans>
解析自定义标签的步骤如下:
-
获取自定义标签的namespace命令空间,例如:http://www.springframework.org/schema/context。
-
根据命名空间获取NamespaceHandler对象。
-
调用NamespaceHandler对象的parse()进行解析。
// org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获得namespace,如http://www.springframework.org/schema/context
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
/**
* @see DefaultNamespaceHandlerResolver#resolve(java.lang.String)
*/
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
/**
* @see NamespaceHandlerSupport#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*/
// 开始解析自定义标签
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
DefaultNamespaceHandlerResolver.resolve
-
获取所有的handlerMappings。
-
根据namespace从handlerMappings中获得NamespaceHandler。
-
如果解析器是类名,就通过反射进行实例化,并放入handlerMappings中,第二次使用时就是对象,不再需要实例化了。
-
调用NamespaceHandler的init()方法进行初始化。
// org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
public NamespaceHandler resolve(String namespaceUri) {
// 获取所有的handlerMappings
Map<String, Object> handlerMappings = getHandlerMappings();
// 根据key获得value,如org.springframework.context.config.ContextNamespaceHandler
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
// 第二次及后续解析相同的namespace时,就会进入这里,类在下面的else中被缓存了
return (NamespaceHandler) handlerOrClassName;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
// 实例化NamespaceHandler
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 调用NamespaceHandler的init()方法
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
... ...
}
}
DefaultNamespaceHandlerResolver.getHandlerMappings
加载所有META-INF/spring.handlers
中的内容封装为一个Map。
// org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
// 只初始化一次
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
if (logger.isTraceEnabled()) {
logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
}
try {
/**
* @see DefaultNamespaceHandlerResolver#DEFAULT_HANDLER_MAPPINGS_LOCATION
*/
// 加载所有META-INF/spring.handlers为Properties
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {
logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}
handlerMappings = new ConcurrentHashMap<>(mappings.size());
// 将Properties的内容转化为Map
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}
下面来看下META-INF/spring.handlers
的内容是什么,这里以spring-context为例,spring的其他jar下面也有这个文件:
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
NamespaceHandler.init
NamespaceHandler的init()只是往往父类的parsers属性中添加各种解析器,方便后续parse时使用。
// org.springframework.context.config.ContextNamespaceHandler#init
public void init() {
// 往父类的parsers属性中添加各种解析器
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
NamespaceHandler#parse
根据localName获得具体的解析器BeanDefinitionParser:
public BeanDefinition parse(Element element, ParserContext parserContext) {
// ComponentScanBeanDefinitionParser
,根据名字获得具体的解析器
BeanDefinitionParser parser = findParserForElement(element, parserContext);
/**
* @see org.springframework.context.annotation.ComponentScanBeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*/
return (parser != null ? parser.parse(element, parserContext) : null);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// localName为context:component-scan中的component-scan
String localName = parserContext.getDelegate().getLocalName(element);
// parsers这个属性一般是前面调用NamespaceHandler.init()时添加的
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
总结
BeanDefinition的各种类型:
-
经过解析XML注入的BeanDefinition的类型为GenericBeanDefinition。
-
经过ComponentScan扫描注入的BeanDefinition的类型为ScannedGenericBeanDefinition。
bean标签
XML值的bean元素解析后会被封装为一个BeanDefinition对象,所以BeanDefinition对象会有一个属性来存储bean元素中的属性。
bean标签的属性总结:
-
id:Bean的唯一标识名。它必须是合法的XMLID,在整个XML文档中唯一。
-
name:用来为id创建一个或多个别名。它可以是任意的字母符合。多个别名之间用逗号或空格分开。
-
class:用来定义类的全限定名(包名+类名)。只有子类Bean不用定义该属性。
-
parent:子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性。注意:子类Bean和父类Bean是同一个Java类。
-
abstract(默认为”false”):用来定义Bean是否为抽象Bean。它表示这个Bean将不会被实例化,一般用于父类Bean,因为父类Bean主要是供子类Bean继承使用。
-
singleton(默认为“true”):定义Bean是否是Singleton(单例)。如果设为“true”,则在BeanFactory作用范围内,只维护此Bean的一个实例。如果设为“flase”,Bean将是Prototype(原型)状态,BeanFactory将为每次Bean请求创建一个新的Bean实例。
-
lazy-init(默认为“default”):用来定义这个Bean是否实现懒初始化。如果为“true”,它将在BeanFactory启动时初始化所有的SingletonBean。反之,如果为“false”,它只在Bean请求时才开始创建SingletonBean。
-
autowire(自动装配,默认为“default”):它定义了Bean的自动装载方式。
-
“no”:不使用自动装配功能。
-
“byName”:通过Bean的属性名实现自动装配。
-
“byType”:通过Bean的类型实现自动装配。
-
“constructor”:类似于byType,但它是用于构造函数的参数的自动组装。
-
“autodetect”:通过Bean类的反省机制(introspection)决定是使用“constructor”还是使用“byType”。
-
-
dependency-check(依赖检查,默认为“default”):它用来确保Bean组件通过JavaBean描述的所以依赖关系都得到满足。在与自动装配功能一起使用时,它特别有用。
-
none:不进行依赖检查。
-
objects:只做对象间依赖的检查。
-
simple:只做原始类型和String类型依赖的检查
-
all:对所有类型的依赖进行检查。它包括了前面的objects和simple。
-
-
depends-on(依赖对象):这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。
-
init-method:用来定义Bean的初始化方法,它会在Bean组装之后调用。它必须是一个无参数的方法。
-
destroy-method:用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参数的方法。它只能应用于singletonBean。
-
factory-method:定义创建该Bean对象的工厂方法。它用于下面的“factory-bean”,表示这个Bean是通过工厂方法创建。此时,“class”属性失效。
-
factory-bean:定义创建该Bean对象的工厂类。如果使用了“factory-bean”则“class”属性失效。
-
autowire-candidate:采用xml格式配置bean时,将元素的autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,即它不会被考虑作为其它bean自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其它bean的。
Spring SPI与Java SPI的区别
-
Java中的SPI,文件名即接口,文件中的内容为接口的实现类,文件内容中的所有类都会被加载。
-
Spring中的SPI,文件中内容为key-value格式,可以实现不同接口的类放在一个文件中,还可以按需加载,节省内存。