Spring 2. 通过 XML装配Bean

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);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37138933/article/details/78765083