关于spring:一起来读官方文档SpringIOC04

47次阅读

共计 19923 个字符,预计需要花费 50 分钟才能阅读完成。

1.4.2。依赖性和具体配置

如上一节所述,您能够将 bean 属性和结构函数参数定义为对其余托管 bean(协作者)的援用或内联定义的值。Spring 的基于 XML 的配置元数据为此目标在其 <property/> 和 <constructor-arg/> 元素中反对子元素类型。

直值(原语,字符串等)
在 value 所述的属性 <property/> 元素指定属性或结构器参数的人类可读的字符串示意。Spring 的 转换服务用于将这些值从转换 String 为属性或参数的理论类型。以下示例显示了设置的各种值:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <!-- results in a setDriverClassName(String) call -->
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
    <property name="username" value="root"/>
    <property name="password" value="misterkaoli"/>
</bean>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/mydb"
        p:username="root"
        p:password="misterkaoli"/>

</beans>

后面的 XML 更简洁。然而,拼写错误是在运行时而不是设计时发现的,除非您应用 IDE(例如 IntelliJ IDEA 或用于 Eclipse 的 Spring 工具)在创立 bean 定义时反对主动属性实现。

您还能够配置 java.util.Properties 实例,如下所示:

<bean id="mappings"
    class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="properties">
        <value>
            jdbc.driver.className=com.mysql.jdbc.Driver
            jdbc.url=jdbc:mysql://localhost:3306/mydb
        </value>
    </property>
</bean>

Spring 容器将 <value></value> 元素中的文本转换为 java.util。属性实例,通过应用 JavaBeans 的 PropertyEditor 机制。这是一个很好的快捷方式,也是 Spring 团队偏爱应用嵌套的 <value></value> 元素而不是 value 属性款式的几个中央之一。

idref 元素

所述 idref 元件是一个防错办法,次要通过将该容器中的另一个 bean 的 id(将 id 作为一个字符串值传递 - 而不是援用)传递给 <constructor-arg/> 或 <property/> 标签。

以下示例显示了如何应用它:

<bean id="theTargetBean" class="..."/>

<bean id="theClientBean" class="...">
    <property name="targetName">
        // 此处将 theTargetBean 作为字符串传递给 theClientBean 的 targetName 属性
        // 而不是将 theTargetName 这个 bean 的实例传递给 targetName 属性
        <idref bean="theTargetBean"/>
    </property>
</bean>

后面的 bean 定义代码段(在运行时)与以下代码段齐全等效:
idref 等价的是 value 标签 而不是 ref 标签

<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
    <property name="targetName" value="theTargetBean"/>
</bean>
元素 的 local 属性在 idref4.0 Bean XSD 中不再受反对,因为它不再提供惯例 bean 援用上的值。降级到 4.0 模式时,将现有 idref local 援用更改为 idref bean。

idref 用法 能够校验传入的作为 bean 的 id 会被用来校验以后 id 的 bean 存不存在

<idref></idref> 元素罕用的地位 (至多在 spring2.0 之前的版本中) 是在 ProxyFactoryBean bean 定义中的 AOP 拦截器配置中。在指定拦截器名称时应用 <idref></idref> 元素能够避免拼写错误。
ref 对其余 Bean 的援用

ref 元素是 <constructor-arg> 或 </property> 定义元素中的最初一个元素。在这里,您将 bean 的指定属性的值设置为对容器治理的另一个 bean 的援用。被援用的 bean 是要设置其属性的 bean 的依赖项,并且在设置属性之前依据须要初始化它(如果协作者是单例 bean,它可能曾经被容器初始化了)。所有援用最终都是对另一个对象的援用。范畴和验证取决于是否通过 bean 或父属性指定其余对象的 ID 或名称。

通过 <ref></ref> 标记的 bean 属性指定指标 bean 是最通用的模式,它容许创立对同一容器或父容器中任何 bean 的援用,而不论它是否在同一 XML 文件中。bean 属性的值能够与指标 bean 的 id 属性雷同,或者与指标 bean 的 name 属性中的一个值雷同。上面的例子展现了如何应用 ref 元素:

//someBean 能够是 bean 的 id  也能够是 bean 的 name
<ref bean="someBean"/>

ref 元素的 local 属性在 ref4.0 Bean XSD 中不再受反对,
因为它不再提供惯例 bean 援用上的值。降级到 4.0 模式时,将现有 ref local 援用更改 ref bean 为。

汇合

<list></list>、<set></set>、<map></map>、</props> 元素别离设置 Java 汇合类型 list、set、map、properties 的属性和参数。上面的例子展现了如何应用它们:

<bean id="moreComplexObject" class="example.ComplexObject">
    <!-- results in a setAdminEmails(java.util.Properties) call -->
    <property name="adminEmails">
        <props>
            <prop key="administrator">administrator@example.org</prop>
            <prop key="support">support@example.org</prop>
            <prop key="development">development@example.org</prop>
        </props>
    </property>
    <!-- results in a setSomeList(java.util.List) call -->
    <property name="someList">
        <list>
            <value>a list element followed by a reference</value>
            <ref bean="myDataSource" />
        </list>
    </property>
    <!-- results in a setSomeMap(java.util.Map) call -->
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>
    <!-- results in a setSomeSet(java.util.Set) call -->
    <property name="someSet">
        <set>
            <value>just some string</value>
            <ref bean="myDataSource" />
        </set>
    </property>
</bean>

map 的 key 或 value, 或 set 的 value 也能够是以下任意元素:

bean | ref | idref | list | set | map | props | value | null
汇合合并

Spring 容器还反对合并汇合。利用开发者能够定义一个父元素 <list></list>、<map></map>、<set></set> 或 </props>,让子元素 <list></list>、<map></map>、<set></set> 或 </props> 继承和笼罩父元素汇合的值。也就是说,子集合的值是合并父汇合和子集合的元素的后果,子集合元素笼罩父汇合中指定的值。

对于合并的这一节探讨父 - 子 bean 机制。不相熟父 bean 和子 bean 定义的读者可能心愿在持续之前浏览相干局部。

上面的例子演示了汇合合并:

<beans>
    <bean id="parent" abstract="true" class="example.ComplexObject">
        <property name="adminEmails">
            <props>
                <prop key="administrator">administrator@example.com</prop>
                <prop key="support">support@example.com</prop>
            </props>
        </property>
    </bean>
    <bean id="child" parent="parent">
        <property name="adminEmails">
            <!-- the merge is specified on the child collection definition -->
            <props merge="true">
                <prop key="sales">sales@example.com</prop>
                <prop key="support">support@example.co.uk</prop>
            </props>
        </property>
    </bean>
<beans>

留神在子 bean 定义的 adminEmails 属性的 </props> 元素上应用了 merge=true 属性。当容器解析并实例化子 bean 时,生成的实例具备一个 adminEmails 属性汇合,该汇合蕴含将子 bean 的 adminEmails 汇合与父 bean 的 adminEmails 汇合合并的后果。上面的清单显示了后果:

administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk

子属性汇合的值集继承父属性 </props> 中的所有属性元素,子属性反对值的值笼罩父属性汇合中的值。

这种合并行为相似地利用于 <list></list>、<map></map> 和 <set></set> 汇合类型。在 <list></list> 元素的特定状况下,将保护与列表汇合类型 (即值的有序汇合的概念) 相关联的语义。父元素的值位于所有子元素列表的值之前。对于 Map、Set 和 Properties 汇合类型,不存在排序。因而,对于位于容器外部应用的关联映射、汇合和属性实现类型下的汇合类型,排序语义不起作用。

汇合合并的局限性

您不能合并不同的汇合类型(例如 Map 和 List)。如果尝试这样做,将会抛出异样。
该 merge 属性必须在上面的继承的子集合定义中指定。
merge 在父汇合定义上指定属性是多余的,不会导致所需的合并。

强类型汇合

随着 Java 5 中泛型类型的引入,您能够应用强类型汇合。也就是说,能够申明一个 Collection 类型,使其仅蕴含(例如)String 元素。如果应用 Spring 将强类型依赖注入 Collection 到 Bean 中,则能够利用 Spring 的类型转换反对,以便在将强类型 Collection 实例的元素增加到之前将其转换为适当的类型 Collection。以下 Java 类和 bean 定义显示了如何执行此操作:

public class SomeClass {
    private Map<String, Float> accounts;
    public void setAccounts(Map<String, Float> accounts) {this.accounts = accounts;}
}
<beans>
    <bean id="something" class="x.y.SomeClass">
        <property name="accounts">
            <map>
                <entry key="one" value="9.99"/>
                <entry key="two" value="2.75"/>
                <entry key="six" value="3.99"/>
            </map>
        </property>
    </bean>
</beans>

当筹备注入 bean 的 accounts 属性时,能够通过反射取得 something 无关强类型的元素类型的泛型信息 Map<String,Float>。因而,Spring 的类型转换根底构造将各种值元素辨认为 type Float,并将字符串值(9.99, 2.75 和 3.99)转换为理论 Float 类型。
空字符串值和空字符串值

Spring 将属性之类的空参数视为空字符串。以下基于 xml 的配置元数据片段将 email 属性设置为空字符串值(“”)。

<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>

后面的示例等效于以下 Java 代码:

exampleBean.setEmail("");

该 <null/> 元素解决 null 的值。以下清单显示了一个示例:

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>

后面的配置等效于上面的 Java 代码:

exampleBean.setEmail(null);
带有 p - 名称空间的 XML 快捷方式

p- 名称空间容许您应用 bean 元素的属性 (而不是嵌套的 </property> 元素) 来形容与之单干的 bean 的属性值,或者两者都应用。

Spring 反对带有名称空间的可扩大配置格局,名称空间基于 XML 模式定义。本章中探讨的 bean 配置格局是在 XML 模式文档中定义的。然而,p- 名称空间没有在 XSD 文件中定义,只存在于 Spring 的外围中。

上面的示例显示了两个解析为雷同后果的 XML 片段(第一个应用规范 XML 格局,第二个应用 p - 名称空间):

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p" <!-- 这一行是要的 -->
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="classic" class="com.example.ExampleBean">
        <property name="email" value="someone@somewhere.com"/>
    </bean>

    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="someone@somewhere.com"/>
</beans>

该示例显示了 email 在 bean 定义中调用的 p -namespace 中的属性。这通知 Spring 蕴含一个属性申明。如前所述,p 名称空间没有架构定义,因而能够将属性名称设置为属性名称。

下一个示例包含另外两个 bean 定义,它们都援用了另一个 bean:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="john-classic" class="com.example.Person">
        <property name="name" value="John Doe"/>
        <property name="spouse" ref="jane"/>
    </bean>

    <bean name="john-modern"
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>

    <bean name="jane" class="com.example.Person">
        <property name="name" value="Jane Doe"/>
    </bean>
</beans>

这个示例不仅蕴含一个应用 p - 名称空间的属性值,而且还应用一种非凡格局来申明属性援用。第一个 bean 定义应用 </property> 来创立一个从 bean john 到 bean jane 的援用,第二个 bean 定义应用 p:spouse-ref=”jane” 作为一个属性来实现完全相同的工作。在本例中,spouse 是属性名,而 -ref 局部表明这不是一个间接的值,而是对另一个 bean 的援用。

    p- 名称空间不如规范 XML 格局灵便。例如,申明属性援用的格局与以 Ref 结尾的属性抵触,而规范 XML 格局不会。咱们建议您认真抉择您的办法,并与您的团队成员沟通,以防止同时生成应用所有三种办法的 XML 文档。The p-namespace is not as flexible as the standard XML format. 
    For example, the format for declaring property references clashes 
    with properties that end in Ref,whereas the standard XML format does not.
    We recommend that you choose your approach carefully 
    and communicate this to your team members to avoid producing XML documents
    that use all three approaches at the same time.
    
    这段没看懂,这里测试了以 Ref 结尾的属性也是能够用 p:xxxRef-ref
具备 c -namespace 的 XML 快捷方式

与应用 p -namespace 的 XML 快捷方式相似,Spring 3.1 中引入的 c -namespace 容许应用内联属性配置结构函数参数,而不是嵌套结构函数参数元素。说白了就是 p -namespace 替换 property,c-namespace 替换 constructor-arg

上面的示例应用 c: 名称空间执行与 基于构造函数的依赖注入雷同的操作:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c" <!-- 新增该条 -->
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="beanTwo" class="x.y.ThingTwo"/>
    <bean id="beanThree" class="x.y.ThingThree"/>

    <!-- 带有可选参数名称的传统申明 -->
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg name="thingTwo" ref="beanTwo"/>
        <constructor-arg name="thingThree" ref="beanThree"/>
        <constructor-arg name="email" value="something@somewhere.com"/>
    </bean>

    <!-- 带有参数名称的 c - 名称空间申明 -->
    <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
        c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>

</beans>

对于结构函数参数名不可用的常见状况(通常是在编译字节码时没有调试信息的状况下),能够应用回退到参数索引,如下所示:

<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
    c:_2="something@somewhere.com"/>
复合属性名称 一个 bean 中嵌套另外一个 bean 并须要给外部的 bean 赋值

在设置 bean 属性时,能够应用复合或嵌套属性名,只有门路的所有组件 (最终属性名除外) 都不为空。思考上面的 bean 定义:

<bean id="something" class="things.ThingOne">
    <property name="fred.bob.sammy" value="123" />
</bean>


所述 something bean 具备 fred 属性,该属性具备 bob 属性,bob 属性具备 sammy 个性,并且最终 sammy 属性被设置为值 123。something bean 的 fred 属性和 fred 的 bob 属性在结构 bean 之后肯定不能为 null。否则,将会引发 NullPointerException。
1.4.3。应用 depends-on

如果一个 bean 是另一个 bean 的依赖项,则通常意味着将一个 bean 设置为另一个 bean 的属性。通常,您能够应用基于 XML 的配置元数据中的 <ref/> 元素来实现此操作。
然而,有时 bean 之间的依赖性不太间接。一个示例是何时须要触发类中的动态初始值设定项,例如用于数据库驱动程序注册。该 depends-on 属性能够在初始化应用此元素的 bean 之前显式强制初始化一个或多个 bean。以下示例应用该 depends-on 属性示意对单个 bean 的依赖关系:

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />

要表白对多个 bean 的依赖性,就须要用逗号隔开多个名称

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
    <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
depends-on 属既能够指定初始化工夫依赖项,也能够指定对应的销毁工夫依赖项(仅在单例 bean 中)。被依赖的 bean 会晚于依赖 bean 之后销毁

<bean id="serviceOneRef" name="serviceOneName" class="org.springframework.example.service.ServiceOne"
          destroy-method="destroyed"/>
    public void destroyed(){System.out.println("ServiceOne destroy");
    }
    
<bean id="serviceTwo" class="org.springframework.example.service.ServiceTwo"
          p:name="asdfasdf"  depends-on="serviceOneRef"
          destroy-method="destroyed" />
    public void destroyed(){System.out.println("serviceTwo destroy");
    }
          
console:serviceTwo destroy
    ServiceOne destroy
1.4.4。懒加载 bean

默认状况下,作为初始化过程的一部分,ApplicationContext 实现会急迫地创立和配置所有的单例 bean。通常,这种预实例化是可取的,因为配置或周围环境中的谬误是立刻发现的,而不是几小时甚至几天后发现的。
当这种行为不适合时,您能够通过将 bean 定义标记为提早初始化来避免单例 bean 的预实例化。提早初始化的 bean 通知 IoC 容器在第一次申请 bean 实例时 (而不是在启动时) 创立 bean 实例。

在 XML 中,这种行为是由 <bean></bean> 元素的 lazy-init 属性管制的,如上面的例子所示:

<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>

当 ApplicationContext 应用后面的配置时,
lazy bean 不会在 ApplicationContext 启动时急迫地预实例化,
not.lazy bean 则会被急迫地预实例化。

然而,当懒加载的 bean 是非懒加载的单例 bean 的依赖项时,ApplicationContext 在启动时则会创立懒加载的 bean,因为它必须满足单例的依赖项。

您还能够通过应用 <beans></beans> 元素的 default-lazy-init 批量设置懒加载 bean

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>
1.4.5。主动拆卸

Spring 容器能够主动拆卸合作 bean 之间的关系。
主动拆卸具备以下长处:

  • 主动拆卸能够大大减少指定属性或结构函数参数的须要。
  • 随着对象的倒退,主动拆卸能够更新配置。例如,如果您须要向类中增加一个依赖项,则无需批改配置即可主动满足该依赖项。因而,主动拆卸在开发过程中特地有用,而不用放心当代码库变得更稳固时切换到显式接线的抉择。

应用基于 XML 的配置元数据时,能够应用元素的 autowire 属性为 bean 定义指定主动拆卸模式 <bean/>。主动拆卸性能具备四种模式。您能够为每个 bean 指定主动拆卸,因而能够抉择要主动拆卸的拆卸。下表形容了四种主动拆卸模式:

模式 解释
no (默认)没有主动拆卸。想要援用其余的 Bean 必须由 ref 元素定义。
对于较大的部署,不倡议更改默认设置,
因为显式地指定须要援用的 bean 能够提供更好的管制和清晰度。
在某种程度上,它记录了零碎的构造。
byName 按属性名称主动拆卸。
Spring 寻找与须要主动实现的属性同名的 bean。
例如,如果一个 bean 定义 autowire 模式设置为 byName,
并且它蕴含一个 master 属性 (也就是说,它有一个 setMaster(..) 办法)
,那么 Spring 将查找一个名为 master 的 bean 定义,
并应用它来设置该属性。
次要还是依据 set 办法来确定属性名,如果你有 master 属性,
然而你的 set 办法是 setMyMaster(..),
那么 Spring 会查找名为 myMaster 的 bean 而不是名为 master 的 bean
byType 实用于 set 办法的入参类型,
如果容器中恰好存在该属性类型的一个 bean,则容许该属性主动注入。
如果存在多个,就会抛出一个致命异样,
这表明您不能对该 bean 应用 byType 主动拆卸。
如果没有匹配的 bean,则什么也不会产生(没有设置属性)。
constructor 相似于 byType,但实用于结构函数参数。
如果容器中没有结构函数参数类型的确切 bean,就会引发致命谬误。

应用 byType 或 constructor 主动拆卸模式,您能够主动注入 arrays 和 collections 类型。在这种状况下,将提供容器中与冀望类型匹配的所有主动拆卸候选,以满足相关性。
如果接管的 map 的 key 值类型为 String,那么你也能够让 Spring 主动拆卸 Map 类型的值,并且 Map 实例的 key 值为相应的 bean 名称。

    @Autowired
    private List<CusService> serviceLists;

    @Autowired
    private Map<String,CusService> cusServiceMap;
主动接线的局限性和毛病

主动拆卸在我的项目中统一应用时工作得最好。如果主动拆卸没有被广泛应用,那么应用它来连贯一个或两个 bean 定义可能会使局部开发人员感到困惑。

思考主动拆卸的局限性和毛病:

  • 属性和结构参数设置中的显式依赖关系总是笼罩主动拆卸。您不能主动连贯简略属性,如 primitives(boolean,int,long 等)、String 和 classes(以及此类简略属性的数组)。这种限度被刻意设计的。
  • 主动拆卸 bean 不如显式指定 bean 准确。不过,正如后面的表中所指出的,Spring 曾经尽可能防止产生意外后果。Spring 治理的对象之间的关系不再被明确地记录。
  • 对于能从 Spring 容器生成文档的工具来说生成连贯信息是不可能的了。
  • 主动注入依赖项时如果有多个能够匹配的选项,如果注入类型是数组、汇合或映射实例,这不是问题。然而,对于冀望应用单个值的依赖项,这种模糊性不能任意解决。如果没有可用的惟一 bean 定义,则抛出异样。

在后一种状况下,您有几个选项:

  • 放弃主动拆卸,反对显式布线。
  • 通过将 bean 定义的 autowire-candidate 设置为 false 来防止主动拆卸。
  • 通过将单个 bean 定义的 <bean></bean> 元素的 primary 设置为 true,将其指定为主候选 bean 定义。
  • 应用基于正文的配置实现更细粒度的管制,1.9 大节会专门解说注解应用。
1. 放弃主动拆卸,改成指定 bean 注入 @Qualifier 或者 xml 的 ref 属性都能够
2.
        <bean id="serviceOne"  class="org.springframework.example.service.ServiceOne" />
        <bean id="serviceTwo"  class="org.springframework.example.service.ServiceTwo" />
    两个 bean 都继承同一个接口 CusService,如果有主动拆卸如下
        @Autowired
        private CusService service;
    则启动时候会报错
    如果给 serviceOne 减少属性 autowire-candidate="false" 
        <bean id="serviceOne"  class="org.springframework.example.service.ServiceOne" autowire-candidate="false" />
    则所有的主动拆卸 CusService 的接口都会优先拆卸 serviceTwo
3. 状况同 2 还能够将 serviceTwo 减少 primary="true" 
        <bean id="serviceTwo"  class="org.springframework.example.service.ServiceTwo" primary="true" />
从主动拆卸中排除 Bean

在每个 bean 的根底上,您能够从主动拆卸中排除一个 bean。在 Spring 的 XML 格局中,将 <bean></bean> 元素的 autowire-candidate 设置为 false。容器使得特定的 bean 定义对主动拆卸基础设施不可用(包含正文格调配置,如 @Autowired)。

autowire-candidate 属性被设计为只影响基于类型的主动拆卸。它不影响按名称的显式援用,即便指定的 bean 没有标记为主动拆卸候选,也会解析显式援用。因而,如果名称匹配,按名称主动拆卸依然会注入一个 bean。

<beans></beans> 元素在其 default-autowire-candidates 属性接管一个 patterns 字符串,意思是依据 patterns 字符串匹配到的所有合格的 beanName 的 autowire-candidates 会被设置为 true,不合格的会被设置为 false
patterns 字符串承受一个或多个匹配模式,多个 patterns 字符串之间能够用逗号隔开。例如 (Repository,Service,*Dao) 这种组合模式

bean 自身的 autowire-candidates 属性优于 <beans> 的 default-autowire-candidates 属性失效

这些技术对于那些您永远不心愿通过主动拆卸被注入到其余 bean 中的 bean 十分有用。这并不意味着被排除的 bean 自身不能应用主动拆卸进行配置。相同,该 bean 自身仅仅是不作为其余 bean 的主动连贯候选对象。

        public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";

        // 获取 autowire-candidate  这个值默认就是 true
        String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
        // 判断 是不是定义的以后 bean 是不是 default
        if (isDefaultValue(autowireCandidate)) {
            // 如果是 default 
            // 查找以后 bean 所在 beans 的 default-autowire-candidates 属性 找到配置的 patterns 表达式
            // 如果表达式为空 就不解决 setAutowireCandidate 属性值 这样该属性仍旧是 true
            String candidatePattern = this.defaults.getAutowireCandidates();
            if (candidatePattern != null) {
                // 表达式不为空 判断以后 beanName 是否在表达式范畴内
                // 在范畴内就 setAutowireCandidate 设置为 true
                // 否则设置为 false
                String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
            }
        }
        else {
        // 如果 autowireCandidate 不是 default 是 true 那就设置为 true 
        // 是 false 那就设置为 false
            bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
        }
1.4.6。办法注入

在大多数利用场景中,容器中的大多数 bean 是 singletons。
当单例 Bean 须要与另一个单例 Bean 合作或非单例 Bean 须要与另一个非单例 Bean 合作时,通常能够通过将一个 Bean 定义为另一个 Bean 的属性来解决依赖性,生命周期雷同的类相互注入时没有问题。
当 bean 的生命周期不同时会呈现问题。假如单例 bean A 须要应用非单例(原型)bean B,兴许在 A 的每个办法调用上都应用。容器仅创立一次单例 bean A,因而只有一次机会来设置属性。每次须要一个容器时,容器都无奈为 bean A 提供一个新的 bean B 实例。

一个解决方案是放弃某些管制反转。您能够通过实现接口 ApplicationContextAware,并使每次容器 A 都须要容器 B 的调用来申请(通常是新的)bean B 实例,从而使 bean A 晓得容器。以下示例显示了此办法:ApplicationContextAware.getBean(“B”)

// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;

// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class CommandManager implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Object process(Map commandState) {
        // grab a new instance of the appropriate Command
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();}

    protected Command createCommand() {
        // notice the Spring API dependency!
        return this.applicationContext.getBean("command", Command.class);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

后面的内容是不现实的,因为业务代码晓得并耦合到 Spring 框架。办法注入是 Spring IoC 容器的一项高级性能,使您能够洁净地解决此用例。

您能够在此博客条目中理解无关办法注入动机的更多信息。

Lookup Method 注入

Lookup Method 注入是指容器笼罩容器治理 bean 上的办法并返回容器中另一个已命名 bean 的查找后果的能力。查找通常波及原型 bean,如上一节所述的场景。Spring 框架通过应用来自 CGLIB 库的字节码生成动静生成笼罩该办法的子类来实现这种办法注入。

  • 要使这个动静子类工作,Spring bean 容器子类的类不能是 final,要笼罩的办法也不能是 final。
  • 单元测试具备形象办法的类须要您本人创立类的子类,并提供形象办法的存根实现。
  • 具体的办法对于组件扫描也是必要的,这须要具体的类来拾取。
  • 另一个要害的限度是,Lookup Method 不能与工厂办法一起工作,特地是与配置类中的 @Bean 办法一起工作,因为在这种状况下,容器不负责创立实例,因而不能动静地创立运行时生成的子类。

对于 CommandManager 后面的代码片段中的类,Spring 容器动静地笼罩该 createCommand() 办法的实现。该 CommandManager 班没有任何 Spring 的依赖,如下所示:

package fiona.apple;
public abstract class CommandManager {public Object process(Object commandState) {
        // 获取适当的命令接口的新实例
        Command command = createCommand();
        // 在 (心愿是全新的) 命令实例上设置状态
        command.setState(commandState);
        return command.execute();}

    // 实现类在哪呢???protected abstract Command createCommand();}

在蕴含要注入的办法的客户端类中(本例为 CommandManager),要注入的办法须要以下模式的签名:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

如果办法为 abstract,则动静生成的子类将实现该办法。否则,动静生成的子类将笼罩原始类中定义的具体方法。思考以下示例:

<!-- 作为原型部署的有状态 bean(非单例)-->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
    <!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor 应用 statefulCommandHelper-->
<bean id="commandManager" class="fiona.apple.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>

标识为 commandManager 的 bean 在须要 myCommand bean 的新实例时调用它本人的 createCommand()办法。是否要将 myCommand bean 部署为原型,必须认真确认本人的需要。如果是单例,则每次都返回雷同的 myCommand bean 实例。

或者,在基于正文的组件模型中,您能够通过 @Lookup 正文申明一个查找办法,如上面的示例所示:

public abstract class CommandManager {public Object process(Object commandState) {Command command = createCommand();
        command.setState(commandState);
        return command.execute();}

    @Lookup("myCommand")
    protected abstract Command createCommand();}

或者,更习用的是,您能够依赖于指标 bean 依据查找办法的申明的返回类型来解析:

public abstract class CommandManager {public Object process(Object commandState) {MyCommand command = createCommand();
        command.setState(commandState);
        return command.execute();}

    @Lookup
    protected abstract MyCommand createCommand();}

请留神,您通常应该应用具体的存根实现来申明这种带正文的查找办法,以便它们与 Spring 的组件扫描规定兼容,其中抽象类在默认状况下会被疏忽。此限度不适用于显式注册或显式导入的 bean 类。

拜访范畴不同的指标 bean 的另一种办法是 ObjectFactory/ Provider 注入点(https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other-injection)。您可能还会发现 ServiceLocatorFactoryBean(在 org.springframework.beans.factory.config 包装中)有用。
任意办法替换

办法替换注入的模式是用另一个办法实现替换托管 bean 中的任意办法的能力。这个非常不罕用,您能够跳过本节的其余部分,等到您真正须要此性能再来看。

对于基于 xml 的配置元数据,您能够应用 replaced-method 元素将一个已部署 bean 的现有办法实现替换为另一个办法实现。思考上面的类,它有一个名为 computeValue 的办法,咱们想要笼罩它:

public class MyValueCalculator {public String computeValue(String input) {// some real code...}
}

实现该 org.springframework.beans.factory.support.MethodReplacer 接口的类提供了新的办法定义,如以下示例所示:

/**
 * 用于笼罩现有的 computeValue(String input)
 * 实现在 MyValueCalculator
 */
public class ReplacementComputeValue implements MethodReplacer {public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // 获取输出值,应用它,并返回计算结果
        String input = (String) args[0];
        ...
        return ...;
    }
}

用于部署原始类并指定办法笼罩的 Bean 定义相似于以下示例:

<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean>

<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>

您能够在 <replaced-method/> 元素内应用一个或多个 <arg-type/> 元素 来批示要笼罩的办法的办法签名。仅当办法重载且类中存在多个变体时,才须要对参数签名。为了不便起见,参数的类型字符串能够是齐全限定类型名称的子字符串。
例如,以下所有都是 java.lang.String 匹配项:

java.lang.String
String
Str

因为参数的数量通常足以辨别每个可能的抉择,所以通过让您仅键入与参数类型匹配的最短字符串,此快捷方式能够节俭很多输出

正文完
 0