Spring中BeanFactory,FactoryBean,factory-bean,factory-method的区别

导读:本篇文章讲解 Spring中BeanFactory,FactoryBean,factory-bean,factory-method的区别,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

概述

我们日常基本的使用中对BeanFactory、FactoryBean、factory-method、facotry-bean基本上不需要关系,但是本着对技术的好奇、敬畏、面试的角度,我们还是要了解一下它们到底时什么,有什么用。以后在工作中可能会使用到哦。

BeanFactory

这个最容易理解,bean工厂,bean的工厂,其实就是我们日常说是的spring容器,所有被spring管理的bean都在其中。

FactoryBean

为什么要使用FactoryBean

我们有多种方式可以向Spring容器中注册bean。
可以使用@Configuration注解结合@Bean注解向Spring容器中注册bean;
可以按照条件向Spring容器中注册bean;
可以使用@Import注解向容器中快速导入bean对象;
可以在@Import注解中使用ImportBeanDefinitionRegistrar向容器中注册bean。

一般情况下,Spring是通过反射机制利用bean的class属性指定实现类来实例化bean的。
但是如果示例化bean的过程比较复杂,按照传统的方式需要在标签中提供大量的配置信息,配置方式的灵活性是受限的,如果能够采用编码的方式定制bean实例化,使用起来比较方便。
下面讲解如何使用FactoryBean向Spring容器中注册bean。
生产bean的工厂,可以理解为就是一个生成bean的代理类。是Spring的特殊接口,工厂类接口(FactoryBean),为了解决复杂的实例化bean过程而被创造的,新版本增加了泛型类应对所有类型。

public interface FactoryBean<T> {
    T getObject() throws Exception;  //返回由FactoryBean创建的Bean实例
    Class<T> getObjectType();
    boolean isSingleton();
}

通过这个接口,我们可以看出使用的就是工厂方法模式,不同的子类实现FactoryBean接口,生成具体的bean。

创建复杂bean时简化配置

spring中如果bean在多参数的情况下需要在中提供大量的配置信息。
例如:

public   class  Car  {  
        private   int maxSpeed ;  
        private  String brand ;  
        private   double price ;  
  //getter/setter方法省略...
}
<bean id ="car" class="xxx.Car">
        <property name="maxSpeed" ref="100"/>
        <property name="brand" ref="Suzuki"/>
        <property name="price" ref="100000"/> 
</bean>

可以看到当属性越多时,标签就越复杂。
当使用了FactoryBean作为工厂类来生产Car对象时:

// 工厂类,实现 FactoryBean<T>接口
public class CarFactoryBean implements FactoryBean<Car>  { 
    private  String carInfo ; 
    // 重写getObject()方法,创建Car实例
    public Car getObject () throws  Exception  {  
        Car car =  new  Car () ;  
        // 将carInfo信息以逗号形式分割,分给各个属性,返回实例
        String []  infos =  carInfo.split ( "," ) ;  
        car.setBrand ( infos [ 0 ]) ;  
        car.setMaxSpeed ( Integer. valueOf ( infos [ 1 ])) ;  
        car.setPrice ( Double. valueOf ( infos [ 2 ])) ;  
        return car;  
    }  
    public  Class<Car> getObjectType () {  
        return Car.class ;  
    }  
    public boolean isSingleton () {  
        return false ;  
    }  
    public String getCarInfo () {  
        return this.carInfo ;  
    }  
  
    // 接受逗号分割符设置属性信息  
    public void setCarInfo ( String carInfo )   {  
        this.carInfo = carInfo;  
    }  
}
<bean id="car" class="com.baobaotao.factorybean.CarFactoryBean">
    <property name="carInfo" value="法拉利,400,2000000"/>
</bean>

这样就极大的简化了标签的代码量,在配置多个bean,多参数的场景下很实用。
当调用getBean(“car”)时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用方法CarFactoryBean#getObject()方法返回Car实例。
如果希望获取CarFactoryBean的实例,则需要使用getBean(“&car”),这是spring的内部约定:在需要获取FactoryBean时需要在getBean(beanName)方法是在beanName前显示的加上&前缀。
getBean(“car”) -> Car实例;
getBean(“&car”) -> CarFactoryBean实例;

简化依赖

当有其他类想要依赖Car类时:

public class Person { 
    private Car car ;
    private void setCar(Car car){ this.car = car;  }  
}// 这里用java config代替了<bean>标签,但这不是重点
@Configuration 
public class CarConfiguration { 
    @Bean 
    public CarFactoryBean carFactoryBean(){ 
      CarFactoryBean cfb = new CarFactoryBean();
      cfb.setBrand("Honda");
      cfb.setPiece(1984000);
      return cfb;
    }@Bean
    public Person aPerson(){ 
    	Person person = new Person();
      	// 注意这里的不同,这里直接调用carFactoryBean().getObject()方法返回Car实例化对象
   	 	person.setCar(carFactoryBean().getObject());
    	return person; 
    } 
}

小结

  • BeanFactory:是个Factory,是SpringIOC容器,是对象的工厂。
  • FactoryBean:是个Bean,一个能生产对象,修饰对象生产的工厂bean。

factory-method 与factory-bean

factory-method,factory-bean只有在spring中才有,springboot中不存在。
它们是标签的属性,用于创建bean对象,需要参数的话使用constructor-arg元素来指定它的参数。
factory-method可以用在静态方法创建类和非静态方法创建类两种,factory-bean用来指定创建bean的工厂bean,只能用在非静态方法创建bean的场景。
使用factory-method和factory-bean方式创建bean,我们可以自己定义一个类,然后在该类中定义一个方法,在该方法中完成spring bean的创建工作,其中factory-bean用于指定自己定义的类,factory-method用于指定创建bean的方法。

示例

  • 定义要创建的bean
public class Stu {
    public String stuId;
    public Stu(String stuId) {
        this.stuId = stuId;
    }
}
  • 定义工厂bean
public class StuFactory {
    static Map<String,Stu> stuMap = new HashMap<>();
    static{
        //初始化
        Stream.iterate(1,n->n+1).limit(5).map(String::valueOf).forEach(t-> stuMap.put(t, new Stu(t)));
    }
    
    //静态创建类,方法必须是静态(static修饰)
    public static Stu getStaticStu(String stuId){
        return stuMap.get(stuId);
    }

    //动态创建类
    public Stu getDynamicStu(String stuId){
        return new Stu(stuId);
    }
}

定义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="staticStu" class="yudaosourcecode.factorymethod.StuFactory" factory-method="getStaticStu">
        <!--传入getStaticStu方法的参数-->
        <constructor-arg value="1"/>
    </bean>

    <!--生成对象的工厂-->
    <bean id="stuFactory" class="yudaosourcecode.factorymethod.StuFactory"/>
    <!--动态获取对象-->
    <bean id="dynamicStu" factory-bean="stuFactory" factory-method="getDynamicStu">
        <!--传入getDynamicStu方法的参数-->
        <constructor-arg value="11"/>
    </bean>
</beans>
  • 测试
@Test
public void springFactoryMethodConfig() {
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:springFactoryMethodConfig.xml");
    //获取静态Bean
    Stu staticStu = ac.getBean("staticStu", Stu.class);
    System.out.println("staticStu: ");
    System.out.println(staticStu);
    //获取动态Bean
    Stu dynamicStu = ac.getBean("dynamicStu", Stu.class);
    System.out.println("dynamicStu: ");
    System.out.println(dynamicStu);
}
staticStu: 
yudaosourcecode.factorymethod.Stu@6ec8211c
dynamicStu: 
yudaosourcecode.factorymethod.Stu@7276c8cd

Process finished with exit code 0

参考

BeanFactory,FactoryBean;factory-bean,factory-method 区别

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99906.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!