重写下Spring-源码分析:
一、首先看下全局图:
1、首先原材料进入spring工厂,原材料也可以说成是资源,我们可以称之为set方法
2、然后从spring工厂获得到目标,称之为get方法
3、而我们的目标全是依赖原材料。
所以就是想要得到某个目标的话,必须要失去某个东西,这也是社会上必然的规律。
那么今天分析下Spring是如何将原材料转换成目标的?我们应该带着问题去学习源码:
二、定个总目标:
从原材料中获取到某个东西,get到对象的实例,如何让Spring工厂帮我们产生对象实例?
1、然后期间分成多个小目标,最后组合起来形成总目标,spring也是这样做的
2、然后看这个目标从哪个母体里面产生出来的,这个概念是非常重要的,也就是说想要得到某个目标,必须要有它的母体,没有母体,目标是无法达到的,母体就是主要依据。
3、我们理解的工厂模式:主要是用来get东西的,spring也是这样的,只不过,spring对它做了非常大的扩展,那么扩展依据又是什么呢?
三、看下spring-beans的体系结构分析图:
在我们java中解决问题,是用接口来解决问题的,接口就是目标和母体之间的桥梁,那么我们抽象为接口,那么接口中的某个方法就是实现目标的某个步骤
总目标的入口
①、首先看下BeanFactory接口:获取基本对象的接口,传个类型,别名,名称进去这个接口是解决总目标的抽象接口,我们要getBean,要get对象实例,我们要有个接口,就可以通过工厂给返回结果。命名为BeanFactory,也是工厂的设计模式,但是它的扩展方式是非常的严格的,这个问题是由具体的场合来解决,在spring中一种是xml,一种是注解,还有一种是外部的spring环境帮我们解决,还有一种是springBoot的环境。
②、原材料就是定义的类,原材料如果放到xml里面,就是xml的原材料,如果放到注解里面,就是注解里面的原材料,但是核心不变,就是类。
③、类有多态,所以接口ListableBeanFactory就是解决多个对象实例问题的。对象有父类,HierarchicalBeanFactory解决继承的问题,解决能够创建一个父工厂,这三个接口是解决获取实例的方法,称之为get。
④、ConfigurableBeanFactory:解决内部依赖配置问题的,就是一些内部组件的配置,所以它是set的操作,set某个资源进去
⑤、AutowireCapableBeanFactory:具有创建对象的能力
然后用ConfigurableListableBeanFactory这个接口把上面的所有的功能的接口进行汇总,由它给暴漏功能。
这些接口解决对象关系创建的问题的,但是还没有和具体的环境联系起来,联系起来是从Bean定义开始的。
四、子目标要依赖总目标的实现
由于一个框架是解决一类问题的,无法预知有多少种情况,我们需要给它规范下,给它统一的一个名称,在spring中就统一定义为BeanDefinition接口,只是原材料加工时产生的对象。
由BeanWrapper接口代替所有具体的类的实例,而我们看到的是Bean标签,从具体到抽象,由接口作为抽象,也可以用抽象类,但是一般用接口来代替
五、那么我么如何获取到BeanWrapper接口呢?我们如何去获取到原材料,原材料在哪里?
①、我们要获取一个对象的实例,我们如何获取类,我们只有得到具体的class,我们才能够new对象。我们现在只知道了实例了,那么我们如何去获取到BeanWrapper对象呢?
②、现在不知道原材料在哪里,我知道Class是我的原材料,现在不能从类里面获取,必须提供统一的入口,那么这个入口是什么呢?一种是用xml来装我们的原材料,第二个是注解
③、以xml为例,xml文件将所有的Class对象全部封装在xml文件里面,只要我们配置了定义的类,也就是原材料,我们就可以从工厂里面获取到BeanWrapper接口,然后进而返回具体的实例。
④、在spring中将Class对象和Bean定义对象进行分开了,但是放在统一的入口里面,只是出口是不同的对象
⑤、原材料,就是定义的类,我们才能够new对象,而类的属性会有基本数据类型,会有复杂的数据类型,还会有一个数据结构,比如下面的原材料:
package com.weizhaoyang.spring5;
import java.util.List;
public class App {
private App app;
private Integer id;
private List<Object> d;
}
⑥、在spring中用BeanDefinition接口代替所有的类,用一个PropertyValue对象代替所有的属性, 类的属性是很多的,在spring中用PropertyValues对象代替很多的属性。这三个抽象也是对xml文件中bean的一个抽象。类是定义在xml文件里面的,在依赖注入的时候,就是对类的属性赋值。属性的复杂类型用ref来表示,字符串用value来表示值。
<?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">
<bean id="xx" class="com.weizhaoyang.spring5.App" name="">
<property name="id" ref="app" value="123"></property>
</bean>
</beans>
⑦、如何将xml文件中的字符串的值转换成java认识的对象呢?
这时在spring中抽象出BeanDefinitionValueResolver对象:就是将PropertyValue封装的字面量进行转换成执行的类型。
上面的对象只能解析成java认识的String类型,如果java的类的属性是int类型的话,那么如何将xml文件中的字符串的类型转成int类型呢?在Spring中抽象成TypeConverter接口:将PropertyValue解析后的属性值转换成指定类型,使用PropertyEdit编辑装换成指定值。
总结:BeanDefinition接口和PropertyBean对象和PropertyValues对象是对xml文件类的封装 ,这三个就是进行set的操作。BeanDefinitionValueResolver对象和TypeConverter接口BeanWrapper接口就是获得对象的操作
六、我们把bean放到了xml文件,那么如何获取到xml文件呢?如何获取到BeanDefinition接口的?上面的只是现象 ,那么如何去产生这个现象呢?
1、xml是母体
2、读取xml,解析xml,封装成BeanDefinition接口和PropertyBean对象和PropertyValues对象,然后再保存对象。又定一个小目标:如何获取到BeanDefinition接口:
我们主要看的是beans的jar包,spring-core主要提供的是spring-beans的基础的功能而已
core里面主要提供两个入口:1、提供基本的bean定义,就是bean策略。
instantiator:提供 bean实例化的功能。lang:是java语言的功能
core:里面有几个是核心的:一个是编码和解码
一个是annotation,将类上的所有的注解做了一个封装
convet:针对类型转换的封装
env:是环境的封装,就是profile,用springBoot的时候用的最多,有测试环境,开发环境,生产环境
io:比如现在的xml文件放到了本地,它也有可能放到远程,io就是将资源进行全部的抽象,里面重要的是Resource和ResourceLoader很重要。
log:对日志的封装。
serializer:对序列化的封装。
style:是对打印日志样式的封装。
task:是对同步和异步线程的封装,里面继承了executor线程池的接口。
name:可以定义别名,别名就是注册在AliasRegistry接口里面,提供了基本的功能,没有具体的场景,所以bean定义接口就继承了这个AliasRegistry接口
总结:spring将java中的对象全部做了一个封装,这也就是spring为什么这么庞大,全部抽象出它自定义的类,比如自己定义的类,方法,属性,它全给进行了封装,这才是面向对象的特点。比如:将属性进行一个包装,代替所有的场合,这是面向对象的思维。
七、如何获取到BeanDefinition接口?
1、写个对于总目标的总入口:resource封装为核心对象,下面的步骤就是set的过程
public class Main {
public static void main(String[] args) {
//统一的入口加载资源类
//set过程
ResourceLoader resourceLoader=new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("spring-mvc.xml");
BeanFactory beanFactory=new XmlBeanFactory(resource);
//get过程
Object app = beanFactory.getBean("app");
}
}
2、那么如何得到BeanDefinition对象呢?先从总目标XmlBeanFactory开始看
@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource the XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource the XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
在上面的类中,首先resource是对资源的抽象,然后把它放入到加载bean定义的方法 reader.loadBeanDefinitions(resource):代表从文档里面加载。总目标是给外部调用的接口,给内部调用的都是子目标。
2、然后到了XmlBeanDefinitionReader类:首先对资源进行编码和解码
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
上面的代码是对资源进行的一些解析,主要获取到InputStream,因为文档转成inputStream,才能够进行读取。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
在转成document对象要知道xml文件有两种xsl,xsd,上面的代码就开始加载Bean定义了,把输入流转成Document对象,这时开始进行模式校验:getValidationModeForResource
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}
校验之后,返回出去,获取到了document文档,然后开始解析
int count = registerBeanDefinitions(doc, resource);
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;
}
BeanDefinitionDocumentReader:是一个类部的类在操作
BeanDefinitionDocumentReader documentReader =createBeanDefinitionDocumentReader();
初始化documentReaderClass,类部使用的
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanUtils.instantiateClass(this.documentReaderClass);
}
bean的实例化:就是反射实例化的过程
public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
Assert.notNull(clazz, "Class must not be null");
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
return instantiateClass(clazz.getDeclaredConstructor());
}
catch (NoSuchMethodException ex) {
Constructor<T> ctor = findPrimaryConstructor(clazz);
if (ctor != null) {
return instantiateClass(ctor);
}
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
catch (LinkageError err) {
throw new BeanInstantiationException(clazz, "Unresolvable class definition", err);
}
}
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
然后回到XmlBeanDefinitionReader
createReaderContext:需要通过XmlReaderContext接口来解析xml中自定义的标签,除了beans的剩下的都是自定义的。接口:NameSpaceHandler:自定义标签解析器,这个接口在spring里面非常的核心,但是在SpringBoot里面就不核心了。
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
回到XmlBeanDefinitionReader类,进行注册BeanDefinitions对象
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
然后看下XmlReaderContext这个类,里面封装了标签解析器和阅读Bean定义对象
final XmlBeanDefinitionReader reader;
private final NamespaceHandlerResolver namespaceHandlerResolver;
然后撤回来:获取完文档,就开始注册Bean定义,参数root:就是xml文件里面的beans标签,但是委托BeanDefintionParserDelegate,类部进行委托的:用这个对象产生Bean定义接口的。
doRegisterBeanDefinitions(doc.getDocumentElement());
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
上面的是创建一个委托的方法,默认的创建了BeanDefinitionParserDelegate,Bean定义的解析委托类,把xml自定义标签的解析器传进来。然后初始化委托,这时委托类就创建成功了。
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
上面的方法这时会判断是否是默认的命名空间,然后从默认的命名空间里面去取值。
下面的两个就是默认的命名空间,默认的命名空间只有bean标签
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
像下面的就是自定义的命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
在解析xml文件之前和之后都有扩展接口,下面的方法就是开始真正的解析,把委托传进来:
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
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);
}
}
BeanDefinitionParserDelegate:专门用来解析xml文件里面的bean标签的,一种是默认的命名空间的标签的解析,一种是自定义标签的解析,在默认的的命名空间里面的解析,获取所有的子元素就是所有的bean标签,还有aop,springmvc标签的,然后通过委托类来判断节点是否是默认的命名空间,parseDefaultElement:解析普通的默认的bean标签,如果不是默认的命名空间就走parseCustomElement,解析自定义的标签
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);
}
}
上面的是解析默认的命名空间的方法,有四种if-else,就是解析四种标签:例如下面的文件,import,alias,beans,bean,这里一定是同级的,有四个根,别名可以在外部引用,也可以在内部引用,如果name的值一个的话,就和bean的id一样,如果是多个的话,就称之为别名,id称之为bean的name。
<?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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="xx" class="com.weizhaoyang.spring5.App" name="app1,app2">
<property name="id" value="123"></property>
</bean>
<import resource=""></import> <!--从外部导入的xml文件-->
<alias name="" alias=""></alias><!--从外部定义的别名-->
<beans></beans><!--迭代定义bean-->
</beans>
在委托类里面是定义了bean标签的和bean标签的属性,还有子标签和子标签的属性
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
/**
* Value of a T/F attribute that represents true.
* Anything else represents false. Case seNsItive.
*/
public static final String TRUE_VALUE = "true";
public static final String FALSE_VALUE = "false";
public static final String DEFAULT_VALUE = "default";
public static final String DESCRIPTION_ELEMENT = "description";
public static final String AUTOWIRE_NO_VALUE = "no";
public static final String AUTOWIRE_BY_NAME_VALUE = "byName";
public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";
public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";
public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";
public static final String NAME_ATTRIBUTE = "name";
public static final String BEAN_ELEMENT = "bean";
public static final String META_ELEMENT = "meta";
public static final String ID_ATTRIBUTE = "id";
public static final String PARENT_ATTRIBUTE = "parent";
public static final String CLASS_ATTRIBUTE = "class";
public static final String ABSTRACT_ATTRIBUTE = "abstract";
public static final String SCOPE_ATTRIBUTE = "scope";
private static final String SINGLETON_ATTRIBUTE = "singleton";
public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
public static final String AUTOWIRE_ATTRIBUTE = "autowire";
public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";
public static final String PRIMARY_ATTRIBUTE = "primary";
public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";
public static final String INIT_METHOD_ATTRIBUTE = "init-method";
public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";
public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";
public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";
public static final String INDEX_ATTRIBUTE = "index";
public static final String TYPE_ATTRIBUTE = "type";
public static final String VALUE_TYPE_ATTRIBUTE = "value-type";
public static final String KEY_TYPE_ATTRIBUTE = "key-type";
public static final String PROPERTY_ELEMENT = "property";
public static final String REF_ATTRIBUTE = "ref";
public static final String VALUE_ATTRIBUTE = "value";
public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";
public static final String REPLACED_METHOD_ELEMENT = "replaced-method";
public static final String REPLACER_ATTRIBUTE = "replacer";
public static final String ARG_TYPE_ELEMENT = "arg-type";
public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";
public static final String REF_ELEMENT = "ref";
public static final String IDREF_ELEMENT = "idref";
public static final String BEAN_REF_ATTRIBUTE = "bean";
public static final String PARENT_REF_ATTRIBUTE = "parent";
public static final String VALUE_ELEMENT = "value";
public static final String NULL_ELEMENT = "null";
public static final String ARRAY_ELEMENT = "array";
public static final String LIST_ELEMENT = "list";
public static final String SET_ELEMENT = "set";
public static final String MAP_ELEMENT = "map";
public static final String ENTRY_ELEMENT = "entry";
public static final String KEY_ELEMENT = "key";
public static final String KEY_ATTRIBUTE = "key";
public static final String KEY_REF_ATTRIBUTE = "key-ref";
public static final String VALUE_REF_ATTRIBUTE = "value-ref";
public static final String PROPS_ELEMENT = "props";
public static final String PROP_ELEMENT = "prop";
public static final String MERGE_ATTRIBUTE = "merge";
public static final String QUALIFIER_ELEMENT = "qualifier";
public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute";
public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";
public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates";
public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";
public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";
protected final Log logger = LogFactory.getLog(getClass());
private final XmlReaderContext readerContext;
private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
private final ParseState parseState = new ParseState();
/**
* Stores all used bean names so we can enforce uniqueness on a per
* beans-element basis. Duplicate bean ids/names may not exist within the
* same level of beans element nesting, but may be duplicated across levels.
*/
private final Set<String> usedNames = new HashSet<>();
<bean id="xx" class="com.weizhaoyang.spring5.App" name="" parent="" lazy-init="default"
abstract="true" autowire-candidate="default" autowire="default" depends-on="" destroy-method=""
factory-bean="" factory-method="" init-method="" primary="true" scope="">
<property name="id" value="123"/>
bean定义对象就是对上面的属性进行get和set操作
然后开始看解析bean标签的属性:BeanDefinitionHolder:用了装饰器的模式将BeanDefinition对象封装成Bean定义持有者对象,来进行Bean定义注册的。然后通过委托类来解析bean定义的元素
processBeanDefinition(ele, delegate);
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionHolder:这个类封装了别名name,id,还有一个bean定义对象,通过这三种 元素来实现Bean注册
private final BeanDefinition beanDefinition;
private final String beanName;
@Nullable
private final String[] aliases;
如何去解析Bean
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
上面的方法是对bean标签的属性进行完整的解析,参数BeanDefinition默认是null,因为还没有完全解析,首先获取id,name,然后定义一个别名的集合,然后解析逗号,返回一个名称的数组,然后把名称添加到别名的集合中。如果没有逗号的话,就把id的值覆盖beanName
checkNameUniqueness(beanName, aliases, ele);
上面的方法检查bean名称是否是独立性,定义的id,要映射,要存在map里面,必须要map里面保证它的唯一性。
就是检验是否是已经使用的名称,如果是的话就添加到已经使用的集合里面。
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
String foundName = null;
if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
foundName = beanName;
}
if (foundName == null) {
foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
}
if (foundName != null) {
error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);
}
this.usedNames.add(beanName);
this.usedNames.addAll(aliases);
}
private final Set<String> usedNames = new HashSet<>();
解析完成之后,bean定义对象开始创建:
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
看下这个类,实现了BeanDefinition接口
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable
看下如何去解析的:this.parseState.push():标识解析前的初始状态。this.parseState.pop():
代表解析完成后的状态 这样做为了解析安全性的。方法的参数:元素,id,传一个BeanDefinition为空的对象,然后获取到class属性,再判断是否有父类,然后创建抽象的bean定义对象,然后下面是解析子标签属性的,就是每一个类里面的元素,就是解析字段的。
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
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;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
throws ClassNotFoundException {
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
上面的 方法的参数传的是className,通过Bean定义阅读工具类去创建Bean定义对象。
GenricBeanDefinition:代表通用的bean定义对象,凡是xml的基本都是通用,下面就是创建了默认的BeanClass,类路径。
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;
}
public class GenericBeanDefinition extends AbstractBeanDefinition
开始解析Bean定义的属性,把属性全部解析出来,下面的方法就是如何进行解析的
是否是单例的,是否是多例的,如果有scope的话,就set值,是否是抽象的,是否是懒加载
等等,然后进行一个一个的set方法,工厂方法再进行bean实例化的时候用。全部设置在BeanDefinition对象里面
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
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());
}
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (isDefaultValue(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if (isDefaultValue(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
bd.setInitMethodName(initMethodName);
}
else if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
}
else if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
return bd;
}
第一个目标获取到:BeanDefinition接口的实现类在解析xml文件来得到的beanDefinition对象。