Spring IoC容器 根据基于xml的配置元数据(configuration Metadata),使用反射机制来创建Bean的实例。
创建的方法有三种:
1. 通过构造器<constructor-arg/>
1.1 使用空构造器进行定义。类中必须有空构造器(可以是默认的)
空构造器中没有传入参数,bean的配置只需要一个定义名就可以了。
<bean id="beanID" class="com.szse.beans.HelloApiImpl "></bean>
例子:
接口HelloApi.java
package com.szse.beans; public interface HelloApi { public void sayHello(); }它的实现类HelloApiImpl.java
package com.szse.beans; public class HelloApiImpl implements HelloApi{ private int num; private String message; public HelloApiImpl(){ num = 1; message = "Hello world!"; } @Override public void sayHello() { System.out.println(num + ":" + message); } }
配置文件HelloWorld.xml<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"> <bean id="firstBean" class="com.szse.beans.HelloApiImpl "> </bean> </beans>单元测试类TestHello.javapackage com.szse.beans; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestHello { @Test public void testInstantiatingBeanByConstructor() { //使用构造器 ApplicationContext ctx = new ClassPathXmlApplicationContext("HelloWorld.xml"); HelloApi firstBean = ctx.getBean("firstBean",HelloApi.class); firstBean.sayHello(); } }输出 1:Hello world!
1.2 带参构造器, 类中有带参的构造方法①根据参数索引(index)<bean id="beanID" class="com.szse.beans.HelloApiImpl "><constructor-arg index=" " value=" "/></bean>index表示构造器的第几个参数,从0开始,value即为该参数的值。例子:在HelloApiImpl.java添加public HelloApiImpl(int num,String message){ this.num = num; this.message = message; }
<bean id="secondBean" class="com.szse.beans.HelloApiImpl "> <constructor-arg index="0" value="2" /> <constructor-arg index="1" value="Hello spring!" /> </bean>
在TestHello.java的测试方法,保留第一个例子作为对比
@Test public void testInstantiatingBeanByConstructor() { //使用构造器 ApplicationContext ctx = new ClassPathXmlApplicationContext("HelloWorld.xml"); HelloApi firstBean = ctx.getBean("firstBean",HelloApi.class); firstBean.sayHello(); HelloApi secondBean = ctx.getBean("secondBean",HelloApi.class); secondBean.sayHello(); }
输出1:Hello world!
2:Hello spring!
②根据参数类型(type)
将上面的secondBean配置改为如下
<bean id="secondBean" class="com.szse.beans.HelloApiImpl "> <constructor-arg type="int" value="2" /> <constructor-arg type="java.lang.String" value="Hello spring!" /> </bean>若是java基础类型,type可以直接指定该类型,其他都要用全类名。
测试方法不变,大家可以自己运行一遍试试结果是否一样。
③根据参数名(name)
将上面的secondBean配置改为如下
<bean id="secondBean" class="com.szse.beans.HelloApiImpl "> <constructor-arg name="num" value="2" /> <constructor-arg name="message" value="Hello spring!" /> </bean>测试方法不变,大家可以自己再运行一遍试试结果是否一样。
注:这里解释顺便给大家加深一下 对 “bean的实例是由IoC容器主动创建,而不是由我们自己创建” 这句话的理解。可以在构造器中加上System.out.println(”print sth…")。
测试方法中只保留这一句:
ApplicationContext ctx =
new ClassPathXmlApplicationContext("HelloWorld.xml");运行输出,看看是不是我们xml文件中配置了几个bean就会打印出几个“print sth…”。
所以,ApplicationContext加载XML文件时就会创建好所有bean的实例,我们用的时候只需要getBean()就可以了。
2. 使用静态工厂方法
<bean id="beanID" class="com.szse.beans.HelloApiStaticFactory"factory-method="newInstance">
</bean>
注意这里的class属性是静态工厂类,而不是该bean的类。使用factory-method属性来确定哪个静态工厂方法创建的bean实例。
Spring调用工厂方法(也可以包含一组参数),并返回一个有效的对象。如果静态工厂方法需要参数,使用<constructor-arg>元素传入。
例子
静态工场类HelloApiStaticFactory.java
package com.szse.beans; public class HelloApiStaticFactory { //工厂方法 public static HelloApi newInstance(int num,String message) { //返回需要的Bean实例 return new HelloApiImpl(num,message); } }xml中加上
<bean id="thirdBean" class="com.szse.beans.HelloApiStaticFactory" factory-method="newInstance"> <constructor-arg name="num" value="3" /> <constructor-arg name="message" value="Hello Jane!" /> </bean>@Test public void testInstantiatingBeanByFactory() { //使用工场方法 ApplicationContext ctx = new ClassPathXmlApplicationContext("HelloWorld.xml"); HelloApi thirdBean = ctx.getBean("thirdBean",HelloApi.class); thirdBean.sayHello(); }
输出结果:3:Hello Jane!
3. 使用实例工场方法
先定义实例工厂Bean
<bean id="instancefactorybean" class="InstanceFactory全类名"/>
再使用实例工厂Bean创建我们需要的Bean,注意这里没有class属性了。若要传入指定方法参数,则和使用构造器方式一样。
<bean id="fourthBean" factory-bean="instancefactorybean" factory-method="newInstance"></bean>例子
实例工厂类HelloApiInstanceFactory.java
package com.szse.beans; public class HelloApiInstanceFactory { public HelloApi newInstance(int num,String message) { return new HelloApiImpl(num,message); } }xml文件中加入
<bean id="instancefactorybean" class="com.szse.beans.HelloApiInstanceFactory"/> <bean id="fourthBean" factory-bean="instancefactorybean" factory-method="newInstance"> <constructor-arg name="num" value="4" /> <constructor-arg name="message" value="Hello Tom!" /> </bean>测试方法testInstantiatingBeanByFactory加入
HelloApi fourthBean = ctx.getBean("fourthBean",HelloApi.class); fourthBean.sayHello();输出结果 4:Hello Tom!
这三种实例化Bean的方式只是配置不一样,从获取方式看完全一样。这三种方式都是基于XML配置文件,脱离xml文件
Spring容器还有基于注解(Annotation)的方式来创建Bean,这个我们以后会讲到。