首先回顾一下我在前面章节提到的内容:
开发,从需求出发 · 之四 春天在这里
我们离spring的内容只有一步之遥,正如前文所说:
private static Map<String, String> appBean = new HashMap<String, String>();
private static Map<String, String[]> appRef = new HashMap<String, String[]>();
static {
appBean.put("luceneDAO", "cn.com.sitefromscrath.dao.LuceneDAOMock");
appBean.put("mysqlDAO", "cn.com.sitefromscrath.dao.MysqlDAOMock");
appBean.put("searchService", "cn.com.sitefromscrath.service.SearchServiceInRealBiz");
appRef.put("searchService", new String[]{"luceneDAO", "mysqlDAO"});
}
请比较和spring.xml的区别:
<?xml version="1.0" encoding="UTF-8"?>
<beans >
<bean id="luceneDAO" class="cn.com.sitefromscrath.dao.LuceneDAOMock" />
<bean id="mysqlDAO" class="cn.com.sitefromscrath.dao.MysqlDAOMock" />
<bean id="searchService" class="cn.com.sitefromscrath.service.SearchServiceInRealBiz">
<constructor-arg index="1" ref="luceneDAO" />
<constructor-arg index="2" ref="mysqlDAO" />
</bean>
</beans>
好吧,没什么根本上的区别, 我们同样能够解析xml,得到我们自己实现的BeanFactory所需要的一切要素。
由于有前一章的基础,我们只需要调用实现的 XmlParser进行整合就可以了:)
请遵守另一个原则,“不要想太多,从最简单的实现”入手。
我们其实需要的仅仅是一个 适配器,Adaptor。
让我们通过代码硬编码赋值进去的内容变成 首先解析xml,然后再赋值给:
private static Map<String, String> appBean = new HashMap<String, String>();
private static Map<String, String[]> appRef = new HashMap<String, String[]>();
由此,先得到方法:
public static void fillAppInitParams(Node root){
for(int i = 0; i < root.getChildren().size(); i++) {
Node bean = (Node) root.getChildren().get(i);
String id = bean.getAttributes().get("id");
String clazz = bean.getAttributes().get("class");
appBean.put(id, clazz);
if(!bean.getChildren().isEmpty()) {
List<String> refs = new ArrayList<String>();
for(int k = 0; k < bean.getChildren().size(); k++) {
Node arg = (Node)bean.getChildren().get(k);
refs.add(arg.getAttributes().get("ref"));
}
appRef.put(id, refs.toArray(new String[0]));
}
}
}
然后,读取xml,解析,然后将获得的根节点传入:
public static void init() {
try {
XmlParser xmlParser = new XmlParser();
InputStream is = xmlParser.getClass().getResourceAsStream("./test.xml");
DomTree dt = xmlParser.build(is);
is.close();
fillAppInitParams(dt.getRoot());
} catch (Exception e) {
e.printStackTrace();
}
}
最后,我们和BeanFactory进行整合:
package net.csdn.blog.deltatang;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.csdn.blog.deltatang.dom4me.DomTree;
import net.csdn.blog.deltatang.dom4me.Node;
import net.csdn.blog.deltatang.dom4me.XmlParser;
public class BeanFactory {
private static boolean initSucc = false;
private static Map<String, String> appBean = new HashMap<String, String>();
private static Map<String, String[]> appRef = new HashMap<String, String[]>();
public static void fillAppInitParams(Node root){
for(int i = 0; i < root.getChildren().size(); i++) {
Node bean = (Node) root.getChildren().get(i);
String id = bean.getAttributes().get("id");
String clazz = bean.getAttributes().get("class");
appBean.put(id, clazz);
if(!bean.getChildren().isEmpty()) {
List<String> refs = new ArrayList<String>();
for(int k = 0; k < bean.getChildren().size(); k++) {
Node arg = (Node)bean.getChildren().get(k);
refs.add(arg.getAttributes().get("ref"));
}
appRef.put(id, refs.toArray(new String[0]));
}
}
}
public static void init() {
try {
XmlParser xmlParser = new XmlParser();
InputStream is = xmlParser.getClass().getResourceAsStream("./test.xml");
DomTree dt = xmlParser.build(is);
is.close();
fillAppInitParams(dt.getRoot());
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getBean(String id) {
if(initSucc) {
init();
initSucc = true;
}
try {
String className = appBean.get(id);
Class clazz = Class.forName(className);
Constructor constructor;
String[] ref = appRef.get(id);
if(ref == null || ref.length == 0) {
constructor = clazz.getConstructor();
return (Object)constructor.newInstance();
}
Class[] parameterTypes = new Class[ref.length];
Object[] initargs = new Object[ref.length];
for(int i = 0; i < ref.length; i++) {
String r = ref[i];
String rclassName = appBean.get(r);
parameterTypes[i] = Class.forName(rclassName).getInterfaces()[0]; //这里我偷懒了:)
initargs[i] = getBean(r);
}
constructor = clazz.getConstructor(parameterTypes);
return (Object)constructor.newInstance(initargs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String ... arg) {
LuceneDAO luceneDAO = (LuceneDAO) getBean("luceneDAO");
int[] vals = luceneDAO.findDocIDs("test");
for(int v : vals) {
System.out.println(v);
}
String keywords = "test";
SearchService searchService = (SearchService)getBean("searchService");
List results = searchService.search(keywords);
for(int i = 0; i < results.size(); i++) {
Result result = (Result) results.get(i);
System.out.print("[" + result.title + "]");
System.out.println(result.content);
}
}
}
最终,我们得到了一个类似spring 的类装配和组织框架。
当然,它相当简陋,不过,足够我们阐述清楚问题,并在我们的项目sitefromscratch中使用。
如果继续向spring靠拢,比如,我们要实现 spring的
singlton="flase" lazy="true"
并不是一件很困难的工作,当然,我无意去“重复发明轮子”,我的目的是通过一个自己的实现去尝试理解成熟框架的实现机制和思想。