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.
-
Initialize the IoC container.
-
Read the configuration file.
-
Convert the configuration file to a data structure (called BeanDefinition in Spring) that the container recognizes
-
The corresponding objects are instantiated in turn using data structures
-
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