您的位置:首页 > 编程语言 > Java开发

Spring核心Bean工厂装配__Spring学习笔记

2008-05-28 06:03 579 查看
在Spring 中最核心的组件是bean工厂,它提供了基本的反向控制和依赖注入的能力。Spring 是一种无侵入性的框架,被bean工厂管理的组件无须知道spring的存在。bean工厂负责打造bean,并注射它们之间的依赖。这些bean会彼此协作。 spring中最基本的BeanFactory接口org.springframework.beans.factory.BeanFactory ,它提供一些工厂的基本方法。

package org.springframework.beans.factory;
import org.springframework.beans.BeansFaException;

public interface BeanFacotory
package com.cao.spring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.Resource;
import org.springframework.beans.factory.xml.XmlBeanFactory;
<bean id="setterBean" class="com.cao.SetterBean" >
<property name="beanOne">
<ref bean="anotherBean"/>
</property>
<property name="beanTwo">
<ref bean="yetAntherBean"/>
</property>
<property name="integerProperty">
<value>1<value>
</property>
</bean>
<bean id="anotherBean" class="com.cao.AnotherBean" />
<bean id="yetAntherBean" class="com.cao.YetAnotherBean" />

//实现的类。
package com.cao.spring;

<beans>
<bean id="constructBean" class="com.cao.spring.ConstructBean">
<constructor-arg>
<ref bean="beanOne"/>
</constructor-arg>
<constructor-arg>
<ref bean="beanTwo"/>
</constructor-arg>

<constructor-arg index="2">
<value type="int">1</value>
</constructor-arg>
</bean>

<bean id="beanOne" class="com.cao.spring.AnotherBean"/>
<bean id="beanTwo" class="com.cao.spring.YetAnotherBean"/>
</beans>

//实现类
package com.cao.spring;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

<beans>
<bean id="diFactory" class="com.cao.spring.DIFactory"/>
<!--在实例工厂方法中通过factory-bean来指定包含该方法的工厂类。factory-method指定创建的方法-->
<bean id="product" factory-bean="diFactory" factory-method="make">
<constructor-arg>
<ref bean="beanOne"/>
</constructor-arg>
<constructor-arg>
<ref bean="beanTwo"/>
</constructor-arg>
<constructor-arg>
<value>1</value>
</constructor-arg>
</bean>

<bean id="beanOne" class="com.cao.spring.AnotherBean"/>
<bean id="beanTwo" class="com.cao.spring.YetAnotherBean"/>
<!--静态工厂方法中factory-method指定创建的方法(静态) 包含改工厂的类为这个工厂本身-->
<bean id="productStatic" class="com.cao.spring.DIFactory" factory-method="create">
<constructor-arg>
<ref bean="beanOne"/>
</constructor-arg>
<constructor-arg>
<ref bean="beanTwo"/>
</constructor-arg>
<constructor-arg>
<value>1</value>
</constructor-arg>
</bean>
</beans>

Spring自动装配(autowiring)
1, no 不进行自动装配,这是spring的默认配置。
2,byName 通过属性名进行自动装配。Spring 查找待装配的bean属性同名的bean。
(测试:发现当找不到匹配的时候取其默认值null / 0 引用类型为null ,基本数据类型为0 )
3,byType Spring 查找待装配的bean 同类型的bean,不过如果找到多于一个一上的bean 是会抛异常的。
(测试:哪怕是同一个bean对应不同的id也会报错,如果不足是不会报错只是为空。如果设置了 dependency-check="objects" 不足也会报错)
4,constructor 类似于 byType 。匹配构造子参数,而非属性。
5,autodetect 让spring 自动选择construtor 或 byType如果找到的是一个默认构造方法则使用byType

依赖检查:
模式: 说明
none 不进行依赖检查
simple 对基本类型和集合进行依赖检查
objects 对协作者(你所注入的哪个类)进行依赖检查
all 对协作者,基本类型和集合都进行检查

使用collection(集合) 元素定义集合。

<beans>
<bean id="complext" class="com.cao.spring.ComplexBean">
<!--java.util.Properties-->
<property name="people">
<props>
<prop key="name">Spirti.J</prop>
<prop key="age">25</prop>
</props>
</property>

<property name="comeList">
<list>
<!-- 配置文件中的<value>之间也不可以带空格spring不处理空格 -->
<value>list中的第一个元素,下一个元素是其他bean的引用</value>
<ref bean="anotherBean"/>
</list>
</property>

<property name="someMap">
<map>
<!-- 测试:当出现同名的key 时 后面的会覆盖前面的 -->
<entry key="key-String" value="我是字符串甲"/>
<entry>
<key><value>key-String</value></key>
<value>我是字符串乙</value>
</entry>

<!-- 两种写法是等效的 -->
<entry key="key-ref" value-ref="anotherBean"></entry>

<entry>
<key><value>key-ref</value></key>
<!-- ref在这里提供一个协作者相当于一个<value>作为一个单独的元素 -->
<ref bean="anotherBean"/>
</entry>
</map>
</property>

<property name="someSet">
<set>
<!-- 测试:当set转化为数组时,与配置的顺序有关系 -->
<value>我是字符串丙</value>
<ref bean="anotherBean"/>
</set>

</property>

</bean>
<bean id="anotherBean" class="com.cao.spring.AnotherBean"/>
</beans>

通过嵌套bean来定义内部bean
内部bean不需要任何id 或则 singleton 标记,它是一种匿名的内部原形,它的实例仅供外部类使用。

<bean id="outerBean" class="com.cao.spring.OuterBean">
<property name="target">
<!-- 内部bean是不需要id的.测试:加了也不报错.但无意义 -->
<bean class="com.cao.spring.ComplexBean">
<property name="people">
<props>
<prop key="name">Spirit.J</prop>
<prop key="age">25</prop>
</props>
</property>
</bean>
</property>

</bean>

方法注入
为什么需要方法注入?
假设一个singleton beanA 和一个non-singleton beanB 那么容器仅仅会对beanA实例化一次也就就只有一次机会去设置它的属性。所以无法每次为beanA
提供一个新的beanB的实例。因为beanB 是BeanA的属性。

使用lookup 方法注入,lookup 方法能够在运行时重写bean的抽象或具体方法,返回或创建容器中其他bean的实例。被创建的通常是一个non-singleton bean
但也可以是 singleton 的。(spring 通过CGLIB来实现这种注入)

<beans>
<bean id="anotherBean" class="com.cao.spring.AnotherBean" singleton="false"/>
<bean id="myBean" class="com.cao.spring.MyLookUpBean">
<lookup-method name="newAnotherBean" bean="anotherBean"/>
</bean>
</beans>

MyLookUpBean中 有方法
protected AnotherBean newAnotherBean(){
return null;
}
在MyLookUpBean调用这个方法时候。spring 都会重写这个方法并返回一个 AnotherBean 的实例。

替换任意方法。
通过replace-method元素替换以存在的方法实现。
使用方法替换需要实现的接口 org.springfarmework.beans.factory.support.MethodReplacer接口。

<bean id="myReplaceBean" class="com.cao.spring.MyValueCalculator">
<replaced-method name="computeValue" replacer="aaa">
<arg-type>String</arg-type>

</replaced-method>
</bean>
<bean id="aaa" class="com.cao.spring.ReplacementComputeValue"/>

原本MyValueCalculator类中有一个方法。
public String computeValue(String input){
System.out.println("原始的计算");
return "";
}

结果在运行时被 ReplacementComputeValue 类中的实现所替换。改类实现了MethodReplacer接口。覆盖该接口中的 reimplement方法的实现作为
computeValue 实现的替换。<replaced-method>中的name 指定了要替换的方法。 replacer属性指定实现MethodReplacer接口的类。

Bean的原生属性
Spring 提供了一些生命周期的标记接口,包括InitializingBean 和DisposableBean. 他们可以改变bean的行为. 使得bean在初始化和析构时执行特定的处理
InitializingBean 中有 afterpropertiesSet() 方法 一个bean 实现了InitializingBean接口后并实现 这个方法可以用来完成初始化工作。但这样做有一个
弊端,就是 bean 与 spring 框架 发生了耦合。 更好的方法是通过在配置文件中用 init-method 属性来指定一个方法来完成初始化工作。
DisposableBean 和 destroy-method 属性的用法 类似 初始化。

Bean先完成属性的注入 然后初始化 当工厂销毁的时候。再销毁
在 singleton bean的情况下 即使多次 factory.getBean("someBean"); 这些工作都只会执行一次 包括属性的注入。

<bean id="someBean" class="com.cao.spring.SomeBean" init-method="afterPropertiesSetOfMy" destroy-method="destroyOfMy">

获取Bean自身的相关信息
BeanNameAware 接口 Spring 容器通过该接口调用bean 获取相关信息。获取的时机是 注入属性之后,初始化(init-method) 方法之前。

<bean id="father" class="com.cao.spring.ParentBean">
<property name="name" value="parent"/>
<property name="age" value="20"/>
</bean>
<!-- parent属性指向父bean -->
<bean id="child" class="com.cao.spring.ChildBean" parent="father">
<!-- 覆盖父baen中的name 属性的值 -->
<property name="name" value="override"/>
</bean>

1> ParentBean father = (ChildBean) factory.getBean("child");
2> ParentBean father = (ParentBean) factory.getBean("child");
father.getName();得到的都是 override说明 factory工厂创建的真正的实例还是ChildBean 当id = "Child" 的bean 没有class属性时可以用2>方法转型
得到的真正实例仍然是ChildBean

容器忽略既没有class也没有parent属性的bean

使用后理器(Post-Processor)
一个Bean post-processor 需要实现BeanPostProcessor接口。它有两个回调方法 postProcessBeforeInitialzation() 和 postProcessAfterInitialization();
如果一个 bean工厂注册了post-processor,那么对与所创建的每个bean实例。初始化方法前后都会得到一个回调。
测试发现: 使用BeanFactory 装配时候不需要 在配置文件中映射你的 后处理类。它会被自动调用。但要手动注册
org.springframework.beans.factory.config.ConfigurableBeanFactory config= new XmlBeanFactor(rs);
org.springframework.beans.factory.config.BeanPostProcessor postProcessor = new MyBeanPostProcessor();
config.addBeanPostProcessor(postProcessor);

使用ApplicationContext 工厂自动装配时。要在配置文件映射该类。<bean id="postBean" class="com.cao.spring.MyBeanPostProcessor"/>
只要你的配置文件有 MyBeanPostProcessor 这个类。好象id是可以随便取的。

使用BeanFactoryPostProcessor
实现 BeanFacotoryPostProcessor的类就是一个Bean factory post-processor,它可以在bean 工厂创建后对整个bean 做某种修改。

PropertyPlaceholderConfigurer
它用来将Spring配置文件中的属性只抽离到一个单独的java Properties文件。
这样可以避免在Spring的配置进行修改。

完整的参考测试工程源码 Eclipse3.2+Tomcate5.0 http://download.csdn.net/source/470868
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: