模拟SpringIoc实例化Bean对象

Bean实例化过程

  • 工厂类通过构造器行参传递要解析的xml配置文件
  • 解析配置文件,得到对应Bean标签的id和class属性值,生成MyBean对象集合
  • 实例化Bean对象,便利MyBean对象集合,通过class全类名反射实例,将实例保存到hashmap中
  • getBean方法,通过id获取从hashmap中获取实例化的Bean对象

引入依赖包

  • dom4j 用于解析xml文件
  • jaxen 用于xpath解析
pom.xml
1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- xpath -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>

创建dao类和service类,用来做测试

1
2
3
4
5
6
7
package org.example.dao;

public class UserDao {
public void test(){
System.out.println("UserDao ...");
}
}
1
2
3
4
5
6
7
package org.example.service;

public class UserService {
public void test(){
System.out.println("UserService ...");
}
}

创建bean配置文件

src/main 目录创建resources目录,并将 resources目录标记为资源目录,resources目录下创建 Bean 配置文件 spring.xml

spring.xml
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="userDao" class="org.example.dao.UserDao" />
<bean id="userService" class="org.example.service.UserService" />
</beans>

创建工厂接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example.factory;

/**
* 工厂模式
* 自定义工厂接口
*/
public interface MyFactory {
/**
* 获取Bean
* @param id Bean的Id
* @return
*/
public Object getBean(String id);
}

创建 Bean 对象类

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
package org.example.factory;

/**
* Bean属性对象
* 用来保存配置文件中的Bean标签的Id和class属性
*/
public class MyBean {
private String id;
private String clazz;

public MyBean() {
}

public MyBean(String id, String clazz) {
this.id = id;
this.clazz = clazz;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getClazz() {
return clazz;
}
}

创建接口工厂实现类

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
92
93
94
package org.example.factory;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 工厂接口实现类
* 1. 通过构造器行参传递要解析的xml配置文件
* 2. 解析配置文件,得到对应Bean标签的id和class属性值,生成MyBean对象集合
* 3. 实例化Bean对象,便利MyBean对象集合,通过class全类名反射实例,将实例保存到hashmap中
* 4. getBean方法,通过id获取从hashmap中获取实例化的Bean对象
*/
public class MyClassPathXmlApplication implements MyFactory{
// 存放实例化的Bean对象,key是Bean的id
private Map<String, Object> beanMap = new HashMap<String, Object>();
// 存放MyBean对象
private List<MyBean> beanList;

// 1. 通过构造器行参传递要解析的xml配置文件
public MyClassPathXmlApplication(String fileName) {
// 2. 解析配置文件
parseXml(fileName);

// 3. 实例化Bean对象
instanceBean();
}

// 2. 解析配置文件
private void parseXml(String fileName){
// 创建xml解析器
SAXReader reader = new SAXReader();
// 获取配置文件对应的Url
URL url = this.getClass().getClassLoader().getResource(fileName);
try {
// 解析配置文件,获取Document对象
Document document = reader.read(url);
// 创建xpath,用来获取获取beans标签下面的所有bean标签
XPath xpath = document.createXPath("beans/bean");
// 通过xpath获取bean标签集合
List<Element> elementList = xpath.selectNodes(document);
// 解析标签,生成MyBean对象
if(elementList != null && elementList.size() > 0){
this.beanList = new ArrayList();
for(Element element : elementList){
// 获取bean标签的id属性值
String id = element.attributeValue("id");
// 获取bean标签的class属性值
String clazz = element.attributeValue("class");
// 生成MyBean对象
MyBean myBean = new MyBean(id, clazz);
// 将MyBean对象存放到集合中
beanList.add(myBean);
}
}
}catch(Exception e){
e.printStackTrace();
}
}

// 3. 实例化Bean对象
private void instanceBean(){
if(beanList != null && beanList.size() > 0){
try {
for(MyBean myBean : beanList){
// 获取beanId
String id = myBean.getId();
// 获取bean全类名
String clazz = myBean.getClazz();

// 通过全类名反射实例化对象
Object obj = Class.forName(clazz).newInstance();

// 将实例化的bean存放到map中
beanMap.put(id, obj);
}
} catch (Exception e){
e.printStackTrace();
}
}
}

@Override
public Object getBean(String id) {
return beanMap.get(id);
}
}

测试运行

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

import org.example.dao.UserDao;
import org.example.factory.MyClassPathXmlApplication;
import org.example.factory.MyFactory;
import org.example.service.UserService;

public class Starter {
public static void main(String[] args) {
MyFactory factory = new MyClassPathXmlApplication("spring.xml");
UserService userService = (UserService)factory.getBean("userService");
userService.test();

UserDao userDao = (UserDao) factory.getBean("userDao");
userDao.test();
}
}