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,容器只负责创建,不负责销毁。