BeanFactory and FactoryBean in Spring

1. Summary of premises

Many java developers have seen classes suffixed with FactoryBean in Spring frameworks, such as SqlSessionFactoryBean in Mybatis-Spring. Speaking of this, we have to mention BeanFactory. FactoryBean and BeanFactory are particularly confusing, and interviews often ask about these two concepts. In fact, their roles and usage scenarios are different.

2.BeanFactory

Let's start with BeanFactory. The root interface for accessing the Spring bean container. This is the basic client view of the Spring bean container. It turned out to be the interface for getting Spring Beans, or IoC containers. Then let's look at the class diagram.

It turns out that our more commonly used Application Context is a BeanFactory. We can get beans from BeanFactory by name or type of beans. It's no stranger to BeanFactory's introduction. Let's turn our attention to FactoryBean.

3.FactoryBean

What is FactoryBean? Take a look at the source code

          public interface FactoryBean<T> {

	          @Nullable
	         T getObject() throws Exception;

 
	          @Nullable
	         Class<?> getObjectType();

 
	         default boolean isSingleton() {
		       return true;
	         }
         }
  • T getObject() gets an instance of generic T. Used to create beans. When the IoC container uses the getBean method to create instances of FactoryBean, it is not the FactoryBean itself that is actually captured, but the T generic instances that are specifically created. We'll verify this later.
  • Class <?> getObjectType () Gets the specific type of the return value T in T getObject(). It is strongly recommended that if T is an interface, return the type of its specific implementation class.
  • default boolean isSingleton() is used to specify whether the bean created by Factory is a singleton. Here, the default method is defined as a single case.

3.1 FactoryBean usage scenarios

FactoryBeans are used to create a class of beans. For example, you have beans that belong to birds that need to be created, but they have their own characteristics. You just need to inject their characteristics into FactoryBeans to produce examples of birds. Take a more practical example. Even this example can be applied to actual java development. We need to build our own wheel of timed tasks. FactoryBean is perfect. Let's step by step demonstrate the usage scenario of FactoryBean using code.

3.2 Building a FactoryBean

We declare that timed tasks generally have the following elements:

  • The cron expression will certainly be used for time periods.
  • An abstract interface for the execution of a task.
  • The executor of the specific behavior of the timed task.

Task task executes the implementation of abstract interface. The implementation includes two aspects:

  • SomeService is the execution logic of specific tasks.
  • cron time expression

public class CustomTask implements Task {
    private SomeService someService;
    private String cronExpression;

    public CustomTask(SomeService someService) {
        this.someService = someService;
    }

    @Override
    public void execute() {
        //do something
        someService.doTask();
    }

    @Override
    public void setCron(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    @Override
    public String getCron() {
        return cronExpression;
    }
}

Through the above definition. Task time and logic can be configured differently according to different business. Then we implement a FactoryBean about Task.


public class TaskFactoryBean implements FactoryBean<Task> {
    private SomeService someService;
    private String cronExpression;


    @Override
    public Task getObject() throws Exception {
        CustomTask customTask = new CustomTask(someService);
        customTask.setCron(cronExpression);
        return customTask;
    }

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

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

    public SomeService getSomeService() {
        return someService;
    }

    public void setSomeService(SomeService someService) {
        this.someService = someService;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }
}


3.3 FactoryBean Injection into IoC

You can use xml injection mode, of course, you can also use Java Config configuration mode. Here we use Java Config injection. We injected two FactroyBean s into the Spring container.

@Configuration
public class Config {

    @Bean
    public TaskFactoryBean customTask() {
        TaskFactoryBean taskFactoryBean = new TaskFactoryBean();
        taskFactoryBean.setCronExpression("0 15 10 * * ?");
        String word = "Timing Task 1";
        SomeService someService = new SomeService();
        someService.setWord(word);
        taskFactoryBean.setSomeService(someService);
        return taskFactoryBean;
    }

    @Bean
    public TaskFactoryBean otherTask() {
        TaskFactoryBean taskFactoryBean = new TaskFactoryBean();
        taskFactoryBean.setCronExpression("0 15 17 * * ?");
        String word = "Timing Task II";
        SomeService someService = new SomeService();
        someService.setWord(word);
        taskFactoryBean.setSomeService(someService);
        return taskFactoryBean;
    }
}

Some Characteristics of 3.4 FactoryBean

Generally, if the @Bean annotation does not explicitly declare the bean name, the method name will be the bean name, and the return value will be the injected bean. But we found this through debug:

That is to say, the Bean created by FactoryBean is returned by the method name. So how do I return the FactoryBean? The answer given in the figure above is to add a reference "&" before the method. The specific reasons are also found in BeanFactory. Is it true that friends don't get together?

We tested the two bean s declared above and also successfully completed different business logic for timing tasks.

    @Autowired
    private Task customTask;
    @Autowired
    private Task otherTask;


    @Test
    public void task() {
        customTask.execute();
        otherTask.execute();
    }

4. Summary

In subsequent use, you can customize more timing tasks by declaring different cron expressions and different SomeService. Through this example, I believe you will have a clear understanding of FactoryBean. demo is not available. It's very simple. It's strongly recommended that you try it on your own to deepen your understanding.

Focus on the Public Number: Number Farmer, Little Pang, Get More Information

Tags: Programming Spring Java Mybatis xml

Posted on Mon, 09 Sep 2019 05:53:49 -0700 by jprazen