Blog: bugstack.cn

Precipitation, share, grow, let yourself and others can gain something! 😄

One, foreword

Can you foresee design problems with complex content?

It stands to reason that a large percentage of programmers write a bunch of if… Else to complete the development and smooth launch. This is mainly because we can not foresee the current demand, whether the development is long-term, whether the flow is huge, whether the iteration is rapid, so in the case of being urged to go online, do not write if… Else is impossible!

So you say, since if… Else implementation so fast, also consider the data structure, algorithm logic, design patterns, system architecture? Of course, it depends on how long your project can be expected to live, if a project lives for at least a year, and there are iterations throughout the year. Like; You create a marketing coupon system that gives out various types of coupons under various conditions, and if you don’t think about the system design and architecture patterns in the beginning, you may end up in a system crash when activity is frequent, traffic is skyrocketing, demand is iterating!

We are focusing the system design perspective on concrete code implementation, what means do you have to implement the design pattern you want? Actually encoding mainly depends on: the interface definition, class implements the interface and abstract class implements the interface, the derived class, inheritance, abstract class, which is isolated from each class operating mode can be very good basic function, general function and business functions, after the class responsibilities clear, your whole design will become easy to extend and iteration.

Next, in this chapter, we will continue to improve the functional development of Spring Bean container framework. In this development process, we will use more interfaces, classes and abstract classes, and there will be class implementation and class inheritance between them. Can carefully refer to the development of this part of the content of the implementation, although it will not be very complex, but this design idea is completely reusable to our own business system development.

Second, the target

In the previous chapter, implementing a Simple Bean container, we implemented a crude version of the code implementation based on Spring Bean container concepts. In this chapter, we need to combine the Spring Bean container to complete the function and realize the registration and acquisition of Bean objects by the Bean container.

This time we leave the creation of the Bean to the container, rather than passing an instantiated Bean object on call, and consider singletons, which can be fetched from memory on a second fetch. In addition to implementing functionality, the class structure of the base container framework needs to be perfected, otherwise it will be difficult to add additional functionality in the future.

Three, the design

Given the case goals of this section, we need to complete the Spring Bean container, and it is important to first register only one class information at Bean registration time, rather than directly registering the instantiation information in the Spring container. Then you need to change the Object property in BeanDefinition to Class. What you need to do next is to handle the instantiation of the Bean Object when you get the Bean Object and determine whether the current singleton has been cached in the container. Figure 3-1 shows the overall design

  • First we need to define a Bean factory such as BeanFactory, which provides the method to get the BeangetBean(String name), the Bean factory interface is then implemented by the abstract class AbstractBeanFactory. Such useTemplate patternCan unify the common core method call logic and standard definition, also very good control of the subsequent implementors do not care about the call logic, according to the unified way of execution. Then the heirs of the class need only care about the logical implementation of the concrete method.
  • So after the inherited abstract classes AbstractBeanFactory AbstractAutowireCapableBeanFactory can implement corresponding abstract method, Because AbstractAutowireCapableBeanFactory itself is an abstract class, so it can only realize their own abstract methods, other abstract method by inheritance AbstractAutowireCapableBeanFactory class implements. You only need to care about the content that belongs to you, not your content, do not participate.This part of the content will be reflected in the code
  • In addition there is also very important piece of knowledge, it is about the singleton SingletonBeanRegistry interface definitions, and DefaultSingletonBeanRegistry after the implementation, is an abstract class AbstractBeanFactory inheritance. AbstractBeanFactory is now a very complete and powerful abstract class that represents its abstract definition of a template pattern.Now let’s take a look at the code implementation with these design-level considerations in mind

Four, implementation,

1. Engineering structure

small-spring-step-02└ ─ ─ the SRC ├ ─ ─ the main │ └ ─ ─ Java │ └ ─ ─ cn. Bugstack. Springframework. Beans │ ├ ─ ─ factory │ │ ├ ─ ─ factory │ │ │ ├ ─ ─ BeanDefinition. Java │ │ │ └ ─ ─ SingletonBeanRegistry. Java │ │ ├ ─ ─ support │ │ │ ├ ─ ─ AbstractAutowireCapableBeanFactory. Java │ │ │ ├ ─ ─ AbstractBeanFactory. Java │ │ │ ├ ─ ─ BeanDefinitionRegistry. Java │ │ │ ├ ─ ─ DefaultListableBeanFactory. Java │ │ │ └ ─ ─ DefaultSingletonBeanRegistry. Java │ │ └ ─ ─ the BeanFactory. Java │ └ ─ ─ BeansException. Java └ ─ ─ the test └ ─ ─ Java └ ─ ─ cn. Bugstack. Springframework. Test ├ ─ ─ bean │ └ ─ ─ UserService. Java └ ─ ─ ApiTest.javaCopy the code

Project source: public account “bugStack wormhole stack”, reply: Spring column, obtain the source code

Spring Bean container class relationships, as shown in Figure 3-2

Although there are still many gaps between the implementation of Spring Bean container functions and Spring source code, the class diagram of the current implementation results shows that there is a certain degree of complexity in the design of these complex class relationships, which are reflected in the interface definition and implementation as well as in the abstract class inheritance. For example:

  • The AbstractBeanFactory abstract class implements the getBean method of the interface
  • And AbstractBeanFactory inherited realized SingletonBeanRegistry DefaultSingletonBeanRegistry class. This AbstractBeanFactory abstract class has singleton Bean registration.
  • AbstractBeanFactory defines two more abstract methods: GetBeanDefinition (String beanName), createBean(String beanName, BeanDefinition BeanDefinition), And the two abstract methods respectively by DefaultListableBeanFactory, AbstractAutowireCapableBeanFactory implementation.
  • Eventually DefaultListableBeanFactory will inherit abstract class AbstractAutowireCapableBeanFactory also can call the createBean method in the abstract class.

To sum up, this part of the class relationship and implementation process will be a bit complicated, because all the implementation of responsibility division, separation of commonalities and call relationship definition as the standard set up class relationship. This part of the study may enrich your design ideas in the development of complex business systems.

2. BeanDefinition definition

cn.bugstack.springframework.beans.factory.config.BeanDefinition

public class BeanDefinition {

    private Class beanClass;

    public BeanDefinition(Class beanClass) {
        this.beanClass = beanClass;
    }
		/ /... get/set
}
Copy the code
  • The Bean definition Class has replaced the Object Bean from the previous section with a Class, so that Bean instantiations can be handled in the container.If you have read and tested the previous chapter carefully, you will see that Bean instantiations are passed to the BeanDefinition constructor during the initial call phase.

3. Singleton registration interface definition and implementation

cn.bugstack.springframework.beans.factory.config.SingletonBeanRegistry

public interface SingletonBeanRegistry {

    Object getSingleton(String beanName);

}
Copy the code
  • This class is relatively simple and mainly defines an interface to get a singleton.

cn.bugstack.springframework.beans.factory.config.DefaultSingletonBeanRegistry

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    private Map<String, Object> singletonObjects = new HashMap<>();

    @Override
    public Object getSingleton(String beanName) {
        return singletonObjects.get(beanName);
    }

    protected void addSingleton(String beanName, Object singletonObject) { singletonObjects.put(beanName, singletonObject); }}Copy the code
  • Main realization in DefaultSingletonBeanRegistry getSingleton method, and implements a protected addSingleton method, this method can be inherited such other type of call. Including: AbstractBeanFactory DefaultListableBeanFactory calls and inheritance.

Abstract Class Definition template method (AbstractBeanFactory)

cn.bugstack.springframework.beans.factory.support.AbstractBeanFactory

public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {

    @Override
    public Object getBean(String name) throws BeansException {
        Object bean = getSingleton(name);
        if(bean ! =null) {
            return bean;
        }

        BeanDefinition beanDefinition = getBeanDefinition(name);
        return createBean(name, beanDefinition);
    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

}
Copy the code
  • AbstractBeanFactory inherited DefaultSingletonBeanRegistry first, also have use singleton registered class methods.
  • The next important point is about the implementation of the interface BeanFactory, which can be seen in the implementation process of the method getBean. It is mainly about the acquisition of the singleton Bean object and the need to get the definition of the Bean when it is not available

Bean instantiation operation. Instead of implementing these methods, getBean defines the calling procedure and provides abstract methods that are implemented by other classes that implement this abstract class.

  • Classes that inherit AbstractBeanFactory include: AbstractAutowireCapableBeanFactory, DefaultListableBeanFactory, these two classes do the corresponding implementation respectively, and then to look down.

5. Instantiate the Bean class (AbstractAutowireCapableBeanFactory)

cn.bugstack.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
        Object bean = null;
        try {
            bean = beanDefinition.getBeanClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        addSingleton(beanName, bean);
        returnbean; }}Copy the code
  • AbstractAutowireCapableBeanFactory class implements the Bean instantiationnewInstanceIn fact, this will bury a hole, how to handle the object with constructor entry parameter?You can think ahead
  • Called directly after processing the instantiation of the Bean objectaddSingletonThe method is stored in the cache of the singleton.

Core class implements (DefaultSingletonBeanRegistry) 6.

cn.bugstack.springframework.beans.factory.support.DefaultSingletonBeanRegistry

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
        returnbeanDefinition; }}Copy the code
  • DefaultListableBeanFactory in Spring source is also a very core classes, in our current implementation is also gradually close to the source code, and the source code is consistent with the name of the class.
  • DefaultListableBeanFactory inherited AbstractAutowireCapableBeanFactory class, also have a series of functions such as interface the BeanFactory and AbstractBeanFactory implementation.So sometimes you’ll see classes that are forced to call certain methods because the class that you’re forcing implements an interface or inherits some class.
  • This class also implements the beanDefinitionDefinition (String beanName, BeanDefinition BeanDefinition) method in the BeanDefinitionRegistry interface, Of course, you’ll also see an implementation of getBeanDefinition, which we mentioned in this article is an abstract method defined in AbstractBeanFactory.Now you can register the Bean definition and get the Bean definition at the same time. Registered interface defines an abstract class defines the access, are concentrated in the beanDefinitionMap DefaultListableBeanFactory

Five, the test

1. Prepare

cn.bugstack.springframework.test.bean.UserService

public class UserService {

    public void queryUserInfo(a){
        System.out.println("Query user information"); }}Copy the code
  • A UserService object is simply defined to facilitate subsequent Spring container testing.

2. Test cases

cn.bugstack.springframework.test.ApiTest

@Test
public void test_BeanFactory(a){
    1. Initialize the BeanFactory
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // 2. Register the bean
    BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
    beanFactory.registerBeanDefinition("userService", beanDefinition);
    // 3. Get the bean for the first time
    UserService userService = (UserService) beanFactory.getBean("userService");
    userService.queryUserInfo();
    // get the bean from Singleton for the second time
    UserService userService_singleton = (UserService) beanFactory.getBean("userService");
    userService_singleton.queryUserInfo();
}
Copy the code
  • In addition to including; Bean factory, register Bean, get Bean, three steps, plus an additional object fetch and call. The main test here is to verify that the singleton is properly stored in the cache.
  • Also, unlike in the previous section, we passed userService.class to the BeanDefinition instead of the direct new UserService() operation as in the previous section.

3. Test results

Querying user information Querying user information Process finished with exit code0
Copy the code
  • There are two test messages, one for the object created directly when the Bean is fetched, and one for the instantiated object fetched from the cache.
  • In addition, it can be seen from the debugging screenshots that the second singleton object can be obtained from memory, as shown in Figure 3-3
  • To the functional realization and test verification of this chapter is completed, on the test process can go to the breakpoint debugging under each stage of the class call, familiar with the call relationship.

Six, summarized

  • Compared with the simple conceptual implementation of the Spring Bean container in the previous chapter, this chapter strengthens the perfection of functions. In the process of implementation can also see that the class relationship becomes more and more, if you have not done some slightly complex system class system, then even the present 9 classes out of the container factory can give you a halo.
  • In the implementation class of The Spring Bean container, we should focus on the responsibilities and relations between classes. Almost all the program function design is inseparable from interface, abstract class, implementation, inheritance, and the use of these different feature classes can be very good separated from the functional responsibilities and scope of the class. This knowledge is also very important in learning the process of writing the Spring Bean container framework.
  • Finally, I want to emphasize the learning of the whole series. It is possible to encounter very simple code implementation like chapter 2, but as a successful programmer, it is important to remember that code implementation is only the final implementation, and it is the design thinking that is most valuable.Like if you have ever met, someone asked you to make a description, document, description to a content, you always feel too simple there is nothing to write, even if you have to write also do not know where to start! In fact, this knowledge comes from your understanding of the overall functionality, which is not just code development but also requirements objectives, solution design, technical implementation, logical verification, and so on. So, don’t just be ignored by the seemingly simple content of the whole picture, to learn to open up your vision, open learning perspective.

Seven, series recommendation

  • “Spring masturbation column” introduction, I will take you to the Spring
  • Spring Bean IOC, AOP loop depends on interpretation
  • How do you become an architect when 90% of programmers have never used multithreading and locking?
  • For a long time, Little Brother Fu’s “Relearning Java Design Pattern” was finally published, color print & paper
  • | to SpringBoot middleware design and development, little nuggets of Fu Ge books online, this time to teach you rocket!