Spring容器的通俗理解及简单写法

Spring容器

Posted by chyuan on 2022-11-13
Estimated Reading Time 5 Minutes
Words 1.2k In Total

问题描述:

  1. 初学者新接触到Spring容器的时候,总是各种懵。
  2. 不知道对象为什么可以在想要的地方,直接@Autowired一下,就可以用。
  3. 这篇文章就是通俗的讲讲,如何做到用@Autowired就可以获得想要的对象。

先想一想为什么要引入Spring容器?

  1. 在实际的开发工作中,开发人员需要编写很多Class去完成一个功能的编写,完成一个事务的处理。
  2. 要使用一个Class去干活,我们先得new一个这个Class的实例对象对吧,会向JVM(Java Virtual Machine)申请空间,然后才可以执行Class中编写的非静态代码段。
  3. 如果没有Spring容器,那么每次new出来的对象干完活,是不是得释放掉呀,避免占用空间对吧。

那么问题就来了,这样重复的对常用的Class去new对象,去释放对象,反而不如就让这些常用的Class保留一个对象对系统的资源开销小。于是Spring容器,应运而生。就是为了解决此处的开发痛点而出现的。

Spring容器的通俗理解:

  1. Spring容器的实际作用,老师们都应该讲过,就是一个承装对象的东西。
  2. 具体点,比如:可以将Spring容器理解为一个工具箱,工具箱里面可以有锤子、钳子、扳手、卷尺等等。

其实Spring容器,也就主要干了三事情。

  1. 创建并保留对象实例。
  2. 给对象实例打上标记管理起来。
  3. 提供给外部通过实例对象的标记获取对象的接口。

实践,干!不怂:

下面来用简单的代码实现一个非常粗犷的Spring容器吧,跟着看一遍,就能懂了。

编码准备:

  1. java JDK1.8版本
  2. IDE工具,首选IntelliJ IDEA(这个要收费,有点小贵,当然破解的方法我是不会告诉你们的,我公开是支持正版的),或者Eclipse,不建议用MyEclipse

准备几个Class:

自定义注册注解:

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.demo.annotation;

import java.lang.annotation.*;

/**
* Created by CN94740284 on 2/9/2020.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyComponent {
}

自定义绑定注解:

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.demo.annotation;

import java.lang.annotation.*;

/**
* Created by CN94740284 on 2/9/2020.
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
}

注册和数据绑定器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/**
* Created by CN94740284 on 11/20/2020.
*/
public class Register {

private static Container container = new Container();

private static Container getContainer() {
return container;
}

private static boolean regist(Class<?> clzz){
Container container = Register.getContainer();
Map<String, Object> tools = container.getTools();
Object o = null;
try {
o = clzz.newInstance();
tools.put(clzz.getName(),o);
return true;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}

private static boolean myAutowired(){
Map<String, Object> tools = Register.getContainer().getTools();

tools.forEach((key,value)->{
Class<?> clzz = value.getClass();
Field[] fs = clzz.getDeclaredFields();
try {
bindFields(value, fs, tools);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});

return true;
}

public static <T> T getBean(Class<T> clzz){
Map<String, Object> tools = Register.getContainer().getTools();
T t = (T) tools.get(Test.class.getName());
return t;
}

private static boolean bindFields(Object obj,Field[] fields,Map<String, Object> tools) throws IllegalAccessException {
for (Field field : fields) {
//获取属性上T类型的注解
if(field.isAnnotationPresent(MyAutowired.class)) {
Class<?> type = field.getType();
Object tool = tools.get(type.getName());
if(tool!=null){
field.setAccessible(true);
field.set(obj,tool);
}else{
return false;
}
}
}
return true;
}

public static boolean registAndAutoBind(ScanFileTool t) {
t.findClassLocal(ScanFileTool.STARATEGY_PATH);
List<Class<? extends String>> eleStrategyList = t.getEleStrategyList();

// 注册对象
if(eleStrategyList!=null && eleStrategyList.size()>0){
eleStrategyList.forEach((clzz)->{
if(clzz.isAnnotationPresent(MyComponent.class)){
Register.regist(clzz);
}
});
}

// 绑定属性对象
Register.myAutowired();

return true;
}
}

使用@MyComponent注解:

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.demo.tools;

import com.example.demo.annotation.MyComponent;

/**
* Created by CN94740284 on 11/20/2020.
*/

@MyComponent
public class Hamer extends Tool {

}

准备抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.example.demo.tools;

import com.alibaba.fastjson.JSON;

/**
* Created by CN94740284 on 11/20/2020.
*/
public abstract class Tool {

public String getToolName() {
return getClass().getName();
}

@Override
public String toString() {
return JSON.toJSONString(this);
}
}

使用自定义注解@MyComponent注册,使用@MyAutowired绑定注入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.demo.tools.test;

import com.example.demo.annotation.MyAutowired;
import com.example.demo.annotation.MyComponent;
import com.example.demo.tools.Hamer;

/**
* Created by CN94740284 on 11/20/2020.
*/
@MyComponent
public class Test {

@MyAutowired
private Hamer hamer;

public void printHamerName(){
System.out.println("Test : "+hamer.getToolName());
}

}

以上方法和类的放心食用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.example.demo;

import com.example.demo.register.Register;
import com.example.demo.tools.test.Test;
import com.example.demo.utils.ScanFileTool;

import java.net.URISyntaxException;

public class DemoApplication {

public static void main(String[] args) throws URISyntaxException {

// 根据包路径扫描含有自定义注解的对象
ScanFileTool t = new ScanFileTool();

// 注册并绑定
boolean b = Register.registAndAutoBind(t);

// 类似SpringUtils.getBean
Test test = Register.getBean(Test.class);

// 调用对象方法
test.printHamerName();

}

}

流程如下:

1
2
3
graph TD
A[扫描包ScanFileTool] -- 注册 --> B[容器Map] -- 绑定 --> C[绑定对象] --> D[容器准备完毕] -- 根据类名 --> E[获取/使用对象]

相关代码下载链接:点此下载


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !