Blog: bugstack.cn

Precipitation, share, grow, let yourself and others can gain something! πŸ˜„

“Spring Manual column” directory

  • Chapter 1:Introduction, I will take you to Spring!
  • Chapter 2:Try to achieve a simple Bean container
  • Chapter 3:Initial skill, the use of design pattern, the implementation of Bean definition, registration, access
  • Chapter 4:Budding class instantiation strategy with constructors based on Cglib
  • Chapter 5:A blockbuster feature implementation for injecting properties into Bean objects and relying on beans
  • Chapter 6: To be filed…

One, foreword

Oversold, dropped, idempotent, your program is always beating!

Think about it, the operation has publicized the activities for seven or eight days, full of joy waiting for the last day of the page online, suddenly appeared a bunch of abnormalities, capital loss, flash back, and the user flow is fleeting, finally want to die heart!

Will tell with regard to programming development, forgetful, gibberish code seven bad, probably this is the true portraitory of daily development of major primary programmer, in even if have test personnel to verify the circumstance, also can appear the phenomenon that takes Bug to go on line, just be did not discover at that time just! Because people write code, there are bound to be mistakes, even old code farmers

In terms of program Bug, will include product Bug for the PRD to gain more on the process, operating configuration activities when bugs, r&d development functions of bugs, test validation miss process of bugs, configuration Bug related to the operations in the process of online services, which in fact can be drawn up by the process specification and certain research and development experience, slowly to reduce as much as possible.

Bug, and the other one is communication usually business demand, product do implementation scheme, research and development, finally have the UI, test and operation, architecture and so on each link of the personnel involved in a project to undertake, development to online operation, in which a group of people need to maintain a unified information transmission is very difficult. For example, in the middle of the project development, the operation said a new requirement to the product, and the product felt that the function was not big, so it immediately found the corresponding front-end research and development and added a logic, but did not expect that it might also affect the back-end development and test use cases. Finally, although the function is on the line, but not in the scope of the demand coverage of the whole production and research, also buried a pit invisible.

So, if you want your program to be punch-resistant and take three punches from a farmer, you need to be more than just a brick yard remover!

Second, the target

First, let’s review what we have accomplished in these chapters: implementing a container, defining and registering beans, instantiating beans, and implementing different instantiation strategies depending on whether or not we include constructors. What is missing in creating object instantiations? In fact, there is a lack of an attribute in the class, if the class contains attributes, the instantiation needs to fill in the attribute information, so that a complete object creation.

The population of properties, not only ints, longs, and Strings, but also object properties that have not yet been instantiated, needs to be populated at Bean creation time. However, we will not consider the cyclic dependency of beans for the time being, otherwise the whole function implementation will be extended, which will be difficult for newcomers to grasp when learning, and the core functions will be gradually improved after the implementation of the core functions

Three, the design

Given the attribute is used in Bean filling newInstance or additional created, began to completion attribute information, you can in the class AbstractAutowireCapableBeanFactory createBean method completion attribute is added. This part we can also compare Spring source code learning in the process of practice, the implementation here is a simplified version of Spring, the follow-up comparison study will be easier to understand

  • Property population is required after class instantiation creation, i.eAbstractAutowireCapableBeanFactoryTo the createBean methodapplyPropertyValuesOperation.
  • Since we need to populate property operations at Bean creation time, we need to add PropertyValues information to the Bean definition BeanDefinition class.
  • In addition, the filling property information also includes the object type of the Bean, that is, a BeanReference needs to be defined, which is actually a simple Bean name, which can be created and filled recursively during the specific instantiation operation, just like the Spring source implementation.Spring source BeanReference is an interface

Four, implementation,

1. Engineering structure

small-spring-step-04β”” ─ ─ the SRC β”œ ─ ─ the main β”‚ β”” ─ ─ Java β”‚ β”” ─ ─ cn. Bugstack. Springframework. Beans β”‚ β”œ ─ ─ factory β”‚ β”‚ β”œ ─ ─ factory β”‚ β”‚ β”‚ β”œ ─ ─ BeanDefinition. Java β”‚ β”‚ β”‚ β”œ ─ ─ BeanReference. Java β”‚ β”‚ β”‚ β”” ─ ─ SingletonBeanRegistry. Java β”‚ β”‚ β”œ ─ ─ support β”‚ β”‚ β”‚ β”œ ─ ─ AbstractAutowireCapableBeanFactory. Java β”‚ β”‚ β”‚ β”œ ─ ─ AbstractBeanFactory. Java β”‚ β”‚ β”‚ β”œ ─ ─ BeanDefinitionRegistry. Java β”‚ β”‚ β”‚ β”œ ─ ─ CglibSubclassingInstantiationStrategy. Java β”‚ β”‚ β”‚ β”œ ─ ─ DefaultListableBeanFactory. Java β”‚ β”‚ β”‚ β”œ ─ ─ DefaultSingletonBeanRegistry. Java β”‚ β”‚ β”‚ β”œ ─ ─ InstantiationStrategy. Java β”‚ β”‚ β”‚ β”” ─ ─ SimpleInstantiationStrategy. Java β”‚ β”‚ β”” ─ ─ the BeanFactory. Java β”‚ β”œ ─ ─ BeansException. Java β”‚ β”œ ─ ─ PropertyValue. Java β”‚ β”” ─ ─ PropertyValues. Java β”” ─ ─ the test β”” ─ ─ Java β”” ─ ─ Cn. Bugstack. Springframework. Test β”œ ─ ─ bean β”‚ β”œ ─ ─ UserDao. Java β”‚ β”” ─ ─ UserService. Java β”” ─ ─ ApiTest. JavaCopy the code

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

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

  • Three new classes need to be added in this chapter.BeanReferenceClass reference,PropertyValue(Attribute value),PropertyValuesProperty collection, respectively, for class and other type property population operations.
  • The other major changes to the class areAbstractAutowireCapableBeanFactoryTo complete the property fill section in createBean.

2. Define properties

cn.bugstack.springframework.beans.PropertyValue

public class PropertyValue {

    private final String name;

    private final Object value;

    public PropertyValue(String name, Object value) {
        this.name = name;
        this.value = value;
    }
    
    / /... get/set
}
Copy the code

cn.bugstack.springframework.beans.PropertyValues

public class PropertyValues {

    private final List<PropertyValue> propertyValueList = new ArrayList<>();

    public void addPropertyValue(PropertyValue pv) {
        this.propertyValueList.add(pv);
    }

    public PropertyValue[] getPropertyValues() {
        return this.propertyValueList.toArray(new PropertyValue[0]);
    }

    public PropertyValue getPropertyValue(String propertyName) {
        for (PropertyValue pv : this.propertyValueList) {
            if (pv.getName().equals(propertyName)) {
                returnpv; }}return null; }}Copy the code
  • The purpose of these two classes is to create a class that passes information about attributes in the class. Since there may be many attributes, you need to define a collection wrapper.

3. Bean definition completion

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

public class BeanDefinition {

    private Class beanClass;

    private PropertyValues propertyValues;

    public BeanDefinition(Class beanClass) {
        this.beanClass = beanClass;
        this.propertyValues = new PropertyValues();
    }

    public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
        this.beanClass = beanClass;
        this.propertyValues = propertyValues ! =null ? propertyValues : new PropertyValues();
    }
    
    / /... get/set
}
Copy the code
  • Information about the Bean needs to be passed during the Bean registration process, as shown in the tests in several previous chaptersnew BeanDefinition(UserService.class, propertyValues);
  • So to ensure that the properties are assigned to the Bean definition, we fill in the PropertyValues property and make some simple optimizations to the two constructors to avoid having to determine if the property is empty later in the for loop.

4. Bean property population

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

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
        Object bean = null;
        try {
            bean = createBeanInstance(beanDefinition, beanName, args);
            // Populate the Bean with properties
            applyPropertyValues(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }

        addSingleton(beanName, bean);
        return bean;
    }

    protected Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {
        Constructor constructorToUse = null; Class<? > beanClass = beanDefinition.getBeanClass(); Constructor<? >[] declaredConstructors = beanClass.getDeclaredConstructors();for (Constructor ctor : declaredConstructors) {
            if (null! = args && ctor.getParameterTypes().length == args.length) { constructorToUse = ctor;break; }}return getInstantiationStrategy().instantiate(beanDefinition, beanName, constructorToUse, args);
    }

    /**
     * Bean ε±žζ€§ε‘«ε……
     */
    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        try {
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {

                String name = propertyValue.getName();
                Object value = propertyValue.getValue();

                if (value instanceof BeanReference) {
                    // A relies on B to get an instantiation of B
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                // Attribute populationBeanUtil.setFieldValue(bean, name, value); }}catch (Exception e) {
            throw new BeansException("Error setting property values:"+ beanName); }}public InstantiationStrategy getInstantiationStrategy(a) {
        return instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy; }}Copy the code
  • This class is a bit longer and consists of three methods: CreateBean, createBeanInstance, applyPropertyValues. Here we focus on the applyPropertyValues method called in the createBean method.
  • In applyPropertyValues, by obtainingbeanDefinition.getPropertyValues()Loop through the property population, and if a BeanReference is encountered, you need to recursively get the Bean instance and call the getBean method.
  • When the dependent Bean object is created, it recursively returns to the property population. It is important to note that we are not dealing with cyclic dependencies, which will be covered later in a larger section.Beanutil.setfieldvalue (bean, name, value) is a method in the Hutool-all utility class, which you can also implement yourself

Five, the test

1. Prepare

cn.bugstack.springframework.test.bean.UserDao

public class UserDao {

    private static Map<String, String> hashMap = new HashMap<>();

    static {
        hashMap.put("10001".Little Fuge.);
        hashMap.put("10002"."Eight glasses of water");
        hashMap.put("10003"."Will");
    }

    public String queryUserName(String uId) {
        returnhashMap.get(uId); }}Copy the code

cn.bugstack.springframework.test.bean.UserService

public class UserService {

    private String uId;

    private UserDao userDao;

    public void queryUserInfo(a) {
        System.out.println("Query user information:" + userDao.queryUserName(uId));
    }

    / /... get/set
}
Copy the code
  • Dao and Service are common development scenarios. Inject the UserDao into the UserService so that the Bean property dependencies are reflected.

2. Test cases

@Test
public void test_BeanFactory(a) {
    1. Initialize the BeanFactory
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();  

    // 2. Register the UserDao
    beanFactory.registerBeanDefinition("userDao".new BeanDefinition(UserDao.class));   

    // 3. UserService sets attributes [uId, userDao]
    PropertyValues propertyValues = new PropertyValues();
    propertyValues.addPropertyValue(new PropertyValue("uId"."10001"));
    propertyValues.addPropertyValue(new PropertyValue("userDao".new BeanReference("userDao")));  

    // 4. UserService injects the bean
    BeanDefinition beanDefinition = new BeanDefinition(UserService.class, propertyValues);
    beanFactory.registerBeanDefinition("userService", beanDefinition);    

    // 5. UserService retrieves the bean
    UserService userService = (UserService) beanFactory.getBean("userService");
    userService.queryUserInfo();
}
Copy the code
  • Instead of getting the Bean object directly, this time we also need to inject the userDao into the Bean container first.beanFactory.registerBeanDefinition("userDao", new BeanDefinition(UserDao.class));
  • The next step is the operation of property filling, one is the general propertynew PropertyValue("uId", "10001")The other is object propertiesnew PropertyValue("userDao",new BeanReference("userDao"))
  • The next step is to simply get the userService object as normal and call the method.

3. Test results

Query user information: Process finished with exit code0
Copy the code
  • From our test results, we can see that our property population is working, because only after the property is populated can Dao methods be called, such as userDao. QueryUserName (uId)

  • So let’s see if we have entered the implementation Bean property population in the case of debugging, as follows:

    • In this screenshot, we can see that the property population operation has started. When the property is found to be a BeanReference, we need to obtain the create Bean instance.

Six, summarized

  • In this chapter we create the object function of the AbstractAutowireCapableBeanFactory class and expanded, depends on whether there is a structural function, after the completion of the instantiation of the strategy to add Bean attribute information. Recursive processing is required when a Bean property is encountered as a Bean object. Finally, reflection is needed for attribute filling, which can also be handled with some utility classes.
  • We have implemented the function points of each chapter step by step, so that new people can better accept the design ideas in Spring. Especially in some already developed classes, how to extend the new functionality of the design is more important. Learning to program sometimes learning to design ideas can improve programming thinking more than just doing simple implementations.
  • In this chapter, the Bean creation operation is developed. Next, we need to complete the loading of resource attributes on the basis of the whole framework. That is, we need to move the Xml configuration, so that our small framework is more and more like Spring. In addition, all the class names in the framework implementation process will refer to Spring source code, and the corresponding design and implementation steps are also corresponding to Spring source code, but it will simplify some of the process, but you can take the same class name, to search for each function in Spring source code implementation.

Seven, series recommendation

  • “Spring masturbation column” chapter 1: Introduction, I will take you to the Spring!
  • Small fu ge, a “sideline” code farmers!
  • How do I stuff a Bean into a Spring container?
  • How many lines of code do I have to write after college to get a development job without spending money on training?
  • Math, how close is it to a programmer?