首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

Spring核心Bean工场装配_Spring学习笔记

2012-10-08 
Spring核心Bean工厂装配__Spring学习笔记在Spring 中最核心的组件是bean工厂,它提供了基本的反向控制和依

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

在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{      //根据名字查找bean      Object getBean(String name) throws BeansException;      //检测目标bean是否具有指定的类型      Object getBean(String name,Class requiredType);            boolean containsBean(String name);      //检测某个bean 是否 singleton 如果是 ,则返回一个共享的实例。否则每次创建一个新的对象实例      boolean isSingleton(String name) throws NoSuchBeanDefinitionException;      Class getType(String name) throws NoSuchBeanDefinitionException;      String getAliases(String name) throws NoSuchBeanDefinitionException;}

?

实例化bean工厂的三种方法:

?

package com.cao.spring;import org.springframework.beans.factory.BeanFactory;import org.springframework.core.io.Resource;import org.springframework.beans.factory.xml.XmlBeanFactory;public class BeanFactoryUsage ...{    public static void main(String[] args)...{        //从文件系统资源实例化BeanFactory;        //默认从当前的工程目录下开始找。(工程目录/com/cao/文件目录)        org.springframework.core.io.Resource res = new org.springframework.core.io.FileSystemResource("com/cao/bean.xml");        org.springframework.beans.factory.BeanFactory factory = new org.springframework.beans.factory.xml.XmlBeanFactory(res);                System.out.println("OK"+factory);                        //从classpath下的资源实例化BeanFactory (Eclipse 中的 src/data目录下)        org.springframework.core.io.Resource  resClasspath = new org.springframework.core.io.ClassPathResource("data/bean2.xml");        org.springframework.beans.factory.BeanFactory factory2 = new XmlBeanFactory(resClasspath);                //使用ApplicationContext  从 classpath下的xml 文件实例化BeanFacotory        String classPath = "data/";        org.springframework.context.ApplicationContext appContext = new org.springframework.context.support.ClassPathXmlApplicationContext(new String[]...{classPath+"bean2.xml"});        //直接生成类工厂的实例。        org.springframework.beans.factory.BeanFactory factory3 = (BeanFactory)appContext;        }}

?

?Bean工厂的处理过程
(1) Spring中,一个bean 定义被抽象为BeanDefinition接口每次实例化XMLBeanFactory 或ClassPathXmlApplicationContext时都会对xml 进行解析,形成AbstractBeanDefinition向BeanFactory进行注册。
(2) 在这个过程中有些BeanFactory还会进行预初始化 (如ClassPathXmlApplicatitonContxt). 这样客户代码在调用getBean的时候就可以迅速取得Bean的实例了。


使用静态工厂方法创建Bean

通过静态工厂方法创建Bean,使用factory-method属性来指定工厂方法名。 目标bean的class属性正是哪个包含静态工厂的类。
<bean id="legacyBean" factory-method="getInstance"/>
这个bean 配置并未指定返回对象的类型,只是指定包含工厂方法的类。并且该类的 getInstance 方法必须是静态方法。


使用实例工厂方法创建Bean

通过实例工厂方法创建Bean ,类似于使用静态工厂,它调用一个已知的bean的工厂方法来创建新的bean
<bean id="legacyBean" /> <bean id="product" factory-bean="legacyBean" factory-method="make"/>
classs 指定了具体的Bean工厂类型 。 factory-bean 映射 id ="legacyBean" ;? factory-method 指定了生产bean 的方法。


Spring中,Ioc/DI 主要有两种形式。
(1)基于设值方法的依赖注入,通过bean的setter方法实现。在构造方法或其他方法创建bean的实例后,进setter注入也是完全允许的。
(2)基于构造方法的依赖注入,通过调用带有多个参数的构造来实现的。这些参数代表bean的协作者(要注入的哪个实例)或属性。spring将通过特定参数的 静态工厂方法来构造bean 也归到此类。

?

1,基于setter的依赖的bean 的配置

?

<bean id="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" /><bean id="yetAntherBean" />

?

//实现的类。package com.cao.spring;public class SetterBean ...{    private AnotherBean beanOne;    private YetAnotherBean beanTwo;    private int i;                public void setBeanOne(AnotherBean beanOne) ...{        this.beanOne = beanOne;    }    public void setIntegerProperty(int i) ...{        this.i = i;    }        public void setBeanTwo(YetAnotherBean beanTwo) ...{        this.beanTwo = beanTwo;    }    @Override    public String toString() ...{        // TODO Auto-generated method stub        return "beanOne"+this.beanOne+":beanTwo" +this.beanTwo+":int"+this.i;    }            public static void main(String[] args)...{        org.springframework.core.io.Resource rs = new org.springframework.core.io.ClassPathResource("data/setter.xml");        org.springframework.beans.factory.BeanFactory factory=              new org.springframework.beans.factory.xml.XmlBeanFactory(rs);                System.out.println(factory.getBean("setterBean"));    }    }

?

比较类和配置文件 ,可以看出。<property name="beanOne">? 的name对应类中的一个setXXX方法 xxx和name的值满足javaBean的定义。
???????????????????????????? <ref bean="anotherBean"/>? bean 的值引用另一个bean的id?? <bean id="anotherBean" />

事实上就是将com.cao.AnotherBean这个类通过 setXXX方法设置到类com.cao.SetterBean中作为它的成员属性。

2,基于构造方法的DI配置

<beans>    <bean id="constructBean" name="code">//实现类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;public class ConstructBean ...{    private AnotherBean beanOne;    private YetAnotherBean beanTwo;    private int i;    public ConstructBean(AnotherBean beanOne, YetAnotherBean beanTwo, int i) ...{        super();        this.beanOne = beanOne;        this.beanTwo = beanTwo;        this.i = i;    }    public String toString() ...{        // TODO Auto-generated method stub        return "beanOne"+this.beanOne+":beanTwo" +this.beanTwo+":int"+this.i;    }        public static void main(String[] args)...{        Resource rs = new ClassPathResource("data/construct.xml");        BeanFactory factory = new XmlBeanFactory(rs);        System.out.println(factory.getBean("constructBean"));            }}

??

做了一个测试发现 <constructor-arg> 配置中的参数的顺序不一定与 构造方法的参数的顺序相同。通过 index="2"来指定参数的位置(从0开始)

3,基于构造方法的DI配置__调用工厂方法(静态或非静态)

?

<beans>    <bean id="diFactory" 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" 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" 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" name="code"><bean id="outerBean" name="code"><beans>    <bean id="anotherBean" singleton="false"/>    <bean id="myBean" bean="anotherBean"/>    </bean></beans>

?

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

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

?

<bean id="myReplaceBean" replacer="aaa">            <arg-type>String</arg-type>                    </replaced-method>    </bean>    <bean id="aaa" name="code"><bean id="someBean" init-method="afterPropertiesSetOfMy" destroy-method="destroyOfMy">

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

public class AwareBean implements org.springframework.beans.factory.BeanNameAware,org.springframework.beans.factory.BeanFactoryAware ...{    private String beanName;    private BeanFactory factory;        public void setBeanName(String arg0) ...{         this.beanName = arg0;        }        public void setBeanFactory(BeanFactory arg0) throws BeansException ...{        this.factory = arg0;    }        public void doInit()...{        String name= factory.getClass().getName();                System.out.println("我是"+name+"创建的"+beanName);    }    public static void main(String[] args)...{        org.springframework.core.io.Resource rs  =              new ClassPathResource("data/beanAware.xml");                org.springframework.beans.factory.BeanFactory factory =             new XmlBeanFactory(rs);                factory.getBean("beanAware");    }}

?

分析代码我们可以发现 一个Bean 竟然可以 获得它的创建者(BeanFactory)的引用 。那么我们就可以利用这个引用获得更多的 信息。还可以将这个
BeanFactory 强制转型为合适的工厂类型 从而获得更多的相关信息。

父子bean的定义
一个bean的定义可以包含大量的配置信息,而一个子bean的定义可以继承父bean的配置。并允许覆盖和添加一些其他信息。在Spring中可以把父bean看成是字bean
的模板。使用父子bean 可以减少很多重复的工作。子bean使用parent属性来指向父bean

?

 <bean id="father" value="parent"/>        <property name="age" value="20"/>    </bean>                                                       <!-- parent属性指向父bean -->    <bean id="child" 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的配置进行修改。

热点排行