IoC
Ioc Is a simplified implementation version of the spring ioc core functionality for easy learning and understanding of principles.
Purpose of Creation
Spring has been used for a long time, very frequently for spring, and in fact has never been quiet about learning the source code.
However, one problem with the spring source is that it is too abstract, which increases the cost of learning.
So this project has evolved from a deep-rooted one, which only implements the core functions of spring and makes it easy for you and others to learn the core principles of spring.
Core of spring
The core of Spring is spring-beans, on which all the following spring-boot s, spring-cloud s, are built.
When someone asks you about spring, I hope you can talk about your own deeper insights into Sprioc, rather than just a few sentences from people online.
What is IOC
Inversion of Control (IoC) is a design principle in object-oriented programming that can be used to reduce the coupling between computer code.
The most common way is called Dependency Injection (DI).
By controlling inversion, when an object is created, a reference to the object on which it depends is passed to it by an external entity that controls all objects in the system.
Alternatively, dependencies are injected into the object.
Why IOC is needed
IoC is a decoupling method.
We know that Java is an object-oriented language. Everything is Object in Java. Our program consists of several objects.
As our projects grow and co-developers grow, our classes grow and references between classes grow exponentially.
Such a project would be a disaster if we introduced the Ioc framework.
A framework maintains the lifecycle of a class and references between classes.
Our system will become like this:
At this point we found that the IoC framework maintains the relationship between our classes and injects them into the required classes.
That is, the user of the class is only responsible for use, not maintenance.
Delegate professional work to a professional framework to complete, greatly reducing the complexity of development.
Quick Start
Introduction of maven
<dependency> <groupId>com.github.houbb</groupId> <artifactId>ioc</artifactId> <version>0.1.11</version> </dependency>
Test preparation
All test code, see the test module.
- Apple.java
public class Apple { public void color() { System.out.println("Apple color: red. "); } }
- apple.json
Similar to the xml configuration, we temporarily use json for configuration validation.
[ {"name":"apple","className":"com.github.houbb.ioc.test.service.Apple"} ]
Execute Tests
- test
BeanFactory beanFactory = new JsonApplicationContext("apple.json"); Apple apple = (Apple) beanFactory.getBean("apple"); apple.color();
- Journal
Apple color: red.
spring Basic Implementation Process
Explain
spring-beans is all about beans.
BeanFactory is responsible for managing the life cycle of bean s. This section shows the simple implementation process of the first section.
spring Core Process
Spring IoC consists mainly of the following steps.
-
Initialize the IoC container.
-
Read the configuration file.
-
Converts a configuration file to a data structure for container identification pairs (this data structure is called BeanDefinition in Spring)
-
Instantiate corresponding objects in turn using data structures
- Dependencies between injection objects
Abstraction of BeanDefinition
BeanDefinition is spring's abstraction of java bean properties, through which a configuration file can be either xml/json/properties/yaml or even an annotation sweep package.
This provides great flexibility for the expansion of spring.
Considering the simplicity of implementation, this framework initially implements only json and annotation-based sweep packages.
Later, if you have time to consider adding an implementation of xml, it is actually more XML parsing workload, the core process has been fully implemented.
Implement Source Selection
BeanDefinition correlation
Contains the basic information abstraction for Java beans.
- BeanDefinition.java
Its default implementation is DefaultBeanDefinition.java, which is the most basic java POJO to implement an interface
/** * Object Definition Properties * @author binbin.hou * @since 0.0.1 */ public interface BeanDefinition { /** * Name * @return Name * @since 0.0.1 */ String getName(); /** * Set Name * @param name Name * @since 0.0.1 */ void setName(final String name); /** * Class Name * @return Class Name */ String getClassName(); /** * Set Class Name * @param className Class Name * @since 0.0.1 */ void setClassName(final String className); }
BeanFactory Core Management Related
- BeanFactory.java
/** * bean Factory Interface * @author binbin.hou * @since 0.0.1 */ public interface BeanFactory { /** * Get the corresponding instance information by name * @param beanName bean Name * @return Object Information * @since 0.0.1 */ Object getBean(final String beanName); /** * Gets the implementation of the specified type * @param beanName Property Name * @param tClass type * @param <T> generic paradigm * @return Result * @since 0.0.1 */ <T> T getBean(final String beanName, final Class<T> tClass); }
- DefaultBeanFactory.java
For the most basic implementation of the interface, the source code is as follows:
/** * bean Factory Interface * @author binbin.hou * @since 0.0.1 */ public class DefaultBeanFactory implements BeanFactory { /** * Object Information map * @since 0.0.1 */ private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); /** * Object map * @since 0.0.1 */ private Map<String, Object> beanMap = new ConcurrentHashMap<>(); /** * Registered Object Definition Information * @since 0.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)) { // This returns a singleton directly, and if the user specifies multiple instances, a new one will be created each time. return bean; } // Get 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); // Here you can add the corresponding listener beanMap.put(beanName, newBean); return newBean; } /** * Creating objects from object definition information * @param beanDefinition Object Definition Information * @return Created object information * @since 0.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; } }
ClassUtils is a class-based reflection tool class, as detailed in ClassUtils.java
JsonApplicationContext
The basic implementation based on the json profile implementation is shown in the sample code for the start type.
- JsonApplicationContext.java
/** * JSON Application Context * @author binbin.hou * @since 0.0.1 */ public class JsonApplicationContext extends DefaultBeanFactory { /** * File Name * @since 0.0.1 */ private final String fileName; public JsonApplicationContext(String fileName) { this.fileName = fileName; // Initialize Configuration this.init(); } /** * Initialization configuration related information * * <pre> * new TypeReference<List<BeanDefinition>>(){} * </pre> * * Read the file: https://blog.csdn.net/feeltouch/article/details/83796764 * @since 0.0.1 */ private void init() { 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); } } } }
Summary
At this point, a basic spring ioc is basically implemented.
If you want to continue learning, you can refer to the following code branches separately.
Branch description
Basic implementation of v0.0.1-BeanFactory
Basic implementation of v0.0.2-ListBeanFactory
v0.0.3 - Singleton and Delayed Loading
v0.0.4 - Initialization and destruction methods
v0.0.5-RespCode Add and Code Optimization
v0.0.6-Constructor and factoryMethod New Object
v0.0.7-property property settings
v0.0.8-Aware listener and PostProcessor
v0.0.9-Parent attribute inheritance
v0.1.0 - Cyclic Dependency Detection
v0.1.1-@Configuration-java code configuration
v0.1.2-@Bean-java object definition
v0.1.3-@Lazy-@Scope-java object property configuration
v0.1.4-@Import Configuration Import
v0.1.5-@Bean parameter construction and @Description
v0.1.6-@Autowired Auto-assembly Annotation Support
v0.1.7-@Primary Specify Priority Note
v0.1.8-@Conditional Conditional Annotation Support
v0.1.9-Environment and @Profile implementation
v0.1.10-Property profile related and @Value/@PropertyResource implementation
v0.1.11-@ComponentScan package scanning support