IoC

Ioc is a simplified implementation of Spring’S core Ioc functions, making it easy to learn and understand the principles.

Writing purpose

Use Spring for a long time, the use of Spring is very frequent, in fact, for the source code has not calmed down to learn.

One problem with Spring source code, however, is that it is too abstract, making it expensive to learn.

Therefore, this project will only implement the core functions of Spring, which will make it easier for myself and others to learn the core principles of Spring.

The core of the spring

The core of Spring is spring-beans, and everything spring-boot and spring-cloud is built on this foundation.

When people ask you about Spring, I hope you can talk about your own deeper insight into Spring IOC, rather than a few words echoed by others on the Internet.

What is the IOC

Inversion of Control (IoC) is a design principle used in object-oriented programming to reduce coupling between computer code.

The most common of these is called Dependency Injection (DI).

With inversion of control, when an object is created, it is passed references to the objects it depends on by an external entity that regulates all objects in the system.

In other words, dependencies are injected into objects.

Why IOC is needed

IoC is one approach to decoupling.

We know that Java is an object-oriented language. In Java, Everything is Object. Our program is made up of several objects.

As our projects get bigger and we work with more and more developers, we have more and more classes, and the number of references between classes grows exponentially.

Such a project would be a disaster if we introduced the Ioc framework.

The life cycle of classes and references between classes are maintained by the framework.

Our system would look like this:

At this point, we found that the relationships between our classes were being maintained by the IoC framework and injected into the required classes.

That is, the user of the class is only responsible for its use, not its maintenance.

Putting professional tasks in the hands of professional frameworks greatly reduces the complexity of development.

Quick start

Maven is introduced into

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>ioc</artifactId>
    <version>0.1.11</version>
</dependency>
Copy the code

Test preparation

For the full test code, see the Test module.

  • Apple.java
public class Apple {

    public void color(a) {
        System.out.println("Apple color: red. "); }}Copy the code
  • apple.json

For an XML-like configuration, we temporarily use JSON for configuration validation.

[{"name":"apple"."className":"com.github.houbb.ioc.test.service.Apple"}]Copy the code

Perform the test

  • test
BeanFactory beanFactory = new JsonApplicationContext("apple.json");
Apple apple = (Apple) beanFactory.getBean("apple");
apple.color();
Copy the code
  • The log
Apple color: red.
Copy the code

Spring basic implementation process

instructions

Spring-beans is all about beans.

BeanFactory is responsible for managing the lifecycle of beans. This section shows a simple implementation of the first section.

Spring Core Processes

Spring IoC consists of the following steps.

  1. Initialize the IoC container.

  2. Read the configuration file.

  3. Convert the configuration file to a data structure (called BeanDefinition in Spring) that the container recognizes

  4. The corresponding objects are instantiated in turn using data structures

  5. Dependencies between injection objects

The abstract BeanDefinition

BeanDefinition is spring’s abstraction of Java bean properties. At this level of abstraction, configuration files can be either XML/JSON/Properties/YAML or even annotated sweep packages.

Brings great flexibility to spring extensions.

This framework takes into account the simplicity of the implementation, the initial implementation of JSON and annotation-based scanning package two ways.

Later, if there is time to consider adding XML implementation, in fact, it is more XML parsing workload, the core process has been fully implemented.

Implement source selection

BeanDefinition related

Contains basic information abstractions for Java beans.

  • BeanDefinition.java

The default implementation for DefaultBeanDefinition. Java, is the implementation of the basic Java POJO

See DefaultBeanDefinition

/** * Object definition properties *@author binbin.hou
 * @since0.0.1 * /
public interface BeanDefinition {

    /** * Name *@returnName *@since0.0.1 * /
    String getName(a);

    /** * Set name *@paramName the name *@since0.0.1 * /
    void setName(final String name);

    /** * Class name *@returnThe class name * /
    String getClassName(a);

    /** * Set class name *@paramClassName className *@since0.0.1 * /
    void setClassName(final String className);

}
Copy the code

BeanFactory core management related

  • BeanFactory.java
/** * Bean factory interface *@author binbin.hou
 * @since0.0.1 * /
public interface BeanFactory {

    /** * Obtain the corresponding instance information by name *@paramBeanName Bean name *@returnObject information@since0.0.1 * /
    Object getBean(final String beanName);

    /** * Get the implementation of the specified type *@paramBeanName Attribute name *@paramTClass type *@param< T > generic *@returnResults *@since0.0.1 * /
    <T> T getBean(final String beanName, final Class<T> tClass);

}
Copy the code
  • DefaultBeanFactory.java

For the most basic implementation of the interface, the source code is as follows:

/** * Bean factory interface *@author binbin.hou
 * @since0.0.1 * /
public class DefaultBeanFactory implements BeanFactory {

    /** * Object information map *@since0.0.1 * /
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /** * Object map *@since0.0.1 * /
    private Map<String, Object> beanMap = new ConcurrentHashMap<>();

    /** * Register object definition information *@since0.0.1 * /
    protected void registerBeanDefinition(final String beanName, final BeanDefinition beanDefinition) {
        // You can add listeners here
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    public Object getBean(String beanName) {
        Object bean = beanMap.get(beanName);
        if(ObjectUtil.isNotNull(bean)) {
            // If the user specifies multiple singletons, the singletons need to be created each time.
            return bean;
        }

        // Obtain the corresponding configuration information
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(ObjectUtil.isNull(beanDefinition)) {
            throw new IocRuntimeException(beanName + " not exists in bean define.");
        }

        // Direct basis
        Object newBean = createBean(beanDefinition);
        // You can add the corresponding listener
        beanMap.put(beanName, newBean);
        return newBean;
    }

    /** * Create an object based on the object definition information@paramBeanDefinition Object definition information *@returnInformation about the created object *@since0.0.1 * /
    private Object createBean(final BeanDefinition beanDefinition) {
        String className = beanDefinition.getClassName();
        Class clazz = ClassUtils.getClass(className);
        return ClassUtils.newInstance(clazz);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getBean(String beanName, Class<T> tClass) {
        Object object = getBean(beanName);
        return(T)object; }}Copy the code

ClassUtils is a class-based reflection utility class. For details, see classutils.java

JsonApplicationContext

Json configuration file based on the implementation of the basic implementation, use the way to see the beginning of the example code.

  • JsonApplicationContext.java
/** * JSON application context *@author binbin.hou
 * @since0.0.1 * /
public class JsonApplicationContext extends DefaultBeanFactory {

    /** * File name *@since0.0.1 * /
    private final String fileName;

    public JsonApplicationContext(String fileName) {
        this.fileName = fileName;

        // Initial configuration
        this.init();
    }

    ** <pre> * new TypeReference<List<BeanDefinition>>(){} * </pre> https://blog.csdn.net/feeltouch/article/details/83796764 *@since0.0.1 * /
    private void init(a) {
        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
        final String jsonConfig = FileUtil.getFileContent(is);
        List<DefaultBeanDefinition> beanDefinitions = JsonBs.deserializeArray(jsonConfig, DefaultBeanDefinition.class);
        if(CollectionUtil.isNotEmpty(beanDefinitions)) {
            for (BeanDefinition beanDefinition : beanDefinitions) {
                super.registerBeanDefinition(beanDefinition.getName(), beanDefinition); }}}}Copy the code

summary

At this point, a basic Spring IOC is basically implemented.

If you want to continue, you can refer to the following code branches separately.

Branch instructions

V0.0.1-beanfactory basic implementation

V0.0.2 -ListBeanFactory basic implementation

V0.0.3 – Singletons and lazy loading

V0.0.4 – Initialization and destruction methods

V0.0.5 -RespCode added and code optimized

V0.0.6 – Constructor and factoryMethod create objects

V0.0.7-property Property setting

V0.0.8 -Aware listener and PostProcessor

V0.0.9 -Parent property inheritance

V0.1.0 – Cyclic dependency detection

v0.1.1-@Configuration-java Code Configuration

v0.1.2-@Bean-java Object Definitions

v0.1.3-@Lazy- @scope – Java object properties configuration

v0.1.4-@Import Configuration Import

v0.1.5-@Bean parameter construct and @description

v0.1.6-@Autowired Automatic assembly annotation support

v0.1.7-@Primary Specifies a priority annotation

v0.1.8-@Conditional Conditional annotations are supported

V0.1.9 -Environment and @profile implementation

V0.1.10 -Property profile related and @value / @propertyResource implementation

v0.1.11-@ComponentScan Package scanning is supported

Develop reading

What is Java IOC-00-IOC