Manually use the Spring framework, design and implement resource loader, parse and register Bean objects from Spring.xml


Author: Xiao Fu Ge
Blog: https://bugstack.cn

Precipitate, share, and grow, so that you and others can gain something! ๐Ÿ˜„

I. Introduction

ไฝ ๅ†™็š„ไปฃ็ ๏ผŒ่ƒฝๆŽฅ็š„ไฝไบงๅ“ๅŠ ้œ€ๆฑ‚ๅ—๏ผŸ

It can be connected, and it can be connected several times, even if...else of one type is okay! But it is not certain what the connection is completed, and whether an accident will occur is not controllable.

When that accident, you say that because I write if ... else more lead to code rotten, but but you first move the hand ah: ไฝ ่ฏด็š„้œ€ๆฑ‚่ฟ˜ๅพ—ๅŠ , , ไฝ ่ฏด็š„่€ๆฟ่ฎฉไธŠ็บฟ, ไฝ ่ฏด็š„ๅˆๅŒ้ƒฝ็ญพไบ†moving bricks yard farmers I can not, just to pile the code level demand, demand is too It's not easy, I just used to move bricks to level the demand! If the princes refuse to accept, I will serve them with soldiers. If you refuse, I will beat you to serve!

But sometimes the code is rotten, not because of the need to increase the speed, nor is it anxious to go online. Because often in the first few times of undertaking product requirements, the design of a functional logic will not be too complicated, and there will be no urgency. It will even set aside time for you to design, review, and develop. If you still canโ€™t do this at this time Evaluate what may happen in the future into the requirements, then the chaos caused by the code has been buried from the beginning, and it can only become more and more chaotic in the future!

Accepting requirements and being able to do it well is the result of comprehensive factors such as understanding of requirements, experience in product scenario development, and ability to control code practices. Just like in the development you are doing now, which of your code changes frequently, which is fixed and common, which is responsible for logical assembly, and which is for core implementation. So now if your core shared layer has frequently changed business layer packaging, then it is certain that your code will become more and more messy, and it may even bury the risk of accidents!

In the Spring framework we implemented, each chapter will be combined with the previous chapter to continue to expand the function, just like every product is adding requirements, then in the process of learning, you can link the comparison and reference of the previous and the next, take a look at each module What logic and technical details are used to achieve the addition. The learning of these contents will be very beneficial to your future design and implementation. When you undertake the specific development of the product requirements, the quality of the code will become higher and higher, and it will become more and more scalable and maintainable.

2. Goal

After completing the prototype of the Spring framework, we can now manually operate the definition, registration and attribute filling of the Bean object through unit testing, and finally obtain the object call method. But there is a problem here, that is, if you actually use this Spring framework, it is unlikely that users can create it manually, but it is best to simplify the creation process through configuration files. Need to complete the following operations:

  • As shown in the figure, we need to integrate the steps: 2, 3, 4 into the Spring framework, and instantiate the Bean object through the Spring configuration file.
  • Next, we need to add operations that can solve Spring configuration reading, parsing, and registering Beans in the existing Spring framework.

Three, design

According to the requirements background of this chapter, we need to add a resource parser to the existing Spring framework prototype, which is able to read the configuration content of the classpath, local files and cloud files. These configuration contents are like Spring.xml configured when using Spring, which will include the description and attribute information of the Bean object. After reading the configuration file information, the next step is to perform the registration operation after parsing the Bean description information in the configuration file, and register the Bean object in the Spring container. The overall design structure is as follows:

  • The resource loader is a relatively independent part. It is located in the IO implementation content of the Spring framework core package and is mainly used to process file information in Class, local and cloud environments.
  • When the resource can be loaded, the next step is to parse and register the Bean into Spring. This part of the implementation needs to be combined with the DefaultListableBeanFactory core class, because all your parsed registration actions will put the Bean definition information into this class in.
  • So when the implementation will achieve good design hierarchy interface, including a read interface we need to define the definition of Bean BeanDefinitionReaderand make corresponding implementation class, complete resolution and registration of the objects in the Bean implementation class.

Fourth, realize

1. Engineering structure

small-spring-step-05
โ””โ”€โ”€ src
    โ”œโ”€โ”€ main
    โ”‚   โ””โ”€โ”€ java
    โ”‚       โ””โ”€โ”€ cn.bugstack.springframework  
    โ”‚           โ”œโ”€โ”€ beans
    โ”‚           โ”‚   โ”œโ”€โ”€ factory
    โ”‚           โ”‚   โ”‚   โ”œโ”€โ”€ factory
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AutowireCapableBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ BeanDefinition.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ BeanReference.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ ConfigurableBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ SingletonBeanRegistry.java
    โ”‚           โ”‚   โ”‚   โ”œโ”€โ”€ support
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AbstractAutowireCapableBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AbstractBeanDefinitionReader.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ AbstractBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ BeanDefinitionReader.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ BeanDefinitionRegistry.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CglibSubclassingInstantiationStrategy.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DefaultListableBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ DefaultSingletonBeanRegistry.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InstantiationStrategy.java
    โ”‚           โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ SimpleInstantiationStrategy.java  
    โ”‚           โ”‚   โ”‚   โ”œโ”€โ”€ support
    โ”‚           โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ XmlBeanDefinitionReader.java
    โ”‚           โ”‚   โ”‚   โ”œโ”€โ”€ BeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”œโ”€โ”€ ConfigurableListableBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ”œโ”€โ”€ HierarchicalBeanFactory.java
    โ”‚           โ”‚   โ”‚   โ””โ”€โ”€ ListableBeanFactory.java
    โ”‚           โ”‚   โ”œโ”€โ”€ BeansException.java
    โ”‚           โ”‚   โ”œโ”€โ”€ PropertyValue.java
    โ”‚           โ”‚   โ””โ”€โ”€ PropertyValues.java 
    โ”‚           โ”œโ”€โ”€ core.io
    โ”‚           โ”‚   โ”œโ”€โ”€ ClassPathResource.java 
    โ”‚           โ”‚   โ”œโ”€โ”€ DefaultResourceLoader.java 
    โ”‚           โ”‚   โ”œโ”€โ”€ FileSystemResource.java 
    โ”‚           โ”‚   โ”œโ”€โ”€ Resource.java 
    โ”‚           โ”‚   โ”œโ”€โ”€ ResourceLoader.java 
    โ”‚           โ”‚   โ””โ”€โ”€ UrlResource.java
    โ”‚           โ””โ”€โ”€ utils
    โ”‚               โ””โ”€โ”€ ClassUtils.java
    โ””โ”€โ”€ test
        โ””โ”€โ”€ java
            โ””โ”€โ”€ cn.bugstack.springframework.test
                โ”œโ”€โ”€ bean
                โ”‚   โ”œโ”€โ”€ UserDao.java
                โ”‚   โ””โ”€โ”€ UserService.java
                โ””โ”€โ”€ ApiTest.java

Project source code :ๅ…ฌไผ—ๅทใ€Œbugstack่™ซๆดžๆ ˆใ€๏ผŒๅ›žๅค๏ผšSpring ไธ“ๆ ๏ผŒ่Žทๅ–ๅฎŒๆ•ดๆบ็ 

Spring Bean container resource loading and usage class relationship, as shown in Figure 6-3

Figure 6-3
  • In order to be able to define this section of Bean, registration and initialization to Spring.xml configuration process, you will need to achieve two blocks of content, namely: resource loader, xml resource handling classes, mainly in the implementation process of the interface Resource, ResourceLoaderthe implemented, while the other BeanDefinitionReaderinterfaces is the specific use of resources, the configuration information registered to Spring container.
  • The implementation of Resource's resource loader includes ClassPath, system files, and cloud configuration files. These three parts are consistent with the design and implementation in the Spring source code, and finally make specific calls in DefaultResourceLoader.
  • Interface: BeanDefinitionReader, abstract class: AbstractBeanDefinitionReader, implementation class: XmlBeanDefinitionReader, these three parts mainly deal with the operation of the registered Bean container after the resource is read in a reasonable and clear manner. Interface management definition, abstract class handles the filling of registered Bean components outside of non-interface functions, and the final realization class can only care about the specific business realization

In addition, this chapter also refers to the Spring source code and makes the relationship between the integration and implementation of the corresponding interfaces. Although these interfaces are not very useful at present, they will also play a role as the framework is gradually improved. As shown in Figure 6-4

Figure 6-4
  • BeanFactory, the existing Bean factory interface is used to obtain Bean objects, this time a new method for obtaining Beans by type has been added:<T> T getBean(String name, Class<T> requiredType)
  • ListableBeanFactory, it is an extension of the interface Bean factory interface, a new addition getBeansOfType, getBeanDefinitionNames()the method, in Spring source there are other extension methods.
  • HierarchicalBeanFactory, in the Spring source code, it provides a method to obtain the parent class BeanFactory, which is a hierarchical sub-interface that extends the factory. Sub-interface implemented by bean factories that can be part of a hierarchy.
  • AutowireCapableBeanFactory is an interface for automatically processing Bean factory configuration. At present, the corresponding implementation has not been done in the case project, and it will be gradually improved in the follow-up.
  • ConfigurableBeanFactory can obtain a configurable interface of BeanPostProcessor, BeanClassLoader, etc.
  • ConfigurableListableBeanFactory provides an interface for analyzing and modifying Beans and pre-instantiated operations, but currently there is only one getBeanDefinition method.

2. Resource loading interface definition and implementation

cn.bugstack.springframework.core.io.Resource

public interface Resource {

    InputStream getInputStream() throws IOException;

}
  • Create the core.io core package under the Spring framework, which is mainly used to handle the resource loading flow.
  • Define the Resource interface, provide a method to obtain the InputStream stream, and then implement three different stream file operations: classPath, FileSystem, URL

ClassPath : cn.bugstack.springframework.core.io.ClassPathResource

public class ClassPathResource implements Resource {

    private final String path;

    private ClassLoader classLoader;

    public ClassPathResource(String path) {
        this(path, (ClassLoader) null);
    }

    public ClassPathResource(String path, ClassLoader classLoader) {
        Assert.notNull(path, "Path must not be null");
        this.path = path;
        this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    }

    @Override
    public InputStream getInputStream() throws IOException {
        InputStream is = classLoader.getResourceAsStream(path);
        if (is == null) {
            throw new FileNotFoundException(
                    this.path + " cannot be opened because it does not exist");
        }
        return is;
    }
}
  • This section is used to realize by ClassLoaderreading the ClassPathfile information in the specific read process are:classLoader.getResourceAsStream(path)

FileSystem : cn.bugstack.springframework.core.io.FileSystemResource

public class FileSystemResource implements Resource {

    private final File file;

    private final String path;

    public FileSystemResource(File file) {
        this.file = file;
        this.path = file.getPath();
    }

    public FileSystemResource(String path) {
        this.file = new File(path);
        this.path = path;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new FileInputStream(this.file);
    }

    public final String getPath() {
        return this.path;
    }

}
  • Reading file information by specifying the file path, this part is definitely familiar to everyone, and often read some txt, excel files and output them to the console.

Url : cn.bugstack.springframework.core.io.UrlResource

public class UrlResource implements Resource{

    private final URL url;

    public UrlResource(URL url) {
        Assert.notNull(url,"URL must not be null");
        this.url = url;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        URLConnection con = this.url.openConnection();
        try {
            return con.getInputStream();
        }
        catch (IOException ex){
            if (con instanceof HttpURLConnection){
                ((HttpURLConnection) con).disconnect();
            }
            throw ex;
        }
    }

}
  • To read the files of the cloud service through HTTP, we can also put the configuration files on GitHub or Gitee.

3. Packaging Resource Loader

According to the different ways of resource loading, the resource loader can concentrate these methods under a unified class service for processing, and external users only need to pass the resource address, which simplifies the use.

Define the interface : cn.bugstack.springframework.core.io.ResourceLoader

public interface ResourceLoader {

    /**
     * Pseudo URL prefix for loading from the class path: "classpath:"
     */
    String CLASSPATH_URL_PREFIX = "classpath:";

    Resource getResource(String location);

}
  • Define the resource acquisition interface and pass the location address inside.

Implementation interface : cn.bugstack.springframework.core.io.DefaultResourceLoader

public class DefaultResourceLoader implements ResourceLoader {

    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        if (location.startsWith(CLASSPATH_URL_PREFIX)) {
            return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()));
        }
        else {
            try {
                URL url = new URL(location);
                return new UrlResource(url);
            } catch (MalformedURLException e) {
                return new FileSystemResource(location);
            }
        }
    }

}
  • In the realization of resource acquisition, three different types of resource processing methods are mainly packaged, which are divided into: judging whether it is ClassPath, URL, and file.
  • Although the implementation process of the DefaultResourceLoader class is simple, it is also the specific result of the design pattern agreement. For example, the external caller will not know too many details here, but only care about the specific call result.

4. Bean definition read interface

cn.bugstack.springframework.beans.factory.support.BeanDefinitionReader

public interface BeanDefinitionReader {

    BeanDefinitionRegistry getRegistry();

    ResourceLoader getResourceLoader();

    void loadBeanDefinitions(Resource resource) throws BeansException;

    void loadBeanDefinitions(Resource... resources) throws BeansException;

    void loadBeanDefinitions(String location) throws BeansException;

}
  • This is a Simple interface for bean definition readers. In fact, it defines several methods, including: getRegistry(), getResourceLoader(), and three methods for loading bean definitions.
  • It should be noted here that getRegistry() and getResourceLoader() are tools used to provide the following three methods, loading and registering, and the implementation of these two methods will be packaged in abstract classes to avoid polluting specific interface implementation methods.

5. Bean definition abstract class implementation

cn.bugstack.springframework.beans.factory.support.AbstractBeanDefinitionReader

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {

    private final BeanDefinitionRegistry registry;

    private ResourceLoader resourceLoader;

    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this(registry, new DefaultResourceLoader());
    }

    public AbstractBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        this.registry = registry;
        this.resourceLoader = resourceLoader;
    }

    @Override
    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    @Override
    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }

}
  • The abstract class implements all the first two methods of the BeanDefinitionReader interface and provides a constructor for external callers to inject the Bean definition into the class and pass it in.
  • In this way, in the specific implementation class of the interface BeanDefinitionReader, the Bean information in the parsed XML file can be registered to the Spring container. In the past, we used it through unit testing, calling BeanDefinitionRegistry to complete the registration of the Bean, and now we can put it in XMl for operation

6. Parse XML and handle Bean registration

cn.bugstack.springframework.beans.factory.xml.XmlBeanDefinitionReader

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        super(registry, resourceLoader);
    }

    @Override
    public void loadBeanDefinitions(Resource resource) throws BeansException {
        try {
            try (InputStream inputStream = resource.getInputStream()) {
                doLoadBeanDefinitions(inputStream);
            }
        } catch (IOException | ClassNotFoundException e) {
            throw new BeansException("IOException parsing XML document from " + resource, e);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource... resources) throws BeansException {
        for (Resource resource : resources) {
            loadBeanDefinitions(resource);
        }
    }

    @Override
    public void loadBeanDefinitions(String location) throws BeansException {
        ResourceLoader resourceLoader = getResourceLoader();
        Resource resource = resourceLoader.getResource(location);
        loadBeanDefinitions(resource);
    }

    protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
        Document doc = XmlUtil.readXML(inputStream);
        Element root = doc.getDocumentElement();
        NodeList childNodes = root.getChildNodes();

        for (int i = 0; i < childNodes.getLength(); i++) {
            // ๅˆคๆ–ญๅ…ƒ็ด 
            if (!(childNodes.item(i) instanceof Element)) continue;
            // ๅˆคๆ–ญๅฏน่ฑก
            if (!"bean".equals(childNodes.item(i).getNodeName())) continue;
            
            // ่งฃๆžๆ ‡็ญพ
            Element bean = (Element) childNodes.item(i);
            String id = bean.getAttribute("id");
            String name = bean.getAttribute("name");
            String className = bean.getAttribute("class");
            // ่Žทๅ– Class๏ผŒๆ–นไพฟ่Žทๅ–็ฑปไธญ็š„ๅ็งฐ
            Class<?> clazz = Class.forName(className);
            // ไผ˜ๅ…ˆ็บง id > name
            String beanName = StrUtil.isNotEmpty(id) ? id : name;
            if (StrUtil.isEmpty(beanName)) {
                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
            }

            // ๅฎšไน‰Bean
            BeanDefinition beanDefinition = new BeanDefinition(clazz);
            // ่ฏปๅ–ๅฑžๆ€งๅนถๅกซๅ……
            for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
                if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
                if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
                // ่งฃๆžๆ ‡็ญพ๏ผšproperty
                Element property = (Element) bean.getChildNodes().item(j);
                String attrName = property.getAttribute("name");
                String attrValue = property.getAttribute("value");
                String attrRef = property.getAttribute("ref");
                // ่Žทๅ–ๅฑžๆ€งๅ€ผ๏ผšๅผ•ๅ…ฅๅฏน่ฑกใ€ๅ€ผๅฏน่ฑก
                Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;
                // ๅˆ›ๅปบๅฑžๆ€งไฟกๆฏ
                PropertyValue propertyValue = new PropertyValue(attrName, value);
                beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
            }
            if (getRegistry().containsBeanDefinition(beanName)) {
                throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
            }
            // ๆณจๅ†Œ BeanDefinition
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }
    }

}

The core content of the XmlBeanDefinitionReader class is the parsing of XML files, which puts our original operation in the code into a way of automatic registration by parsing XML.

  • The loadBeanDefinitions method handles resource loading. Here is a new internal method:, doLoadBeanDefinitionswhich is mainly responsible for parsing xml
  • In doLoadBeanDefinitions method, xml mainly for reading XmlUtil.readXML(inputStream)and parsing of Element. In the process of parsing, the Bean configuration and the id, name, class, value, and ref information in the configuration are obtained by looping operations.
  • Finally, the read configuration information is created into BeanDefinition and PropertyValue, and finally the complete Bean definition content is registered in the Bean container:getRegistry().registerBeanDefinition(beanName, beanDefinition)

Five, test

1. Prepare in advance

cn.bugstack.springframework.test.bean.UserDao

public class UserDao {

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

    static {
        hashMap.put("10001", "ๅฐๅ‚…ๅ“ฅ");
        hashMap.put("10002", "ๅ…ซๆฏๆฐด");
        hashMap.put("10003", "้˜ฟๆฏ›");
    }

    public String queryUserName(String uId) {
        return hashMap.get(uId);
    }

}

cn.bugstack.springframework.test.bean.UserService

public class UserService {

    private String uId;

    private UserDao userDao;

    public void queryUserInfo() {
        return userDao.queryUserName(uId);
    }

    // ...get/set
}
  • Dao and Service are the scenes we often use in our usual development. Inject UserDao into UserService, so that the dependency of Bean attributes can be reflected.

2. Configuration file

important.properties

# Config File
system.key=OLpj9823dZ

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <bean id="userDao" class="cn.bugstack.springframework.test.bean.UserDao"/>

    <bean id="userService" class="cn.bugstack.springframework.test.bean.UserService">
        <property name="uId" value="10001"/>
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>
  • There are two configuration files, one is used to test the resource loader, and spring.xml is used to test the overall Bean registration function.

3. Unit testing (resource loading)

Case study

private DefaultResourceLoader resourceLoader;      

@Before
public void init() {
    resourceLoader = new DefaultResourceLoader();
}   

@Test
public void test_classpath() throws IOException {
    Resource resource = resourceLoader.getResource("classpath:important.properties");
    InputStream inputStream = resource.getInputStream();
    String content = IoUtil.readUtf8(inputStream);
    System.out.println(content);
}   

@Test
public void test_file() throws IOException {
    Resource resource = resourceLoader.getResource("src/test/resources/important.properties");
    InputStream inputStream = resource.getInputStream();
    String content = IoUtil.readUtf8(inputStream);
    System.out.println(content);
}    

@Test
public void test_url() throws IOException {
    Resource resource = resourceLoader.getResource("https://github.com/fuzhengwei/small-spring/important.properties"
    InputStream inputStream = resource.getInputStream();
    String content = IoUtil.readUtf8(inputStream);
    System.out.println(content);
}

Test Results

# Config File
system.key=OLpj9823dZ

Process finished with exit code 0
  • These three methods: test_classpath, test_file, and test_url are used to test and load ClassPath, FileSystem, and Url files respectively. The URL file is on Github and may be slow to load.

4. Unit testing (configuration file registration bean)

Case study

@Test
public void test_xml() {
    // 1.ๅˆๅง‹ๅŒ– BeanFactory
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

    // 2. ่ฏปๅ–้…็ฝฎๆ–‡ไปถ&ๆณจๅ†ŒBean
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    reader.loadBeanDefinitions("classpath:spring.xml");

    // 3. ่Žทๅ–Beanๅฏน่ฑก่ฐƒ็”จๆ–นๆณ•
    UserService userService = beanFactory.getBean("userService", UserService.class);
    String result = userService.queryUserInfo();
    System.out.println("ๆต‹่ฏ•็ป“ๆžœ๏ผš" + result);
}

Test Results

ๆต‹่ฏ•็ป“ๆžœ๏ผšๅฐๅ‚…ๅ“ฅ

Process finished with exit code 0
  • You can see in the above test case, we manually registered before Bean configuration and content attribute information, to the new XmlBeanDefinitionReader(beanFactory)class to read Spring.xml way to deal with, and passed the test validation.

Six, summary

  • The project structure at this time has become more and more of the flavor of the Spring framework. The configuration file is used as the entrance to parse and register the Bean information, and finally the Bean is obtained through the Bean factory and the corresponding invocation operations are performed.
  • Regarding the implementation of each step in the case, Brother Xiao will refer to the interface definition, abstract class implementation, name specification, code structure, etc. of the Spring source code as much as possible, and do the corresponding simplification. In this way, you can learn the Spring source code through the class name or interface and the entire structure during the learning process, so that it is much easier to learn.
  • After reading it, it is definitely not equal to knowing it. You can only really master the knowledge in it when you start from a small project frame structure and continue to grow bigger, more, and stronger now and in the future. In addition, the functional realization of each chapter will involve a lot of code design ideas, which should be carefully understood. Of course, practice is the best way to understand!

Seven, series recommendation