FactoryBean使用示例

半兽人 发表于: 2018-01-11   最后更新时间: 2018-01-11 17:43:19  
{{totalSubscript}} 订阅, 4,074 游览

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

FactoryBean接口对于Spring框架来说占有重要的地位,Spring 自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂bean的细节,给上层应用带来了便利。从Spring 3.0 开始, FactoryBean开始支持泛型,即接口声明改为FactoryBean 的形式:

package org.Springframework.beans.factory;    
public interface FactoryBean<T> {    
   T getObject() throws Exception;    
   Class<?> getObjectType();    
   boolean isSingleton();    
}
在该接口中还定义了以下3个方法。
  • T getObject():返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。

  • boolean isSingleton():返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。

  • Class getObjectType():返回FactoryBean创建的bean类型。

当配置文件中的class属性配置的实现类是FactoryBean时,通过 getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。例如:如果使用传统方式配置下面Car的时,Car的每个属性分别对应一个元素标签。

package com.system.net.springFactory;

public class Car {
    private int maxSpeed;
    private String brand;
    private double price;

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

如果用FactoryBean的方式实现就会灵活一些,下例通过逗号分割符的方式一次性地为Car的所有属性指定配置值:

package com.system.net.springFactory;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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<Car> getObjectType() {
        return Car.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    public String getCarInfo() {
        return this.carInfo;
    }

    // 接受逗号分割符设置属性信息
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

有了这个CarFactoryBean后,就可以在配置文件中使用下面这种自定义的配置方式配置Car Bean了:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
       xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="https://www.springframework.org/schema/p"
       xsi:schemaLocation="https://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="car" class="com.system.net.springFactory.CarFactoryBean" p:carInfo="benz,400,289000"/>
</beans>

运行测试

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/applicationContext.xml"});
        // 正常情况
        Car car = (Car) context.getBean("car");
        System.out.println(car.getBrand());
        System.out.println(car.getMaxSpeed());
        System.out.println(car.getPrice());

        // 获取CarFactoryBean的实例
        CarFactoryBean carFactoryBean = (CarFactoryBean) context.getBean("&car");
        System.out.println(carFactoryBean.getCarInfo());
    }

当调用getBean("car")时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean#getObject()方法返回。如果希望获取CarFactoryBean的实例,则需要在使用getBean(beanName) 方法时在beanName前显示的加上 "&" 前缀,例如getBean("&car")。

项目已分享到git上: https://github.com/orchome/net

更新于 2018-01-11
在线,1小时前登录

查看java更多相关的文章或提一个关于java的问题,也可以与我们一起分享文章