Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系。
但需要告诉Spring要创建哪些Bean并且如何将其装配在一起。 Spring有三种主要的装配机制:
- 在XML中进行显式配置;
- 在java中进行显示配置(通过注解);
- 隐式的bean发现机制和自动装配。
这篇博客讲述通过XML装配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。
下面写一段代码:
<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的类通过class属性来指定,而id属性来唯一标识一个名字。当Spring发现这个
元素时,它将会调用其无参构造器来创建bean。然后将chen
字面值注入到这个bean的name属性。这就是属性注入。
还有一种方法,通过更加简洁的p-命名空间。为了用p-命名空间,需要在XML文件中文件中与其他的命名空间一起对其声明(一般IDE会帮我们做好这件事):xmlns:p="http://www.springframework.org/schema/p"
。
然后按照
来进行属性注入。
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引用
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;
}
}
id="car" class="demo.Car">
name="brand" value="BMW">
id="person" class="demo.Person" p:name="chen">
<property name="car" ref="car">property>
对于p-命名空间,也有p:car-ref,如:
。
在上面的那个例子,可以看到在XML配置car的时候出现了
,这就是构造器注入。当然,与属性注入相似,也可以用c-命名空间(通过xmlns:c="http://www.springframework.org/schema/c"
声明)。
代码如下:
id="car" class="demo.Car" c:brand="BMW">
id="person" class="demo.Person" c:name="chen" c:car-ref="car">
那如果Person所拥有的一个Car的List集合,即:
public class Person {
private String name;
private List cars;
public Person(){}
public Person(String name, List cars) {
this.name = name;
this.cars = cars;
}
public List getCars() {
return cars;
}
public void setCars(List 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!");
}
}
这个时候引出在
下的
,至于
会在后面继续讨论。
如果字面值包含特殊字符可以使用 包裹起来。
使用构造器注入的属性值可以通过type指定参数参数类型;如:type="java.lang.String"
指明该属性值为String类型。
<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 id="person" class="demo.Person">
<constructor-arg type="java.lang.String">
<value>]]>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"
声明)。
<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>
<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>
上面两种都是通过反射的机制来配置bean,需要在bean配置中指明全类名。
而在工厂方法模式中, Spring不会直接利用反射机制创建bean对象, 而是会利用反射机制先找到Factory类,然后利用Factory再去生成bean对象。
而工厂方法分为两类:
工厂方法较其他方法用处较少,一般用于整合第三方框架的时候用到。
FactoryBean 用法可以与工厂方法有点类似,我们同样需要写工厂类,只不过这个类需要实现FactoryBean接口。
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;
}
}
<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);
}
}