Goal lead &
Benpian is "now I guess Spring-Boot" series, the first two (Oh, I actually have written a 10, really is not easy).
In the last article, we achieved Bean created, but only to create it, did not really realize the injection of Bean. So this today, we are going to achieve the bean automatically injected.
We have previously defined in the project SimpleService
and SimpleController
these two categories, then this article, we want to SimpleService
automatically injected into the SimpleController
middle;
SimpleController.java
@Service
public class SimpleController {
@Autowired
private SimpleService simpleService;
public SimpleController(){
System.out.println("the controller is created!");
}
}
Because there is just a console program, no way to call and show genuine, so I SimpleService
add an output that represents the uniqueness of this class. In this way, SimpleService
it becomes like this:
SimpleService.java
@Service
public class SimpleService {
private String serviceId ;
public SimpleService(){
serviceId= UUID.randomUUID().toString();
System.out.println("the service :"+serviceId+"is created!");
}
public String getServiceId(){
return this.serviceId;
}
}
Although now have to call, there is no way to verify our ideas.
Altogether, we will count on the meter, we add a PostContruct
comment now :)
SimpleController.java
public class SimpleController{
// other code
@PostContruct
public void init(){
System.out.println("the service id is :"+this.simpleService.getServiceId());
}
}
Dependency injection needs analysis
Our goal by the change program, we can see that the pair of major changes in the following points:mini-boot
Definitions
PostConstruct
andAutowired
In
Autowired
marked, dependency injectionWith
PostContruct
marked realize Bean created in automatic initialization
3 is intuitive to target this time we want to achieve, however, due between us is too simple design, we have a problem to solve, namely:
We need a place to store, find has already raw bean!
Then the problem is clearly more important than 1,2,3 strip, so
The foregoing digging, later filled pit
Our goal becomes:
Achieve storage and management of Bean
Definitions
PostConstruct
andAutowired
In
Autowired
marked, dependency injectionWith
PostContruct
marked realize Bean created in automatic initialization
Step 0 Bean storage and management of
In Spring, obtained from bean next external mode:
Dependency injection or by other means to give
ApplicationContext
By obtaining the corresponding bean.
ApplicationContext.getBean
By these two, it is obvious:
We also like a photo
ApplicationContext
And by this logic to get the bean class name or class, obviously a map like this, us.
ApplicationContext
Become very good realization:
ApplicationContext.java
package com.github.yfge.miniboot.context;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
public class ApplicationContext {
private Map<String,Object> beanMap ;
public ApplicationContext(){
beanMap=new LinkedHashMap<>();
}
public void addBean( Object ob){
this.beanMap.put(ob.getClass().getName(),ob);
}
public Object getBean(String beanName){
return this.beanMap.get(beanName);
}
public Object getBean(Class beanClass){
return this.beanMap.get(beanClass.getName());
}
}
Ah, with the ApplicationContext
later, we can use a applicationContext all the bean are saved while generating bean. At this time, our function has a little bit of change:Application.loadBeans
Application.loadBeans
public class Application{
// other code
private static void LoadBeans(Class source) {
ClassUtils util = new ClassUtils();
List<String> classNames = util.loadClass(source);
/** 实例化一个context **/
ApplicationContext applicationContext = new ApplicationContext();
for (String name : classNames) {
try {
var classInfo = Class.forName(name);
/**
* 检查是否声明了@Service
**/
if (classInfo.getDeclaredAnnotation(Service.class) != null) {
/**
* 得到默认构造函数
*/
var constructor = classInfo.getConstructor();
if (constructor != null) {
/**
* 创建实例
*/
var obj = constructor.newInstance();
/** 保存bean**/
applicationContext.addBean(obj);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
//other code
}
It can be seen at this time of change is still small, we are just at the beginning of the initialization of a context, then after the bean is generated, stored in the context of the bean
OK, hold bean functional complete (just previous pit filled it), our next step is to begin formal work.
Step1 defined Annotation
Previously analyzed, we need to define Autowired
and PostContruct
two notes are very simple, you can do some statement:
Autowired.java
package com.github.yfge.miniboot.autoconfigure;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}
PostConstruct.java
package com.github.yfge.miniboot.autoconfigure;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface PostConstruct {
}
Also note that we are here to add this line, the specific features and differences, we will look for opportunities to explain (again digging, not digging uncomfortable group)@Retention(RetentionPolicy.RUNTIME)
Step2 to @Autowired marked, dependency injection
Ah, we want to be the most exciting part, and dependency injection, that is, we want to SimpleService
automatically injected into the SimpleController
middle.
But ....
Everything has a very matter of course, but what good double Cheese Li excited? We have to do nothing more than:
Put all taken out of context in the bean;
To give a reflection of each field bean;
Check this field has not added autowird comment;
If so, check this field type is not a bean;
If so, the assignment taken out by reflection;
Because we are using a storage Map performed, it can be combined into two steps 4 and 5:
4-5 Press this field to get the type of bean, if not empty, it is assigned.
Because we want to clear, coherent nature codes, i.e. increasing injection logic behind this:Application.loadBeans
Application.loadBeans
public class Application {
/**
* 加载相应的bean(Service)
*
* @param source
*/
private static void LoadBeans(Class source) {
//other code
//上面是之前的逻辑
/** 注入bean **/
for (Object ob : applicationContext.getAllBeans()) {
var classInfo = ob.getClass();
for (var field : classInfo.getDeclaredFields()) {
if (field.getDeclaredAnnotation(Autowired.class) != null) {
field.setAccessible(true);
var filedBean = applicationContext.getBean(field.getType());
if (filedBean != null) {
try {
field.set(ob, filedBean);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
//other code
}
At the same time, we added a new method for the ApplicationContext, to get all the bean
ApplicationContext.java
public class ApplicationContext {
//other code
public Collection<Object> getAllBeans(){
return this.beanMap.values();
}
}
Note that there is a point that we Applicaton.loadBeans cycle twice:
The first is to generate and store the bean
The second is to assign all bean taken out, dried in the form of injection for each dependency bean
The reason for this are obvious:
In order to ensure that when injected can get what we want bean, must be processed after all the bean generates
Step3 @PostConstruct marked to achieve the initialization process automatically run
To the previous step, in fact, our dependency injection has been completed, but due to the current of our framework is too simple, there is no way to validate our success.mini-boot
So, here we are passing mechanism will also realize what @PostContruct, after automatic initialization class that is loaded.
With the step of the work, you will find that this time we work very stylized and tasteless, namely:
Put all taken out of context in the bean;
Each of the bean to give a reflection method ;
Check this method has not added PostContruct comment;
If so, using this method of performing reflective ;
You will have noticed, here I have some standard fonts are thick, the reason is because the standard thick: 1-4 Here is my copy from the top down, just mark the thick part of the change .
Now that the realization of ideas can be copied, then the code has become very easy.
Application.loadBeans
public class Application {
/**
* 加载相应的bean(Service)
*
* @param source
*/
private static void LoadBeans(Class source) {
//other code
//上面是之前的逻辑
//包括
//1. 生成所有的bean并存储
//2. 遍历已经生成的bean进行依赖注入
/** 执行初始化方法 **/
for (Object ob : applicationContext.getAllBeans()) {
var classInfo = ob.getClass();
if (classInfo.getDeclaredAnnotation(Service.class) != null) {
for (var method : classInfo.getDeclaredMethods()) {
if (method.getDeclaredAnnotation(PostConstruct.class) != null) {
try {
method.invoke(ob);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}
// other code
}
OK, now compile the project, execution, you will see the following output:
the controller is created!
the service :580fbd69-d82b-44b6-847a-b4c5cbc4d97b is created!
the service Id is :580fbd69-d82b-44b6-847a-b4c5cbc4d97b
The Mini-Boot Application Is Run! The Name is Hello
This output:
The first line is automatically created controller
When the second row of the table service is automatically created and the unique id is xxxx
The third line is the output of our controller in the init function, you can see where service has not empty, and that is automatically created between us!
In other words:
We have implemented a simple automatic injection as expected
We also expect to achieve in accordance with a simple automatic operation initialization function
Now, quietly Recall from our article, is there some doors have been opened to you
other
Not to share the source code bullying!
So, our project address is: https: //github.com/yfge/mini-boot due, with the release of the article, the code will be constantly updated, so, tag this chapter is : article-02
(forgive me a name of Level)
Abduction lean on old
Free-range program ape, wild lion architecture
Second-rate workers moving bricks, third-rate photographer
Prudish than funny, installed two forced literary reality
So, that being a public number, there will be code, scripts, there are beauties, have chicken soup, anyway, chaos seventy-eight was, chances are which just hit on its hands of it to your
What is not said, scan code to focus on it