A classic interview question: What is the difference between BeanFactory and FactoryBean?

This is also a classic interview question during the Spring interview. Today we will talk about this topic.

In fact, it can be seen from the name that BeanFactory is Factory and FactoryBean is a Bean. Let's look at the summary first:

  • BeanFactory is one of the core interfaces of the Spring framework, used to manage and obtain Bean instances in the application. It is an implementation of the factory pattern responsible for creating, configuring and managing Bean objects. BeanFactory is the foundation of the Spring IoC container, which can read the definition of beans from configuration metadata (such as XML files), and instantiate and provide these beans when needed.
  • A FactoryBean is a special bean that is a factory object used to create and manage instances of other beans. The FactoryBean interface defines a way to create beans, which allows developers to perform more custom operations in the process of creating beans. By implementing the FactoryBean interface, developers can create complex Bean instances, or perform some additional logic processing before Bean instantiation.

The difference is that BeanFactory is the core interface of the Spring framework for managing and providing Bean instances, while FactoryBean is a special Bean for creating and managing instances of other Beans. FactoryBean provides more customization capabilities in the Bean creation process, allowing additional logic processing.

Some friends may not see it very clearly, let's take a closer look.

1. BeanFactory

BeanFactory Knows that this is a Bean factory just by looking at the name. Friends know that the Spring IoC container helps us complete Bean creation, management and other operations, so these operations are inseparable from BeanFactory.

Let's take a brief look at the code of BeanFactory:

public interface BeanFactory {
	String FACTORY_BEAN_PREFIX = "&";
	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;
	<t> ObjectProvider<t> getBeanProvider(Class<t> requiredType);
	<t> ObjectProvider<t> getBeanProvider(ResolvableType requiredType);
	boolean containsBean(String name);
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
	boolean isTypeMatch(String name, Class<!--?--> typeToMatch) throws NoSuchBeanDefinitionException;
	@Nullable
	Class<!--?--> getType(String name) throws NoSuchBeanDefinitionException;
	@Nullable
	Class<!--?--> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
	String[] getAliases(String name);

}

These methods basically follow the name:

  • FACTORY_BEAN_PREFIX: This variable actually means that if the current bean is not a common bean like User or Book but a FactoryBean, add a prefix to the bean name. &amp;I will demonstrate this with my friends in the second section.
  • getBean: This method is to query the Bean according to the name and type of the Bean.
  • getBeanProvider: This method can get an ObjectProvider, ObjectProvider is an interface in the Spring framework, used to get the instance of the Bean object. It provides a way of lazy loading Bean, you can dynamically get the Bean instance when needed (lazy loading).
  • containsBean: Determine whether a Bean is included.
  • isSingleton: Determine whether a Bean is a singleton.
  • isPrototype: Determine whether a Bean is multi-instance.
  • isTypeMatch: Determine whether the type of a Bean is a given type.
  • getType: Get the type of Bean.
  • getAliases: Get the aliases of the Bean.

It can be seen that many of them are commonly used methods in our daily development.

When many small partners first get in touch with Spring, they will use an object ClassPathXmlApplicationContext, which is actually a subclass of BeanFactory. Let's look at the inheritance diagram of BeanFactory:

There are many inheritance classes, let me say a few that you may be familiar with:

  1. ClassPathXmlApplicationContext: This is to load the XML configuration file from the current classpath when the Spring container starts, and the parameter is the XML file path under the classpath.
  2. FileSystemXmlApplicationContext: This is to load the XML configuration file from the file system when the Spring container starts, and the parameter is an absolute path.
  3. AnnotationConfigApplicationContext: This is to load the Java configuration class through this configuration class if we use Java code to configure the Spring container.
  4. DefaultListableBeanFactory: This default implementation of the ListableBeanFactory and BeanDefinitionRegistry interface is a relatively mature BeanFactory.

Well, this is the characteristic of BeanFactory, everyone understands~

2. FactoryBean

2.1 Analysis

In fact, many friends may have seen FactoryBean, but they may not summarize it. Let me give you guys a few examples.

In the SSM project, if we want to configure MyBatis into the project, we generally need to configure the following Bean:

<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="typeAliasesPackage" value="org.javaboy.shirodemo.model" />
    <property name="mapperLocations">
        <list>
            <value>classpath*:org/javaboy/shirodemo/mapper/*.xml</value>
        </list>
    </property>
</bean>

When we configure Shiro, we generally configure the following beans:

<bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" id="shiroFilter">
    <property name="securityManager" ref="securityManager" />
    <property name="loginUrl" value="/login" />
    <property name="successUrl" value="/index" />
    <property name="unauthorizedUrl" value="/unauthorizedUrl" />
    <property name="filterChainDefinitions">
        <value>
            /index=anon
            /doLogin=anon
            /hello=user
            /**=authc
        </value>
    </property>
</bean>

If the parameters passed by our front end are in key-value format and have a date, then friends know that SpringMVC on the server side cannot handle this date by default, and a date converter needs to be configured. Generally, we add the following Bean in the Spring container (for This little friend who is not familiar with it can reply to ssm in the background of the official account [Jiangnan Yidianyu], there is a free introductory video recorded by Brother Song):

<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean" id="conversionService">
    <property name="converters">
        <set>
            <ref bean="myDateConverter" />
        </set>
    </property>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />

Friends observe that the above three beans have a common feature, that is, the names of the beans are all xxxFactoryBean.

Why use xxxFactoryBean instead of directly injecting the required Bean into the Spring container? Take MyBatis as an example:

Friends who have manually configured MyBatis should know that MyBatis has two important classes, one is SqlSessionFactory, and the other is SqlSession. A SqlSession can be obtained through SqlSessionFactory. But I don’t know if the friends still remember the configuration code, the manual configuration code is as follows (friends who are not familiar with this can reply to ssm in the background of the official account [Jiangnan Yidianyu], there is a free introductory video recorded by Song Ge):

public class SqlSessionFactoryUtils {
    private static SqlSessionFactory SQLSESSIONFACTORY = null;
    public static SqlSessionFactory getInstance() {
        if (SQLSESSIONFACTORY == null) {
            try {
                SQLSESSIONFACTORY = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return SQLSESSIONFACTORY;
    }
}
public class Main {
    public static void main(String[] args) {
        SqlSessionFactory factory = SqlSessionFactoryUtils.getInstance();
        SqlSession sqlSession = factory.openSession();
        List<user> list = sqlSession.selectList("org.javaboy.mybatis01.mapper.UserMapper.getAllUser");
        for (User user : list) {
            System.out.println("user = " + user);
        }
        sqlSession.close();
    }
}

Friends can see that neither SqlSessionFactory nor SqlSession is serious new. In fact, these two are interfaces, and it is obviously impossible to new. The former configures various properties through the builder mode, and finally generates an instance of SqlSessionFactory , the latter is generated through the factory of the former, and the objects obtained in the end are all subclasses of these two interfaces.

Therefore, SqlSessionFactory and SqlSession cannot be directly configured in the Spring container, so for such a Bean, it can be configured through xxxFactoryBean.

Let's take a look at the SqlSessionFactoryBean class. The source code is very long. I picked out the important ones:

public class SqlSessionFactoryBean implements FactoryBean<sqlsessionfactory>, InitializingBean, ApplicationListener<applicationevent> {

  private SqlSessionFactory sqlSessionFactory;

  @Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }
  @Override
  public Class<!--? extends SqlSessionFactory--> getObjectType() {
    return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
  }
  @Override
  public boolean isSingleton() {
    return true;
  }
}

Let's take a look, SqlSessionFactoryBean needs to implement the FactoryBean interface, and when implementing the interface, specify the generic type as SqlSessionFactory, that is, the final Bean produced by SqlSessionFactoryBean is SqlSessionFactory. After implementing the FactoryBean interface, you need to implement three methods in the interface:

  • getObject: The object returned by this method is the object to be registered in the Spring container. In this method, we can configure the Bean in various ways.
  • getObjectType: This method returns the object type registered with the Spring container.
  • isSingleton: This method is used to return whether the Bean registered in the Spring container is a singleton.

This is the characteristic of FactoryBean. Since the initialization of a certain Bean is too complicated, FactoryBean can be used to help register it in the Spring container.

2.2 Practice

Brother Song will write another simple example to let friends experience FactoryBean.

Let's say I have classes like:

public class Author {

    private String name;
    private Integer age;

    private Author() {
    }

    public static Author init(String name, Integer age) {
        Author author = new Author();
        author.setAge(age);
        author.setName(name);
        return author;
    }
    //省略 getter/setter/toString
}

The characteristic of this class is that the construction method is private, and you cannot go to new from the outside. Now I want to register the object of this class in the Spring container, so I can provide an AuthorFactoryBean:

public class AuthorFactoryBean implements FactoryBean<author> {
    @Override
    public Author getObject() throws Exception {
        return Author.init("javaboy", 99);
    }

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

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

Then configure AuthorFactoryBean in the Spring container:

<bean class="org.javaboy.bean.AuthorFactoryBean" id="author" />

Next, we can get the Author object from the container, but it should be noted that the Author object is obtained through the author name, not the AuthorFactoryBean object. If you want to get the AuthorFactoryBean object, then you need to get it through this name &amp;author( Review what was said in the first section).

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object author = ctx.getBean("author");
        Object authorFactoryBean = ctx.getBean("&amp;author");
        System.out.println("author.getClass() = " + author.getClass());
        System.out.println("authorFactoryBean.getClass() = " + authorFactoryBean.getClass());
    }
}

Let's take a look at the final running results:

Be consistent with what we think~

3. Summary

After the previous introduction, I believe that the friends have been able to distinguish between BeanFactory and FactoryBean, and then review the content at the beginning of this article:

  • BeanFactory is one of the core interfaces of the Spring framework, used to manage and obtain Bean instances in the application. It is an implementation of the factory pattern responsible for creating, configuring and managing Bean objects. BeanFactory is the foundation of the Spring IoC container, which can read the definition of beans from configuration metadata (such as XML files), and instantiate and provide these beans when needed.
  • A FactoryBean is a special bean that is a factory object used to create and manage instances of other beans. The FactoryBean interface defines a way to create beans, which allows developers to perform more custom operations in the process of creating beans. By implementing the FactoryBean interface, developers can create complex Bean instances, or perform some additional logic processing before Bean instantiation.

The difference is that BeanFactory is the core interface of the Spring framework for managing and providing Bean instances, while FactoryBean is a special Bean for creating and managing instances of other Beans. FactoryBean provides more customization capabilities in the Bean creation process, allowing additional logic processing. </author></applicationevent></sqlsessionfactory></user></t></t></t></t></t></t></t></t></ t></t></t>

Graduates of the National People’s University stole the information of all students in the school to build a beauty scoring website, and have been criminally detained. The new Windows version of QQ based on the NT architecture is officially released. The United States will restrict China’s use of Amazon, Microsoft and other cloud services that provide training AI models . Open source projects announced to stop function development LeaferJS , the highest-paid technical position in 2023, released: Visual Studio Code 1.80, an open source and powerful 2D graphics library , supports terminal image functions . The number of Threads registrations has exceeded 30 million. "Change" deepin adopts Asahi Linux to adapt to Apple M1 database ranking in July: Oracle surges, opening up the score again
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/lenve/blog/10086859