spring-FactoryBean

spring-FactoryBean

FactoryBean 是一个将对象构造逻辑封装在一个类中的一种设计模式。它可以用于构造复杂的对象,因为可能有许多的依赖关系,或者构造逻辑本身高度依赖于配置时,可以使用.FactoryBean 可以用于帮助Spring 构造无法轻松构造的对象。

我们先来看下这个模式的功能:

public interface FactoryBean<T> {
	/**
	* 返回一个实例
	*/
	@Nullable
	T getObject() throws Exception;

	/**
	* 返回即将创建的实例的类型
	*/
	@Nullable
	Class<?> getObjectType();

	/**
	* 返回是否单例
	*/
	default boolean isSingleton() {
		return true;
	}

}

举个例子:

首先有两个类 Person 和 Car ,Person 依赖 Car
Person类:

public class Person {
    private Car car;

    private void setCar(Car car) {
        this.car = car;
    }
}

Car类:

public class Car {


}

Car 的 builder:

public class CarBuilder {


    private String make;
    private int year;


    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public static CarBuilder car() {
        return new CarBuilder();
    }

    public Car factory() {
        return new Car();
    }
}

然后有个 MyCarFactoryBean 实现 FactoryBean

public class MyCarFactoryBean implements FactoryBean<Car> {

    private String make;
    private int year;


    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    @Override
    public Car getObject() throws Exception {
        // 如果你的构造逻辑很简单的话,其实没必要使用FactoryBean
        CarBuilder cb = CarBuilder.car();

        if (year != 0) {
            cb.setYear(this.year);
        }

        if (StringUtils.hasText(this.make)) {
            cb.setMake(this.make)
        }
        return cb.factory();
    }

    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

}

Bean 的配置:

<bean class = "a.b.c.MyCarFactoryBean" id = "car">
	<property name = "make" value ="Honda"/>
	<property name = "year" value ="1984"/>
</bean>
<bean class = "a.b.c.Person" id = "josh">
	<property name = "car" ref = "car"/>
</bean>

简单说明一下,这个功能是提供一个Person 类的bean,并依赖 Car 的bean,但是其中Car 的bean 是通过 MyCarFactoryBean 实现 FactoryBean 来的,因为我们可以在 MyCarFactoryBean 中自定义Car 的构建过程。在这个例子中,FactoryBean 的 getObject() 将会被spring 调用,而不是 FactoryBean 本身。如果你使用的是java 配置的方式,它需要你手动调用getObject()方法了,例如

// 和 xml 模式配置功能一样			
@Configuration 
public class CarConfiguration { 

  @Bean 
  public MyCarFactoryBean carFactoryBean(){ 
	MyCarFactoryBean cfb = new MyCarFactoryBean();
	cfb.setMake("Honda");
	cfb.setYear(1984);
	return cfb;
  }

  @Bean
  public Person aPerson(){ 
	Person person = new Person();
	person.setCar( carFactoryBean().getObject());
	return person; 
  }	
}

Spring FactoryBeans具有任何其他Spring bean的所有其他特性,包括Spring容器中所有Bean都享有的生命周期钩子和服务(如AOP)因此,如果您希望在设置FactoryBean上的属性之后执行构造逻辑,但在调用getObject()方法之前,则可以告诉Spring容器为FactoryBean提供回调。一种方法是实现InitializingBean接口。无论如何,这都会被调用。更多以POJO为中心的替代方法是使用@PostConstruct注释方法。在这种情况下,在设置了代码> make和year属性之后,将调用此方法。您可以使用此回调在对象构造完成之前进行完整性检查,但在容器的配置完成之后。

 @PostConstruct 
 public void setup() throws Throwable { 
   // these methods throw an exception that 
   // will arrest construction if the assertions aren't met
   Assert.notNull(this.make, "the 'make' must not be null")	;
   Assert.isTrue(this.year > 0, "the 'year' must be a valid value"); 
 }

FactoryBean在XML配置中很有用,作为其局限性的解决方法。 它是在静态XML中注入“动作”的方法,但是在 java 配置方式中,显得就不是那么有用了。

参考文档

posted @ 2019-08-04 22:15  莫己若  阅读(147)  评论(0编辑  收藏  举报