Skip to content

Commit 8704706

Browse files
committed
更新ioc
1 parent cb2fcb7 commit 8704706

2 files changed

Lines changed: 290 additions & 1 deletion

File tree

‎ioc/3.myioc.md‎

Lines changed: 288 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,300 @@
55

66
首先设计接口,一个IOC容器中最核心的当属容器接口,来一个Container。
77

8-
那么容器里应该有什么呢,我想它至少要有存储和移除一个对象的能力。
8+
那么容器里应该有什么呢,我想它至少要有存储和移除一个对象的能力,其次可以含括更多的获取和注册对象的方法。
99

10+
```java
11+
/**
12+
* IOC容器
13+
* @author biezhi
14+
*
15+
*/
16+
public interface Container {
17+
18+
/**
19+
* 根据Class获取Bean
20+
* @param clazz
21+
* @return
22+
*/
23+
public <T> T getBean(Class<T> clazz);
24+
25+
/**
26+
* 根据名称获取Bean
27+
* @param name
28+
* @return
29+
*/
30+
public <T> T getBeanByName(String name);
31+
32+
/**
33+
* 注册一个Bean到容器中
34+
* @param object
35+
*/
36+
public Object registerBean(Object bean);
37+
38+
/**
39+
* 注册一个Class到容器中
40+
* @param clazz
41+
*/
42+
public Object registerBean(Class<?> clazz);
43+
44+
/**
45+
* 注册一个带名称的Bean到容器中
46+
* @param name
47+
* @param bean
48+
*/
49+
public Object registerBean(String name, Object bean);
50+
51+
/**
52+
* 删除一个bean
53+
* @param clazz
54+
*/
55+
public void remove(Class<?> clazz);
56+
57+
/**
58+
* 根据名称删除一个bean
59+
* @param name
60+
*/
61+
public void removeByName(String name);
62+
63+
/**
64+
* @return 返回所有bean对象名称
65+
*/
66+
public Set<String> getBeanNames();
67+
68+
/**
69+
* 初始化装配
70+
*/
71+
public void initWrited();
72+
}
73+
```
74+
75+
那么我写一个简单的实现代码:
76+
77+
```java
78+
/**
79+
* 容器简单实现
80+
* @author biezhi
81+
*/
82+
@SuppressWarnings("unchecked")
83+
public class SampleContainer implements Container {
84+
85+
/**
86+
* 保存所有bean对象,格式为 com.xxx.Person : @52x2xa
87+
*/
88+
private Map<String, Object> beans;
89+
90+
/**
91+
* 存储bean和name的关系
92+
*/
93+
private Map<String, String> beanKeys;
94+
95+
public SampleContainer() {
96+
this.beans = new ConcurrentHashMap<String, Object>();
97+
this.beanKeys = new ConcurrentHashMap<String, String>();
98+
}
99+
100+
@Override
101+
public <T> T getBean(Class<T> clazz) {
102+
String name = clazz.getName();
103+
Object object = beans.get(name);
104+
if(null != object){
105+
return (T) object;
106+
}
107+
return null;
108+
}
109+
110+
@Override
111+
public <T> T getBeanByName(String name) {
112+
Object object = beans.get(name);
113+
if(null != object){
114+
return (T) object;
115+
}
116+
return null;
117+
}
118+
119+
@Override
120+
public Object registerBean(Object bean) {
121+
String name = bean.getClass().getName();
122+
beanKeys.put(name, name);
123+
beans.put(name, bean);
124+
return bean;
125+
}
126+
127+
@Override
128+
public Object registerBean(Class<?> clazz) {
129+
String name = clazz.getName();
130+
beanKeys.put(name, name);
131+
Object bean = ReflectUtil.newInstance(clazz);
132+
beans.put(name, bean);
133+
return bean;
134+
}
135+
136+
@Override
137+
public Object registerBean(String name, Object bean) {
138+
String className = bean.getClass().getName();
139+
beanKeys.put(name, className);
140+
beans.put(className, bean);
141+
return bean;
142+
}
143+
144+
@Override
145+
public Set<String> getBeanNames() {
146+
return beanKeys.keySet();
147+
}
148+
149+
@Override
150+
public void remove(Class<?> clazz) {
151+
String className = clazz.getName();
152+
if(null != className && !className.equals("")){
153+
beanKeys.remove(className);
154+
beans.remove(className);
155+
}
156+
}
157+
158+
@Override
159+
public void removeByName(String name) {
160+
String className = beanKeys.get(name);
161+
if(null != className && !className.equals("")){
162+
beanKeys.remove(name);
163+
beans.remove(className);
164+
}
165+
}
166+
167+
@Override
168+
public void initWrited() {
169+
Iterator<Entry<String, Object>> it = beans.entrySet().iterator();
170+
while (it.hasNext()) {
171+
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) it.next();
172+
Object object = entry.getValue();
173+
injection(object);
174+
}
175+
}
176+
177+
/**
178+
* 注入对象
179+
* @param object
180+
*/
181+
public void injection(Object object) {
182+
// 所有字段
183+
try {
184+
Field[] fields = object.getClass().getDeclaredFields();
185+
for (Field field : fields) {
186+
// 需要注入的字段
187+
AutoWrited autoWrited = field.getAnnotation(AutoWrited.class);
188+
if (null != autoWrited) {
189+
190+
// 要注入的字段
191+
Object autoWritedField = null;
192+
193+
String name = autoWrited.name();
194+
if(!name.equals("")){
195+
String className = beanKeys.get(name);
196+
if(null != className && !className.equals("")){
197+
autoWritedField = beans.get(className);
198+
}
199+
if (null == autoWritedField) {
200+
throw new RuntimeException("Unable to load " + name);
201+
}
202+
} else {
203+
if(autoWrited.value() == Class.class){
204+
autoWritedField = recursiveAssembly(field.getType());
205+
} else {
206+
// 指定装配的类
207+
autoWritedField = this.getBean(autoWrited.value());
208+
if (null == autoWritedField) {
209+
autoWritedField = recursiveAssembly(autoWrited.value());
210+
}
211+
}
212+
}
213+
214+
if (null == autoWritedField) {
215+
throw new RuntimeException("Unable to load " + field.getType().getCanonicalName());
216+
}
217+
218+
boolean accessible = field.isAccessible();
219+
field.setAccessible(true);
220+
field.set(object, autoWritedField);
221+
field.setAccessible(accessible);
222+
}
223+
}
224+
} catch (SecurityException e) {
225+
e.printStackTrace();
226+
} catch (IllegalArgumentException e) {
227+
e.printStackTrace();
228+
} catch (IllegalAccessException e) {
229+
e.printStackTrace();
230+
}
231+
}
232+
233+
private Object recursiveAssembly(Class<?> clazz){
234+
if(null != clazz){
235+
return this.registerBean(clazz);
236+
}
237+
return null;
238+
}
239+
240+
}
241+
```
242+
243+
这里将所有Bean的名称存储在 `beanKeys` 这个map中,将所有的对象存储在 `beans` 中,用 `beanKeys` 维护名称和对象的关系。
244+
245+
在装配的时候步骤如下:
246+
247+
1. 判断是否使用了自定义命名的对象(是:根据name查找bean)
248+
2. 判断是否使用了Class类型Bean(是:根据Class查找Bean,如果查找不到则创建一个无参构造函数的Bean)
249+
250+
下面是一个测试:
10251

11252
```java
253+
public class IocTest {
254+
255+
private static Container container = new SampleContainer();
256+
257+
public static void baseTest(){
258+
container.registerBean(Lol.class);
259+
// 初始化注入
260+
container.initWrited();
261+
262+
Lol lol = container.getBean(Lol.class);
263+
lol.work();
264+
}
265+
266+
public static void iocClassTest(){
267+
container.registerBean(Lol2.class);
268+
// 初始化注入
269+
container.initWrited();
270+
271+
Lol2 lol = container.getBean(Lol2.class);
272+
lol.work();
273+
}
274+
275+
public static void iocNameTest(){
276+
container.registerBean("face", new FaceService2());
277+
container.registerBean(Lol3.class);
278+
// 初始化注入
279+
container.initWrited();
280+
281+
Lol3 lol = container.getBean(Lol3.class);
282+
lol.work();
283+
}
284+
285+
public static void main(String[] args) {
286+
baseTest();
287+
//iocClassTest();
288+
//iocNameTest();
289+
}
290+
291+
}
292+
```
293+
294+
输出结果:
12295

296+
```sh
297+
剑圣买了5毛钱特效,装逼成功!
13298
```
14299

300+
[代码出处](https://github.com/junicorn/easy-ioc/tree/master/src/test/java/com/junicorn/ioc/test)
301+
15302
## links
16303
* [目录](<index.md>)
17304
* 上一节: [Spring中怎么用](<2.spring.md>)

‎ioc/index.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
IOC是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、微信号...(balabala),想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个,或者从 `JNDI` 中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。
66
下面的章节带你理解并实现一个IOC容器。
77

8+
IOC源码:[https://github.com/junicorn/easy-ioc](https://github.com/junicorn/easy-ioc)
9+
810
## 目录
911

1012
* [IOC的概念](1.concept.md)

0 commit comments

Comments
 (0)