Bean元数据信息在Spring容器中对应物是由一个个BeanDefinition形成的Bean注册表,
Bean配置信息定义了Bean的实现以及依赖关系
<?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-3.0.xsd">
<bean id="car" name="#car1" class="com.baobaotao.simple.Car"></bean>
<bean id="boss" class="com.baobaotao.simple.Boss"></bean>
</beans>
Bean的名字:
id作为Bean的名称,在IOC容器中必须唯一,由字母开头,后面可以是a-zA-Z0-9-.等
Bean也可以使用name进行命名,name没有字符上的限制,几乎可以使用任意字符,不过最好不要使用中文字符,name可以重复,getBean(beanName)时返回最后的那个bean
name可以写多个逗号用,隔开,例如name="p,q",id不可以
如果id和name都没有指定,name默认使用类的全称作为Bean名字,<bean id="boss" class="com.baobaotao.simple.Boss"></bean>要使用getBean("com.baobaotao.simple.Boss");来获得,如果出现下面的情况:
同一个容器中:
<bean class="com.baobaotao.simple.Boss"></bean>
<bean class="com.baobaotao.simple.Boss"></bean>
<bean class="com.baobaotao.simple.Boss"></bean>
第一个通过getBean("com.baobaotao.simple.Boss");或者getBean("com.baobaotao.simple.Boss#0");获得第二个通过getBean("com.baobaotao.simple.Boss#1");获得,第三个通过getBean("com.baobaotao.simple.Boss#2");获得
依赖注入:
属性注入:
<bean id="car" class="com.baobaotao.attr.Car" lazy-init="default">
<property name="brand">
<value>
<![CDATA[红旗&CA72]]>
</value>
</property>
<property name="maxSpeed">
<value>200</value>
</property>
<property name="price" value="2000.00" />
</bean>
属性名以小写开头,应符合java命名规范,如果出现特殊情况,也要保持属性前两个字母,要么全部大写要么全部小写
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
<list>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</list>
<list>
<ref bean="usera"/>
<ref bean="userb"/>
<ref bean="userc"/>
</list>
<array>
<value>看报</value>
<value>赛车</value>
</array>
<map>
<entry >
<key>
<value>AM</value>
</key>
<value>会见客户</value>
</entry>
<entry>
<key>
<value>PM</value>
</key>
<value>公司内部会议</value>
</entry>
</map>
<props>
<prop key="jobMail">john-office@baobaotao.com</prop>
<prop key="lifeMail">john-life@baobaotao.com</prop>
</props>
<property name="car">
<ref local="car" /> 指向另一个bean的id
</property>
<ref>元素可通过三个属性引用其他容器中的Bean:
bean:同一个容器或者父容器中的Bean(常见)
local:同一配置文件中定义的bean
parent:父容器中的bean
父子容器允许有相同id的bean,子容器可以访问父容器中的bean,父容器却不能访问子容器中的bean,我们自己很少写父子容器,下面是父子容器的简单代码:
ClassPathXmlApplicationContext parentFactory=new ClassPathXmlApplicationContext(new String[]{"parent.xml"});
ClassPathXmlApplicationContext childFactory=new ClassPathXmlApplicationContext(new String[]{"parent.xml"},parentFactory);
childFactory.getBean("bean");
<bean id="sportsCar" class="com.baobaotao.attr.SportsCar">
<property name="brand">
<bean id="car.brand"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
</bean>
</property>
</bean>
上面的是内部bean,虽然提供了id,但是其他bean都不能使用它,name,id,scope属性都会被忽略,这里scope默认为prototype,如果sportsCar是prototype类型的话,每次得到一个"新"的sportsCar时,都会调用一次brand对应的bean的构造方法,如果是在外面定义的bean,scope默认值就是singleton的,上面定义的sportsCar就是singleton类型的
<property name="IDCode"><value></value></property> 值是空字符串
<property name="IDCode"><null/></property> 值是null
<property name="car.name"><null/></property> 级联属性 会调用 .getCar().setName(null); 如果car不存在为null,就会出错
如果子bean继承了父bean的同名集合元素,可以把父子合并:
<bean id="parentBoss" abstract="true"
class="com.baobaotao.attr.Boss">
<property name="favorites">
<set>
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</set>
</property>
</bean>
<bean id="childBoss" parent="parentBoss">
<property name="favorites">
<set merge="true">
<value>爬山</value>
<value>游泳</value>
</set>
</property>
</bean>
为了简化操作可以使用p命名空间,p:属性名="xxx" p:属性名_ref="xxx",例如:
<bean id="car" class="com.baobaotao.ditype.Car"
p:brand="红旗&CA72"
p:maxSpeed="200"
p:price="20000.00"/>
<bean id="boss" class="com.baobaotao.ditype.Boss"
p:car-ref="car"/>
如果希望配置集合类型的bean,那么可以使用util命名空间
<util:list id="favoriteList1" list-class="java.util.LinkedList">
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</util:list>
<util:set id="favoriteSet1" >
<value>看报</value>
<value>赛车</value>
<value>高尔夫</value>
</util:set>
<util:map id="emails1" >
<entry key="AM" value="会见客户" />
<entry key="PM" value="公司内部会议" />
</util:map>
<util:properties id="emailProps1"
location="classpath:com/baobaotao/fb/mails.properties" />
当然该util类还有其他用处,例如:
<property name="brand">
<util:constant
static-field="com.baobaotao.fb.CarBrandType.HONG_QI" />
</property>
<property name="brand">
<util:property-path path="boss.car.brand"/> 找到id为boss的bean取出car中的brand属性
</property>
构造方法注入:
按类型:
<bean name="constructorBean" class="bean.ConstructorBean">
<constructor-arg type="java.lang.String" value="1"/>
<constructor-arg type="java.lang.Integer" value="2"/>
</bean>
如果构造方法中有两个相同的类型就出问题了,按索引值:
<bean name="constructorBean" class="bean.ConstructorBean">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="2"/>
</bean>
两者联合使用也可以:
<bean name="constructorBean" class="bean.ConstructorBean">
<constructor-arg index="0" type="java.lang.String" value="1"/>
<constructor-arg index="1" type="int" value="2"/>
</bean>
使用构造方法注入时有可能出现循环依赖,比如 Bean1中有Bean2属性,Bean2中也有Bean1属性,两者都使用构造注入就出现了循环依赖问题
工厂方法注入:(参考:http://550516671-qq-com.iteye.com/blog/803999)
非静态方法:
public class CarFactory {
public Car createHongQiCar(){
Car car = new Car();
car.setName("红旗");
car.setSpeed("200");
return car;
}
}
<bean id="carFactory" class="com.lbx.factory.CarFactory"></bean>
<bean id="car" factory-bean="carFactory" factory-method="createHongQiCar"></bean>
静态方法:
public class CarFactory2 {
public static Car createHongQiCar(){
Car car = new Car();
car.setName("红旗");
car.setSpeed("200");
return car;
}
}
<bean id="car" class="com.lbx.factory.CarFactory2" factory-method="createHongQiCar"></bean>
Bean的作用域通过scope属性来指定,值如下:(参考:)
singleton
当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。
prototype
prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的
getBean()
方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)
request
request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
session
session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
global session
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用
自定义bean装配作用域
在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定义,自定义自己的作用域只要实现该接口即可
bean之间的依赖关系可以自动装配,在beans中可以配置属性default-autowire(全局对所有bean生效),在bean中设置autowire来实现。值如下:
no:通过ref元素指定依赖
byName:在容器中寻找和需要自动装配的属性名相同的Bean(或ID),如果没有找到相符的Bean,该属性就没有被装配上.
byType:在容器中寻找一个与需要自动装配的属性类型相同的Bean;如果没有找到相符的Bean,该属性就没有被装配上.
Constructor:在容器中查找与需要自动装配的Bean的构造方法参数一致的一个或者多个Bean,如果存在不确定的Bean或构造方法,容器会抛出异常org.springframework.beans.factory.UnsatisfiedDependencyException.
Autodetect:使用constructor或byType来自动装配。如果提供了默认的无参构造,就使用byType
方法注入:
让bean实现BeanFactoryAware,在方法中写:return (Car)factory.getBean("car");用在单例的bean中每次获取某属性时都要求是prototype类型的对象
lookup注入:bean中的某方法返回值并不是执行该方法得到的结果,而是容器中的某个bean,这里是通过为bean动态创建子类或实现类的方式实现的,例如
<bean name="userManager" class="research.spring.beanfactory.ch2.UserManager">
<lookup-method name="getUserDao" bean="userDao" />
</bean>
这里如果调用userManager中的getUserDao会返回userDao,无论UserManager中getUserDao有无实现
方法替换:
一个bean中的方法用另一个bean中相同签名的方法替换掉,例如:
<bean id="boss2" class="com.baobaotao.injectfun.Boss2"/>
<bean id="boss1" class="com.baobaotao.injectfun.Boss1">
<replaced-method name="getCar" replacer="boss2"></replaced-method>
</bean>
bean之间的关系:
继承:
父bean一般设置abstract=“true”表示只是为了代码被复用,子bean写属性parent=“parentbeanid”,这样子bean就可复制了父bean的配置信息
依赖:
在bean中写depends-on="beana" 那么保证在实例化当前bean时一定有了被依赖的bean了;即使不写依赖关系spring也会自动处理,这个属性主要在代码中依赖很不明显的情况下使用
引用:
把之前的ref标签改为idref标签,这样如果写错了id值,不是在运行时用到再报错,而是在容器启动时就报错了
如果需要一个配置文件包含其他配置文件,可以使用<import resource="classpath:com/auscend/beans.xml"/>
在bean标签中属性init-method="init" 定义实例化bean之后调用的方法, destroy-method="destory"定义要销毁bean之前要调用的方法,这两个方法都是定义在bean内部的方法,要注意如果是prototype的bean,容器只负责创建,不负责销毁。