1. BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。
在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory
、XmlBeanFactory
、ApplicationContext
等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。
BeanFactory接口最重要的方法就是getBean:
public interface BeanFactory {
Object getBean(String name) throws BeansException;
1.1 例子
Car.java,这个普通的bean,有3个属性:
必须提供get、set方法用来设置属性
package com.my.test;
public class Car {
//最大速度,单位千米/小时
private int maxSpeed;
//品牌
private String brand;
//价格,单位元
private double price;
//-----提供属性的get和set方法
public int getMaxSpeed() {
return this.maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return this.brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return this.price;
}
public void setPrice(double price) {
this.price = price;
}
}
main方法执行代码:
package com.my.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Car car = (Car) context.getBean("car");
System.out.println(car.getBrand()+" "+car.getMaxSpeed()+" "+car.getPrice());
}
}
beans.xml,放在根路径,也可以放在其他位置,和main方法中保持一致即可:
<?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="car" class="com.my.test.Car">
<property name="brand" value="法拉利"/>
<property name="maxSpeed" value="400"/>
<property name="price" value="2000000"/>
</bean>
</beans>
路径:
执行结果:
法拉利 400 2000000.0
2. FactoryBean
Spring中共有两种bean,一种为普通bean,另一种则为工厂bean,即FactoryBean。
普通bean如同前文中:
<bean id="car" class="com.my.test.Car">
<property name="brand" value="法拉利"/>
<property name="maxSpeed" value="400"/>
<property name="price" value="2000000"/>
</bean>
通过context.getBean(“car”);获取的bean时候,类型就是bean.xml中class属性定义的"com.my.test.Car"
那么工厂bean是什么呢?
简单来说,FactoryBean的作用是创建一个bean,类似工厂方法。
以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>
接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()
返回的对象,而不是FactoryBean本身(FactoryBean本身是指class属性定义的),如果要获取FactoryBean对象,请在id前面加一个&符号来获取。
一般情况下,Spring通过反射机制
利用<bean>
的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>
中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。
Spring为此提供了一个org.springframework.bean.factory.FactoryBean
的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>
的形式。
2.1 例子:
我们基于<1.1 例子>改造:
CarFactoryBean.java,继承了FactoryBean接口:
需要实现getObject()和getObjectType(),getObject()返回值是Car
package com.my.test;
import org.springframework.beans.factory.FactoryBean;
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo ;
@Override
public Car getObject() throws Exception {
Car car = new Car () ;
String [] infos = carInfo .split ( "," ) ;
car.setBrand ( infos [ 0 ]) ;
car.setMaxSpeed ( Integer. valueOf ( infos [ 1 ])) ;
car.setPrice ( Double. valueOf ( infos [ 2 ])) ;
return car;
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
修改beans.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="car" class="com.my.test.Car">-->
<!--<property name="brand" value="法拉利"/>-->
<!--<property name="maxSpeed" value="400"/>-->
<!--<property name="price" value="2000000"/>-->
<!--</bean>-->
<bean id="car" class="com.my.test.CarFactoryBean" >
<property name="carInfo" value="法拉利,400,2000000"/>
</bean>
</beans>
执行结果,和普通bean的输出结果一致,调用getBean方法时获得的结果类型是Car:
法拉利 400 2000000.0
分析:
我们在beans.xml中定义的class="com.my.test.CarFactoryBean"
,并不是"…Car”,但是,当调用getBean方法时,其值却是个Car类型:
Car car = (Car) context.getBean("car");
如果希望获取CarFactoryBean自身的实例,则需要在使用getBean(beanName)方法时在beanName前显示的加上"&“前缀:如getBean(”&car");