[Spring] article quickly get to know the difference between BeanFactory and FactoryBean

table of Contents

A, BeanFactory

1.1 Source

1.2 usage scenarios

二、FactoryBean

2.1 Source

2.2 Example

2.2.1 Method One

2.2.2 Method Two

The two uses 2.3 FactoryBean

2.3.1 simplify the configuration xml hide details

2.3.2 return different instances of Bean

2.4 usage scenarios

Three, BeanFactory and the differences and similarities FactoryBean


A, BeanFactory

BeanFactory, ending Factory, indicating that it is a factory class (Interface), which is responsible for a bean factory production and management, we can get the object factory management through it. In Spring, the BeanFactory is IOC core interface container , its responsibilities include : instantiating or configuration application objects and the dependencies between those objects . It defines getBean () , containsBean () and other management general method of Bean. But BeanFactory only interfaces, not concrete realization IOC containers, but the Spring container to achieve given the variety, such as:

  • DefaultListableBeanFactory
  • XmlBeanFactory
  • ApplicationContext

 

XmlBeanFactory which is a commonly used, this implementation will be described XML dependencies between objects and objects that make up the application.

 

1.1 Source

public interface BeanFactory {
    /**
	用于区分factoryBean和bean,后面会讲到
    /*String FACTORY_BEAN_PREFIX = "&";

    /**
     返回byName返回bean的实例
	*/
    Object getBean(String name) throws BeansException;

    <T> T getBean(String name, Class<T> requiredType) throws BeansException;

    Object getBean(String name, Object... args) throws BeansException;

    <T> T getBean(Class<T> requiredType) throws BeansException;

    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;


    /**
     * Return a provider for the specified bean, allowing for lazy on-demand retrieval
     * of instances, including availability and uniqueness options.
     * @param requiredType type the bean must match; can be an interface or superclass
     * @return a corresponding provider handle
     * @since 5.1
     * @see #getBeanProvider(ResolvableType)
     */

    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    /**
	 判断工厂中是否包含给定名称的bean定义,若有则返回true
	*/
    boolean containsBean(String name);

    /**
    判断bean是否为单例
	*/
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    /**
	判断bean是否为多例
	*/
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    /**
	检查具有给定名称的bean是否匹配指定的类型。
     */
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    /**
	返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除*/
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    /**
	返回给定bean名称的所有别名 
	*/
    String[] getAliases(String name);
}

 

1.2 usage scenarios

  • Bean acquired from Ioc container (byName or byType)
  • Retrieving Ioc container contains the specified Bean
  • Bean determines whether singleton

 

二、FactoryBean

XML configuration, when spring containers, Spring reflection by using <bean> attribute specifies the class of the Bean class instance, under certain circumstances, Bean instantiation process is complex, if the conventional manner, the need to <bean > provides a lot of configuration information. Flexibility of arrangement is limited, such a heavy reliance on other class of object properties, even at this time by an automatic assembly, the dependencies between the bean does not need to explicitly written out, but the dependent object it needs to be fitted into the spring container, also need to rely on it more than a bean label objects are created they will inject, if this class relies on hundreds of objects, then this is undoubtedly a very large workload.

Spring factory class provides the interface for this org.springframework.bean.factory.FactoryBean a user can instantiate Bean by logic implementing this interface customization. FactoryBean interfaces for the Spring Framework occupy an important position, Spring provides its own implementation of more than 70 FactoryBean. They hide the details of some of the examples of complex Bean, to the upper application is made easier. From Spring3.0 start, FactoryBean began to support generic, namely the interface declaration instead FactoryBean <T> form.

There are two types of Spring bean, one for the common bean, was another bean factory

Ending Bean, indicating that it is a Bean, Bean is different from the ordinary: it is realized FactoryBean <T> Bean interface, based on the ID obtained from the Bean is actually the FactoryBean BeanFactory getObject () object returned instead FactoryBean itself, if you want to get FactoryBean object, add an ampersand in front of the id to get.

 

2.1 Source

public interface FactoryBean<T> {
    //从工厂中获取bean
    @Nullable
    T getObject() throws Exception;

    //获取Bean工厂创建的对象的类型
    @Nullable
    Class<?> getObjectType();

    //Bean工厂创建的对象是否是单例模式
    default boolean isSingleton() {
        return true;
    }
}

It can be seen from the interface definition, FactoryBean the performance of the duties of a plant. That is, if a Bean A FactoryBean implements an interface, then A becomes a factory, acquired under the name of A is actually a factory calls getObject () returns an object, rather than A itself, if you want to get A's own factory example, the need to add '&' symbol in front of the name.

  • getObject ( 'name') return an instance of the plant
  • getObject ( '& name') return an instance of the plant itself,

 

Under normal circumstances, no need to realize their bean factory pattern, Spring containers role as a factory; but a few cases, the container itself is a bean plant, is to produce other bean instances. Other examples of a bean plant bean generated not generated by the Spring container, so different from the ordinary bean configuration, is no longer necessary to provide elements class.

 

2.2 Example

We now want the following TempDaoFactoryBean class to the factory to create management

public class TempDaoFactoryBean {
    private String msg1;
    private String msg2;
    private String msg3;

    public void test() {
        System.out.println("FactoryBean");
    }
    public void setMsg1(String msg1) {
        this.msg1 = msg1;
    }
    public void setMsg2(String msg2) {
        this.msg2 = msg2;
    }
    public void setMsg3(String msg3) {
        this.msg3 = msg3;
    }
    public String getMsg1() {
        return msg1;
    }
    public String getMsg2() {
        return msg2;
    }
    public String getMsg3() {
        return msg3;
    }
}

 We have two ways to choose:

Method a: configure its spring by way of the xml.

Method two: define a class CarProxy achieve factoryBean interface.

 

2.2.1 Method One

If using a conventional Car disposed below the <bean>, respectively corresponding to each attribute of a Car <property> tag element, even if the use of automated assembly also write a lot of <bean> tag, very troublesome

 

2.2.2 Method Two

FactoryBean implement the interface defined DaoFactoryBean

/**
 * FactoryBean由名字可以看出,是以bean结尾的,就说明这是一个bean,是由IOC容器管理的一个bean对象
 *
 * 如果你的类实现了FactoryBean
 * 那么spring容器当中会存储两个对象:一个是getObject()方法返回的对象(TempDaoFactoryBean),还有一个就是当前对象(DaoFactoryBean)
 *
 * getObject()返回的对象(TempDaoFactoryBean)存储在spring容器中给这个对象设置的beanName是当前类指定的对象,也就是     @Component("daoFactoryBean")  中的daoFactoryBean
 * 当前对象(DaoFactoryBean)在spring容器中设置的beanName是在@Component("")指定name的基础上加一个“&”,这里也就是&daoFactoryBean
 *  
 * ClassCastException类型转换异常
 */
public class DaoFactoryBean implements FactoryBean {
     // DaoFactoryBean这个工厂bean管理的对象
    private String msg;

    // 使用setter方法将其注入
    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void testBean() {
        System.out.println("testBean");
    }

    @Override
    public Object getObject() throws Exception {    
        // 在FactoryBean内部创建对象实例
        TempDaoFactoryBean temp = new TempDaoFactoryBean();
        String[] msfArray = msg.split(",");
           temp.setMsg1(msfArray[0]);
        temp.setMsg2(msfArray[1]);
        temp.setMsg3(msfArray[2]);
        return temp;
    }

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

    /**
     * 是否是单例
     * @return
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

 Xml using this spring is fitted into the container factoryBean

<?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="daoFactory" class="priv.cy.dao.DaoFactoryBean">
        <property name="msg" value="msg1,msg2,msg3"></property>
    </bean>

</beans>

 

Test categories:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext
                = new AnnotationConfigApplicationContext(AppConfig.class);

        TempDaoFactoryBean tempDaoFactoryBean = (TempDaoFactoryBean) annotationConfigApplicationContext.getBean("daoFactory");
        System.out.println(tempDaoFactoryBean.getMsg1());
        System.out.println(tempDaoFactoryBean.getMsg2());
        System.out.println(tempDaoFactoryBean.getMsg3());
    }
}

 

Results of the:

 

Because when we getBean, spring FactoryBean of classes that implement the interface to achieve a special treatment

When you call getBean ( "daoFactory") when, the Spring through discovery reflection DaoFactoryBean achieved FactoryBean interface ,

In this case the container calls the interface method Spring in getObject () method returns. If you wish to obtain an instance of CarFactoryBean,

With "&" prefix is ​​required before beanName displayed when using the getBean (beanName) Method: as getBean ( "& car");  

 

2.3 FactoryBean two uses of

 

2.3.1 simplify the xml configuration, hidden details

If a class has a lot of attributes, we want to inject the value of class attributes Spring, is bound to write a lot of attributes configured in the configuration file, resulting in bloated configuration file, then you can consider using it to simplify the configuration FactoryBean

 

New bean

public class Student {
    /** 姓名 */
    private String name;
    /** 年龄 */
    private int age;
    /** 班级名称 */
    private String className;
    public Student() {
    }
    public Student(String name, int age, String className) {
        this.name = name;
        this.age = age;
        this.className = className;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getClassName() {
        return className;
    }
    public void setClassName(String className) {
        this.className = className;
    }
    @Override
    public String toString() {
        return "Student{" + "name='" + name + '\'' + ", age=" + age + ", className='" + className + '\'' + '}';
    }
}

 

FactoryBean implementation Interface

public class StudentFactoryBean implements FactoryBean<Student> {
    private String studentInfo;
    @Override
    public Student getObject() throws Exception {
        if (this.studentInfo == null) {
            throw new IllegalArgumentException("'studentInfo' is required");
        }
        String[] splitStudentInfo = studentInfo.split(",");
        if (null == splitStudentInfo || splitStudentInfo.length != 3) {
            throw new IllegalArgumentException("'studentInfo' config error");
        }

        Student student = new Student();
        student.setName(splitStudentInfo[0]);
        student.setAge(Integer.valueOf(splitStudentInfo[1]));
        student.setClassName(splitStudentInfo[2]);
        return student;
    }
    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }
    public void setStudentInfo(String studentInfo) {
        this.studentInfo = studentInfo;
    }
}

 

New day03.xml profile

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--注意:class是StudentFactoryBean而不是Student-->
    <bean id="student" class="com.lyc.cn.day03.StudentFactoryBean" p:studentInfo="张三,25,三年二班"/>
</beans>

 

Test category

public class MyTest {
    @Before
    public void before() {
        System.out.println("---测试开始---\n");
    }
    @After
    public void after() {
        System.out.println("\n---测试结束---");
    }
    @Test
    public void testStudentFactoryBean() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("day03.xml");
        System.out.println(applicationContext.getBean("student"));
        System.out.println(applicationContext.getBean("&student"));
    }
}

 

run

---测试开始---

Student{name='张三', age=25, className='三年二班'}

org.springframework.beans.factory_bean.StudentFactoryBean@1ae369b7

---测试结束---

 

这样我们就实现了通过BeanFactory接口达到了简化配置文件的作用。另外大家也可以发现getBean(“student”)返回的Student类的实例;而getBean("&student")返回的是StudentFactoryBean实例,即工厂bean其本身。

 

2.3.2 return different Bean instances

Since FactoryBean is a bean factory, then we may be required depending on the type of returns to different instances of the bean, by briefly explain the code

 

New bean

public interface Animal {
    void sayHello();
}

public class Cat implements Animal {
    @Override
    public void sayHello() {
        System.out.println("hello, 喵喵喵...");
    }
}

public class Dog implements Animal {
    @Override
    public void sayHello() {
        System.out.println("hello, 汪汪汪...");
    }
}

Animal interface creates an extremely two implementation classes Cat and Dog, and a simple output, how to return a different instance of Animal configure it by FactoryBean

 

New AnimalFactoryBean

public class AnimalFactoryBean implements FactoryBean<Animal> {
    private String animal;

    @Override
    public Animal getObject() throws Exception {
        if (null == animal) {
            throw new IllegalArgumentException("'animal' is required");
        }
        if ("cat".equals(animal)) {
            return new Cat();
        } else if ("dog".equals(animal)) {
            return new Dog();
        } else {
            throw new IllegalArgumentException("animal type error");
        }
    }

    @Override
    public Class<?> getObjectType() {
        if (null == animal) {
            throw new IllegalArgumentException("'animal' is required");
        }
        if ("cat".equals(animal)) {
            return Cat.class;
        } else if ("dog".equals(animal)) {
            return Dog.class;
        } else {
            throw new IllegalArgumentException("animal type error");
        }
    }
    public void setAnimal(String animal) {
        this.animal = animal;
    }
}

 

Day03.xml modify the configuration file, add the bean

<bean id="animal" class="com.lyc.cn.day03.AnimalFactoryBean" p:animal="cat"/>

 

Add a test case in the MyTest

@Test
public void testAnimalFactoryBean() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("day03.xml");
    Animal animal = applicationContext.getBean("animal", Animal.class);
    animal.sayHello();
}

 

run

---测试开始---

hello, 喵喵喵...

---测试结束---

可以看到,配置文件里我们将animal配置成了cat,那么返回的就是cat的实例,也是简单工厂的一个实现

 

 

2.4 Use Scene

Having said that, why have FactoryBean this thing does, what specific role it?

 

FactoryBean In Spring the most typical application is used to create a proxy object AOP.

We know that Spring AOP is actually created at runtime a proxy object, that object, we created at runtime, rather than the definition of a good start, which is in line with the factory method pattern. More figuratively speaking, AOP proxy object through Java's reflection mechanism to create a proxy object at runtime, the target object's proxy method based on business requirements woven into a corresponding method. This object is in Spring --ProxyFactoryBean.

So, FactoryBean provides a more flexible way for us to instantiate Bean, we can create a more sophisticated Bean instance by FactoryBean.

 

For example, we still spring need to integrate mybatis, in the absence of spring-mybatis case of (spring-mybatis will help you MyBatis  code is seamlessly integrated into the Spring  in ), we need to mybatis core classes SqlSessionFactory injected into the container spring, then think the most commonly used in two ways:

  1. Notes , however mybatis is referenced independent of our project . Nothing to do with our own project source code , we are unable to modify its source code, add annotations on its source, so you can not use annotation methods
  2. xml, sqlSessionFacory need to inject a lot of dependencies , if you use XML to configure, we need to write a lot of configuration label, very inconvenient to maintain.

A proxy class can be selected to handle sqlSessionFacory, i.e. we integrate spring + SqlSessionFactoryBean mybatis use of this class is provided by our fast factoryBean mybatis used to facilitate configuration mybatis by the class code for a lot of complicated configuration package up, similar to the decorator pattern, SqlSessionFactoryBean inside the sqlSessionFacory management and configuration settings related to his operation, we only need to SqlSessionFactoryBean injected into the spring container and some simple configuration information passed to the factoryBean in xml, SqlSessionFactoryBean it will help us to automatically configure sqlSessionFacory, many complex configurations to help us fill the well, then we can get done sqlSessionFacory configured by SqlSessionFactoryBean.

 

Three, BeanFactory and FactoryBean differences and similarities

Common: all interfaces

the difference:

  • BeanFactory ending Factory's, indicating that it is a factory class for the management of a factory Bean. In Spring, Bean are all to be managed by the BeanFactory (ie IOC container). The interface is the top-level interface IoC container is the most basic IoC container implementation, but also access to the root interface Spring container, responsible for bean creation, access, etc.
  • For FactoryBean, the ending Bean, stated that this is a given container to manage the bean. This is not a simple Bean Bean, but a generation capable of producing or modifying objects plant Bean, similar to its implementation and design model of the factory model and modified mode.

References:https://blog.csdn.net/lyc_liyanchao/article/details/82424122

Published 54 original articles · won praise 47 · views 10000 +

Guess you like

Origin blog.csdn.net/cy973071263/article/details/104758856