<?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-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
>
<description>这个是描述</description>
<!--
<import resource=""/>
<alias name="" alias=""/>
<beans></beans>
-->
<!-- parent="user" 拷贝user对应的bean属性配置,则可以重写与user不同的属性及配置,使用相同的属性及配置创建bean对象 -->
<bean id="userSub" class="com.zghw.spring.demo.demo.User" parent="user" scope="prototype">
<property name="name" value="override"/>
<property name="soso">
<!-- merge="true" 对于引用parent,如果子bean要使用父bean的数组 集合或者map等则需要使用merge=“true”,
否则会覆盖父类数组中的全部元素 -->
<array value-type="int" merge="true">
<value>5555</value>
</array>
</property>
</bean>
<!--abstract="true" 定义为抽象的bean则不会创建该对象的实例,在创建bean之前,会检查到时抽象的就不会创建该bean实例 -->
<bean id="abstractBean" class="com.zghw.spring.demo.demo.AbstractBean" abstract="true">
<constructor-arg name="name" type="String" index="0" value="zhangsan"></constructor-arg>
<constructor-arg name="count" type="int" index="1" value="23"></constructor-arg>
</bean>
<!--depends-on="userSub,carFactory"依赖于其他bean对象,在依赖的bean一个个创建完成后
才创建该bean。依赖于多个就使用逗号分开 -->
<bean id="relationBean" class="com.zghw.spring.demo.demo.RelationBean" depends-on="userSub,carFactory" ></bean>
<!-- bean的作用范围:scope的使用 默认情况下,scope是sington即调用该对象是全局唯一 prototype每次访问都是最新的对象 -->
<!-- name作为bean名称 -->
<bean name="user1" class="com.zghw.spring.demo.demo.User" scope ="prototype">
<property name="cardID" value="4110XXXXXXXXXX"/>
<property name="name" value="zhxxxxx"/>
<property name="age" value="111"/>
</bean>
<bean id="webSite1" class="com.zghw.spring.demo.demo.WebSite">
</bean>
<bean id="webSite2" class="com.zghw.spring.demo.demo.WebSite" scope="prototype">
</bean>
<!-- 默认构造参数 -->
<bean id="webSite3" class="com.zghw.spring.demo.demo.WebSite">
</bean>
<bean id="car" class="com.zghw.spring.demo.demo.Car" scope ="prototype">
<!-- 构造器的使用
name 参数名称 | type 参数类型 | index 参数位置从0开始 | value 参数值 构造器元素下可以放集合 数组 或引用bean等
-->
<constructor-arg name="name" type="java.lang.String" index="0" value="audi"></constructor-arg>
<constructor-arg name="price" type="double" index="1" value="2456546.22"></constructor-arg>
</bean>
<!--
静态工厂方法创建实例
factory-method 静态的工厂方法名字
constructor-arg静态的工厂方法参数
-->
<bean id="carFactory" class="com.zghw.spring.demo.demo.CarFactory" factory-method="getInstance" scope ="prototype">
<constructor-arg name="factoryName" type="java.lang.String" value="static factory method"></constructor-arg>
</bean>
<!-- 动态工厂方式创建对象
factory-bean 工厂对象
factory-method 工厂方法名字
constructor-arg 工厂方法参数
-->
<bean id="carSub" class="com.zghw.spring.demo.demo.CarSub" scope ="prototype" factory-bean="carFactory"
factory-method="getCar">
<constructor-arg name="namefactory" type="java.lang.String" value="AAAAAA"></constructor-arg>
<constructor-arg name="countfactory" type="int" value="11122"></constructor-arg>
</bean>
<!--autowire属性,控制是否自动注入bean对象的字段值,默认是不自动注入
1.autowire="no",不自动注入
2.autowire="byName",根据bean的字段值名称匹配bean集合中名称相同的bean对象进行注入
3.autowire="byType" 根据bean的字段值类型匹配bean集合中类型相同的bean对象进行注入,
如果有多个相同类型,会失败,可以指定相应多个bean中一个bean为primary主选
4.autowire="constructor"
-->
<!-- init-method="init" destroy-method="destroy" 定义了bean创建前使用的方法和销毁前使用的方法 -->
<bean id="relationBean1" class="com.zghw.spring.demo.demo.RelationBean" depends-on="userSub,carFactory"
autowire="byType" init-method="init" destroy-method="destroy" scope="singleton" ></bean>
<bean id="userDependency" class="com.zghw.spring.demo.demo.User"></bean>
<!-- 给bean起别名 -->
<alias name="user1" alias="uuu"/>
<!-- 级联别名的使用 ws关联webSite1 ss又关联ws wss又关联ss -->
<alias name="webSite1" alias="ws"/>
<alias name="ws" alias="ss"/>
<alias name="ss" alias="wss"/>
<!-- primary="true" 表示如果有多个bean匹配到则使用当前的作为主bean,优先选择
默认primary=false
id作为bean名称 -->
<bean id="user" class="com.zghw.spring.demo.demo.User" primary="true">
<!-- 基本类型注入 -->
<property name="cardID" value="411024198902151655"/>
<property name="name" value="zhangsan"/>
<property name="age" value="27"/>
<property name="money" value="333333.33"></property>
<property name="isMarried" value="false"/>
<!-- 属性是一个引用,包含当前User对象 -->
<property name="userChild" ref="user1"></property>
<!-- 属性是一个bean -->
<property name="computer">
<bean id="cp" class="com.zghw.spring.demo.demo.Computer">
<property name="cs">
<!-- 属性中引用其他bean -->
<ref bean="carSub" />
<!--使用idref和上面效果一样
<idref bean="relationBean"/>
-->
</property>
<property name="cs1">
<!--区分null属性 -->
<null></null>
</property>
</bean>
</property>
<property name="arrayWebSite">
<!-- 数组类型注入 -->
<array value-type="com.zghw.spring.demo.demo.WebSite">
<!-- 内部bean,和外部的bean不冲突 -->
<bean id="webSite1" class="com.zghw.spring.demo.demo.WebSite">
</bean>
<bean id="webSite2" class="com.zghw.spring.demo.demo.WebSite">
</bean>
<bean id="webSite3" class="com.zghw.spring.demo.demo.WebSite">
</bean>
</array>
</property>
<property name="soso">
<array value-type="int">
<value>11111</value>
<value>2222</value>
<value>333</value>
</array>
</property>
<meta key="we" value="22"/>
<!-- 集合数据注入 -->
<property name="listCar">
<list value-type="com.zghw.spring.demo.demo.Car">
<ref bean="car"/>
<bean id="car" class="com.zghw.spring.demo.demo.Car">
<!-- 构造器的使用 -->
<constructor-arg name="name" type="java.lang.String" index="0" value="audi1"></constructor-arg>
<constructor-arg name="number" type="java.lang.String" index="1" value="xxxx"></constructor-arg>
<constructor-arg name="brand" type="java.lang.String" index="2" value="DsAuto"></constructor-arg>
</bean>
</list>
</property>
<property name="registedWebSite">
<!-- map注入 -->
<map key-type="java.lang.String" value-type="com.zghw.spring.demo.demo.WebSite">
<entry>
<key><value>"wwww.baidu.com"</value></key>
<ref bean="webSite1"/>
</entry>
<entry>
<key><value>"wwww.google.com"</value></key>
<ref bean="webSite2"/>
</entry>
<entry key="wwww.facebook.com" value-ref="webSite3">
</entry>
</map>
</property>
<!-- 枚举类型注入 -->
<property name="fruit" value="APPLE"></property>
<!-- 使用SPEL引用其他bean属性值或者调用方法都行作为值 给力哦 也可以使用三维运算符 ? : -->
<property name="mapProp">
<props>
<prop key="#{user1.cardID}">
"#{user1.getName()}"
</prop>
<prop key="#{user1.name}">"#{user1.getAge()}"</prop>
</props>
</property>
<!-- 使用SPEL引入静态方法返回值作为值 -->
<!-- <property name="systemProp" value="#{T(com.zghw.spring.demo.demo.User).getProperties()}"></property>
<property name="systemProp" value="#{T(java.lang.System).getProperties()}">
</property> -->
<!-- Class类型注入 -->
<property name="clazz" value="com.zghw.spring.demo.demo.User"></property>
</bean>
<!-- 枚举类型不需要
<bean id="fruit" class="com.zghw.spring.demo.demo.Fruit"></bean>
-->
<bean id="computer" class="com.zghw.spring.demo.demo.Computer"></bean>
</beans>
/**
* BeanDefinitionReader 把一个Resource资源或者一个String定位符加载成一个BeanDefinition对象
* 实现该接口可以设置不同的加载实现,及对BeanDefinition的format 当然你也不一定非要实现这个接口,可以通过其他方式加载bean
*
* 接口方法: 1.加在一个资源Resource 2.加载多个资源Resource 3.加载一个String location定位符
* 4.加载多个String location定位符 5.返回BeanDefinition注册表 6.返回资源加载器 7.返回类加载器
* 8.返回beanname生成器
*
* BeanNameGenerator 接口 BeanDefinition的name生成器 接口方法: 1.放入BeanDefinition
* 及BeanDefinitionResitory注册表 生成一个name
* DefaultBeanNameGenerator实现了BeanNameGenerator接口 1.得到beanclassname 然后
* 如果为空使用父类的classname+$child 如果父类classname为空就用工厂中bean的名称+$created
* 判断得到的最后name在注册表中的数量 最后得到BeanName#counter
*
* AbstractBeanDefinitionReader抽象类实现BeanDefinitionReader大部分工作,
* 并且实现了EnvironmentCapable运行环境属性 提供了共同的属性,比如bean工厂工作和使用的类加载器加载bean类。
* 他通过构造方法参数BeanDefinitionRegistry来创建该对象,使读到的BeanDefinition注入到注册器中
* XmlBeanDefinitionReader类继承了AbstractBeanDefinitionReader
* 它主要把工作委托给BeanDefinitionDocumentReader来工作
*
* PropertiesBeanDefinitionReader继承了AbstractBeanDefinitionReader
* 这个读取器可以读取属性格式的BeanDefinition 也可以读取map
* 然后把属性值或map循环取值匹配到BeanDefinition中,然后放入注册表中。 在spring中有很多final map
* 它们在spring容器中就像一个个数据结构一样或者说是数据库把
*
* DocumentLoader接口 xml文档加载器 策略模式加载xml文档对象
*
* 它加在xml为一个文档的方法需要三个参数
* 第一个参数 资源输入流 这个客户端给定
* 第二个参数 EntityResolver 实体解析器
* 第三个参数 errorHandler 错误处理器
* 第四个参数 验证模式 是验证DTD还是XSD
* 第五个参数 XML解析器是否应该被XML名称空间感知的
*
* 第一个参数通过包装客户端给的url成为一个inputstream
* 第二个参数是替换网络的url systemId 为本地的systemId
* spring实现EntityResolver接口有以下类:
* BeansDtdResolver :它为了转化带有.dtd的systemId,从访问网络的url转换为本地的url的dtd文件
* PluggableSchemaResolver:它为了转化带有.xsd的systemId,从访问网络的url转换为本地的url的.xsd文件
* 它把META-INF/spring.schemas循环放入map中 然后比较你定义的xsd是否在map中存在,如果存在则取出对应的url
* 把它转换为输入流放入Inputsource中
* 1.DelegatingEntityResolver 使用委托的方式,根据xml文件的systemId的后缀.dtd还是.xsd判断用
* BeansDtdResolver 还是PluggableSchemaResolver来处理。
* ResourceEntityResolver继承了DelegatingEntityResolver 主要解决好像是空systemId路径是默认当前系统的路径
* 第三个参数 :使用默认的SimpleSaxErrorHandler 就是抛异常
* 第四个参数 :验证是DTD还是XSD,默认自动验证,使用了XmlValidationModeDetector来自动验证,判断是否包含Document。
* 第五个参数 :XML解析器是否应该被XML名称空间感知的。默认设置是“假”。
* * 就是前一个是publicID,后一个是SystemId,是一一对应的
* http://www.springframework.org/schema/beans publicID
* http://www.springframework.org/schema/beans/spring-beans-2.5.xsd SystemId
*
* DefaultDocumentLoader 默认实现 DocumentLoader它使用了标准的JAXP-configured来解析XML文档
* 它设置了自动感知.xsd的文档
*
*
*################## BeanDefinitionDocumentReader ####
*BeanDefinitionDocumentReader接口从xmldocument对象中读取bean对象
* 读取的bean对象保存在了beanDefinition注册表中
* 接口方法:
* void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
* 读取Document文档注册,保存在了beanDefinition注册表中
* DefaultBeanDefinitionDocumentReader实现了BeanDefinitionDocumentReader 1.设置readerContext
2.开始document文档解析,查找根元素
3.首先使用XmlReaderContext创建BeanDefinitionParserDelegate委托对象,初始化委托对象,读取root属性,填充默认的DocumentDefaultsDefinition
1.default-lazy-init 默认为false
2.default-merge 默认为false
3.default-autowire 默认为no
4.设置default-dependency-check
5.存在就设置default-autowire-candidates
6.存在就设置default-init-method
7.存在就设置default-destroy-method
4.查询
如果root不是默认的命名空间:
则通过该root元素查找到namespaceURI,通过namespaceURI查找到NamespaceHandler,然后调用parse解析为BeanDefinition对象返回。
如果是默认的命名空间
8.存在就取profile设置环境
循环root下的子元素
如果子元素不是默认的命名空间则像上面一样处理
如果子元素是默认命名空间
<beans>下的节点:
1.import
2.alias
3.bean
4.beans 重复之前的步骤
1.import节点
resource属性,解析location有占位符时,e.g. "${user.dir}"
如果resource的资源定位正确,则reader.loadBeanDefinitions加载
2.alias节点
name属性:
alias属性:
注册器注册
3.bean元素
属性:
1.id
2.name
3.class
4.parent
开始创建AbstractBeanDefinition,仅仅设置了父类名称和class类型
5.scope
6.abstract
7.lazy-init 默认就是用root<beans>下的
8.autowire 0不自动装配 1 byname 2 bytype 3.by constructor
9.dependency-check
10.有就设置depends-on
11.autowire-candidate
12.存在就设置primary
13.有就设置init-method没有就看root是否有
14.destroy-method有就设置看root是否有
15.factory-method工厂方法
16.factory-bean
bean子节点元素
1.description
2.meta 属性:1.key 2.value 放入了BeanMetadataAttributeAccessor中 0-*
3.lookup-method 属性:1.name 2.bean 创建LookupOverride对象 0-*
4.replaced-method 属性:1.name 2.replacer 创建ReplaceOverride对象
5.arg-type 属性match
6.constructor-arg 属性1.index 2.type 3.name
7.property 属性1.name 这个复杂 有空在看
8.qualifier 属性1.type2.value 子元素:attribute属性1.key2.value
这样一个bean就组合好了返回这个BeanDefinitionHolder
如果定制的要包装bean的则包装
最后一步就是注册BeanDefinition及别名
property
属性:
name
ref | value | 元素
ref ---RuntimeBeanReference
value ---TypedStringValue
元素
1.bean ---BeanDefinitionHolder
2.ref 属性bean --RuntimeBeanReference
3.id-ref 属性bean --RuntimeBeanNameReference
4.null --TypedStringValue
5.array 属性 value-type merge ---ManagedArray
6.list 属性value-type merge ---ManagedList<Object>
7.set 属性value-type merge ---ManagedSet<Object>
8.map 属性key-type value-type merge ---ManagedMap<Object, Object>
元素: entry 属性: key key-ref value value-ref value-type
entry元素:
key 属性key-ref --TypedStringValue 或RuntimeBeanReference
value
9.props 属性 ---ManagedProperties
元素:prop 属性 key --TypedStringValue
DefaultsDefinition接口继承了BeanMetadataElement
具体实现通常是基于文档的默认值,例如在根标记级别进行指定在一个XML文档。
DocumentDefaultsDefinition类实现了DefaultsDefinition接口,它持有默认指定
<beans>基本的spring bean定义属性 比如:
default-lazy-init default-autowire
* #################### ReaderContext XmlReaderContext######################
* ReaderContext 定义读取容器,主要用于保存读取状态及资源
* ProblemReporter 用于解析document出现问题时问题反馈
* ReaderEventListener spring只提供了EmptyReaderEventListener空实现,如果需要你可以自定义
* SourceExtractor 这是个提取:解析document后返回的原生bean定义,如果你需要则可以实现这个接口,
* 放入到ReaderContext中,读取信息后就可以使用这些资源了。就像访问器一样。
* spring提供了NullSourceExtractor空实现,PassThroughSourceExtractor简单实现返回了对象资源。
* 如果需要你可以自定义
* XmlReaderContext类继承自ReaderContext
* 它还加入xml中命名空间的解析器NamespaceHandlerResolver和XmlBeanDefinitionReader实现类
*
* ####################### NamespaceHandlerResolver ####################
* NamespaceHandlerResolver接口给定一个命名空间的URL解析本地实现了NamespaceHandler的处理器
* DefaultNamespaceHandlerResolver类实现了NamespaceHandlerResolver
* 默认的会查询所有的jar包下的META-INF/spring.handlers文件,解析为map key--命名空间URL value-class类名(转换为对象判断是否是处理器实例),
* 然后使用命名空间URL可以查询里面对应的NamespaceHandler
* 当然你也可以使用DefaultNamespaceHandlerResolver的构造器DefaultNamespaceHandlerResolver(ClassLoader, String)
* 来为自己构造
*
* ####################### NamespaceHandler #####################
* NamespaceHandler接口用来处理spring的xml文件命名空间
* 比如:在xml文中引入了bean工厂不认识,也就是你定制的命名空间,在beans元素下使用了该
* 命名空间下的元素,则你需要提供一个实现了NamespaceHandler接口的处理器,来处理该
* 命名空间下的元素。
* SimpleConstructorNamespaceHandler 直接继承自 BeanDefinitionParser
* 用于解析构造器参数 这样简便的定义
* <bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>
*
* SimplePropertyNamespaceHandler 直接继承自BeanDefinitionParser
* 解析属性值 简便定义
* <bean id="rob" class="..TestBean" p:name="Rob Harrop" p:spouse-ref="sally"/>
*
* 开发人员编写自己的定制元素扩展通常不会直接实现这个接口,而是利用所提供的NamespaceHandlerSupport类。
* 接口方法:
* 1.初始化方法,用于在需要定制的NamespaceHandler实现类时进行初始化
* 2.调用parse方法解析元素为一个BeanDefinition
* 3.装饰一个节点或属性为BeanDefinitionHolder
* NamespaceHandlerSupport抽象类,使用了final map 作为注册表
* 定义了三个注册表
* 1.key-elementName(元素的名称) value -BeanDefinitionParser(命名处理器对应元素的转化器)
* 2.key-elementName(元素的名称) value -BeanDefinitionDecorator(命名处理器对应元素的包装器)
* 3.key-attrName(属性的名称) value -BeanDefinitionDecorator(命名处理器对应元素属性的包装器)
* 让实现的子类通过以下方法注入到注册表中,这个设计有点意思。
* registerBeanDefinitionParser
* registerBeanDefinitionDecorator
* registerBeanDefinitionDecoratorForAttribute
* 子类要实现初始化方法。
* 在查找处理器时,通过解析后的命名空间名称查找到对应的处理器,使用转化器进行转换为BeanDefinition
* 实现 可以参考ContextNamespaceHandler
* UtilNamespaceHandler 实现了NamespaceHandlerSupport
* 它使用初始化方法 把key “constant” "property-path" "list" "set" "map" "properties"元素
* 及内部类实现了AbstractSingleBeanDefinitionParser的对象,来注册到父类注册表中
####################### BeanDefinitionParser ##########################
* BeanDefinitionParser接口用来转换xml文件中的元素为一个BeanDefinition
*
* ############################# ProblemReporter #################
* Location在解析资源出问题时可以得到本地资源位置,
* ParseState 是一个轨迹栈,在解析深层次xml元素时,如果出错需要记录一层一层的错误记录。
* 使用ParseState把元素压入栈,用完出栈,在出现问题时,从Stack中读取统计的栈信息以树的形式。
* 元素继承ParseState的内部接口Entry
* 其中BeanEntry、ConstructorArgumentEntry、PropertyEntry、和QualiflerEntry
* 每当读取这些元素就把相应的元素入栈和出栈
* Problem 对象使用ParseState Location组合信息输出
* ProblemReporter接口接受一个Problem定义了问题的性质
* 1.致命的
* 2.错误
* 3.提醒
* FailFastProblemReporter类实现了ProblemReporter接口
* 对于致命和错误的抛出BeanDefinitionParsingException(Problem)
* 提醒的使用了日志记录
*/