【Spring笔记】2. XML装配Bean

来源:互联网 发布:centos kvm 多主机 编辑:程序博客网 时间:2024/06/08 03:52

1. 装配Bean的可选方案

Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系。
但需要告诉Spring要创建哪些Bean并且如何将其装配在一起。 Spring有三种主要的装配机制:
- 在XML中进行显式配置;
- 在java中进行显示配置(通过注解);
- 隐式的bean发现机制和自动装配。

这篇博客讲述通过XML装配Bean。

2. XML装配Bean

  • 写一个简单的bean
public class Person{    private String name;    public Person(){}    public Person(String name) {        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void sayHello(){        System.out.println(name+" is saying Hello Spring!");    }}

这是一个我们想装配的bean。

2.1 属性注入

下面写一段代码:

  • Spring XML配置
<?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.xsd">     <bean id="person" class="demo.Person">         <property name="name" value="chen"></property>     </bean></beans>

通过<bean>来声明bean,bean的类通过class属性来指定,而id属性来唯一标识一个名字。当Spring发现这个<bean>元素时,它将会调用其无参构造器来创建bean。然后将chen字面值注入到这个bean的name属性。这就是属性注入
还有一种方法,通过更加简洁的p-命名空间。为了用p-命名空间,需要在XML文件中文件中与其他的命名空间一起对其声明(一般IDE会帮我们做好这件事):xmlns:p="http://www.springframework.org/schema/p"
然后按照<bean id="person" class="demo.Person" p:name="chen"></bean>来进行属性注入。

public class Main {    public static void main(String[] args) {        //原来的创建Person类实例的方法        //Person person = new Person();        //person.setName("chen");        //person.sayHello();        //通过Spring容器获取Person类实例        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");        Person person = (Person) context.getBean("person");//通过id来获取Person        person.sayHello();    }}

现在Person类用有了一个Car类,不能进行字面值注入了,这个时候引入ref引用

  • Car类
public class Car {    private String brand;    public Car() {}    public Car(String brand) {        this.brand = brand;    }    public String getBrand() {        return brand;    }    public void setBrand(String brand) {        this.brand = brand;    }}
  • XML的配置
<bean id="car" class="demo.Car">   <constructor-arg name="brand" value="BMW"></constructor-arg></bean><bean id="person" class="demo.Person" p:name="chen">    <property name="car" ref="car"></property></bean>

对于p-命名空间,也有p:car-ref,如:<bean id="person" class="demo.Person" p:name="chen" p:car-ref="car"></bean>

2.2 构造器注入

在上面的那个例子,可以看到在XML配置car的时候出现了<constructor-arg name="brand" value="BMW"></constructor-arg>,这就是构造器注入。当然,与属性注入相似,也可以用c-命名空间(通过xmlns:c="http://www.springframework.org/schema/c"声明)。
代码如下:

  • XML配置
<bean id="car" class="demo.Car" c:brand="BMW">    </bean><bean id="person" class="demo.Person" c:name="chen" c:car-ref="car"></bean>

那如果Person所拥有的一个Car的List集合,即:

  • Person类
public class Person {    private String name;    private List<Car> cars;    public Person(){}    public Person(String name, List<Car> cars) {        this.name = name;        this.cars = cars;    }    public List<Car> getCars() {        return cars;    }    public void setCars(List<Car> cars) {        this.cars = cars;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void sayHello(){        System.out.println(name+" is saying Hello Spring!");    }}

这个时候引出在<constructor-arg>下的<list>,至于<set>,<map>,<props>会在后面继续讨论。

如果字面值包含特殊字符可以使用<![CDATA[]]> 包裹起来。
使用构造器注入的属性值可以通过type指定参数参数类型;如:type="java.lang.String"指明该属性值为String类型。

  • XML配置
<bean id="car1" class="demo.Car" c:brand="BMW"></bean><!-- 使用构造器注入属性值可以通过type指定参数参数类型,以区分重载的构造器--><bean id="car2" class="demo.Car">    <constructor-arg name="brand" value="Audi" type="java.lang.String"></constructor-arg></bean><bean id="car3" class="demo.Car" c:brand="Benz"></bean><bean id="person" class="demo.Person">    <constructor-arg  type="java.lang.String">        <!-- 字面值包含特殊字符,如:<chen>,可以使用<![CDATA[]]> 包裹起来-->        <value><![CDATA[<chen>]]></value>    </constructor-arg>    <constructor-arg>        <list>            <ref bean="car1"></ref>            <ref bean="car2"></ref>            <ref bean="car3"></ref>        </list>    </constructor-arg></bean>

如果在配置每个person bean的时候,都有相同的list,那我们可以将这些共同代码提取出来,即引入util-命名空间(通过xmlns:util="http://www.springframework.org/schema/util"声明)。

  • XML配置
<bean id="car1" class="demo.Car" c:brand="BMW"></bean><bean id="car2" class="demo.Car">     <constructor-arg name="brand" value="Audi" type="java.lang.String"></constructor-arg></bean><bean id="car3" class="demo.Car" c:brand="Benz"></bean><!-- 配置单例的集合bean,以供多个bean进行引用--><util:list id="cars">   <ref bean="car1"></ref>   <ref bean="car2"></ref>   <ref bean="car3"></ref></util:list><bean id="person" class="demo.Person">   <constructor-arg name="name" value="chen" type="java.lang.String"></constructor-arg>   <constructor-arg name="cars" ref="cars"></constructor-arg></bean>

2.3 工厂方法

上面两种都是通过反射的机制来配置bean,需要在bean配置中指明全类名。
而在工厂方法模式中, Spring不会直接利用反射机制创建bean对象, 而是会利用反射机制先找到Factory类,然后利用Factory再去生成bean对象。
而工厂方法分为两类:

  • 静态工厂方法
  • 实例工厂方法

工厂方法较其他方法用处较少,一般用于整合第三方框架的时候用到。

2.4 FactoryBean

FactoryBean 用法可以与工厂方法有点类似,我们同样需要写工厂类,只不过这个类需要实现FactoryBean接口。

  • CarFactoryBean 类
public class CarFactoryBean implements FactoryBean<Car>{    private String brand;    public void setBrand(String brand) {        this.brand = brand;    }    @Override    public Car getObject() throws Exception {        return new Car(brand);    }    @Override    public Class<?> getObjectType() {        return Car.class;    }    @Override    public boolean isSingleton() {        return true;    }}
  • XML配置
<!--    通过FactoryBean来配置bean的实例    class:指向FactoryBean的全类名    property:配置factory的属性    但实际返回的实例是FactoryBean的getObject()方法--><bean id="car" class="demo.CarFactoryBean">    <property name="brand" value="BWM"></property></bean>
  • 测试
public class Main {    public static void main(String[] args) {        ApplicationContext context =  new ClassPathXmlApplicationContext("beans-factoryBean.xml");        Car car  = (Car) context.getBean("car");        System.out.println(car);    }}
原创粉丝点击