【学习笔记】动手实现IOC和AOP

一、实现IOC

IOC用于解决程序之间的耦合关系。

1. 建立配置文件和相应的Bean

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@AllArgsConstructor
@NoArgsConstructor
public class A {
private String name;
}
@NoArgsConstructor
@AllArgsConstructor
@Data
public class B {
private A a;
}
1
2
3
4
5
6
7
8
<beans>
<bean name="A" class="com.windranger.basic.ioc.A">
<property name="name" value="tom"/>
</bean>
<bean name="B" class="com.windranger.basic.ioc.B">
<property name="a" ref="A"/>
</bean>
</beans>

2.读取配置

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
public class ConfigManager {
// 1. 读取配置文件,并返回数据
public static Map<String, Bean> getConfig(String path) {
// 0. 创建一个Map对象,存放数据
HashMap<String, Bean> hashMap = new HashMap<>();
// 1. 创建解析器
SAXReader reader = new SAXReader();
// 2. 加载配置文件==>document对象
InputStream inputStream = ConfigManager.class.getClassLoader().getResourceAsStream(path);
Document doc = null;
try {
doc = reader.read(inputStream);
} catch (DocumentException e) {
e.printStackTrace();
throw new RuntimeException("不存在该配置文件");
}
// 3. 定义xpath表达式,取出所有Bean元素
List<Element> list = doc.selectNodes("/beans/bean");
// 4. 对Bean进行遍历
list.forEach(element -> {
// 4.1 将Bean的name/class 属性封装到Bean中
Bean bean = new Bean();
String name = element.attributeValue("name");
bean.setName(name);
bean.setClassName(element.attributeValue("class"));
// 4.2 将Bean中的Property封装
List<Element> children = element.elements("property");
List<Property> properties = new ArrayList<>();
children.forEach(child -> {
Property property = new Property();
property.setName(child.attributeValue("name"));
property.setValue(child.attributeValue("value"));
property.setRef(child.attributeValue("ref"));
properties.add(property);
});
bean.setProperties(properties);
// 4.3 将Bean封装到Map中
hashMap.put(name, bean);
});
// 5. 返回Map结果
return hashMap;
}
}

3. 建立Bean的属性类

1
2
3
4
5
6
7
8
9
10
11
12
13
@Data
public class Bean {
private String name;
private String className;
private List<Property> properties = new ArrayList<>();
}

@Data
class Property {
private String name;
private String ref;
private String value;
}

4.建立接口

1
2
3
4
public interface BeanFactory {
// 获取Bean数据
Object getBean(String beanName);
}

5.建立ioc容器

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
87
88
89
90
91
public class ClassPathXmlApplicationContext implements BeanFactory {

/**
* config:配置文件
* context:Spring容器
*/
private Map<String, Bean> config;
private Map<String, Object> context = new HashMap<>();

public ClassPathXmlApplicationContext(String path) {
// 1. 读取配置文件获取需要初始化的Bean信息
config = ConfigManager.getConfig(path);
// 2. 遍历配置初始化Bean
config.forEach((beanName, bean) -> {
// 获取配置中Bean信息
if (context.get(beanName) == null) {
// 根据Bean配置创建bean对象
Object obj = createBean(bean);
// 3. 将初始化好的Bean放入容器中
context.put(beanName, obj);
}
});
}

private Object createBean(Bean bean) {
// 1. 获取要创建的Bean的class
String className = bean.getClassName();
Class cls = null;
Object obj = null;
// 1. 获得class,并反射创建出来
try {
cls = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("classBean配置错误");
}
try {
obj = cls.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException("无空参构造");
}
// 2. 注入bean的属性
Object finalObj = obj;
bean.getProperties().forEach(property -> {
String name = property.getName();
if (property.getValue() != null) {
// 简单的注入,直接注入值。
String value = property.getValue();
// 根据属性名称,获得属性的set方法
BeanUtils.getWriteMethod(finalObj, name, value);
}
if (property.getRef() != null) {
Object existBean = context.get(property.getRef());
if (existBean == null) {
// 不存在则创建
existBean = createBean(config.get(property.getRef()));
// 将创建好的bean放入容器中
context.put(property.getRef(), existBean);
}

// 根据属性名称,获得属性的set方法
BeanUtils.getWriteMethod(finalObj, name, existBean);
}
});
return obj;
}

@Override
public Object getBean(String beanName) {
return context.get(beanName);
}
}
class BeanUtils {
public static void getWriteMethod(Object object, String name, Object value) {
Class cls = object.getClass();
Field field = null;
try {
field = cls.getDeclaredField(name);
} catch (NoSuchFieldException e) {
e.printStackTrace();
throw new RuntimeException("没有该属性");
}
field.setAccessible(true);
try {
field.set(object, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}

6.测试类

1
2
3
4
5
6
7
8
9
public class Test {
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
A a = (A) factory.getBean("A");
System.out.println(a);
B b = (B) factory.getBean("B");
System.out.println(b);
}
}