代码已上传到GitHub,有兴趣的同学可以下载来看看:https://github.com/ylw-github/Java-CodeAnalysis-Demo
在上一节,我们知道SpringIOC的原理是使用了XML技术
+发射技术
,本文主要讲解如何手写SpringIOC。
org.springframework
spring-core
4.3.7.RELEASE
org.springframework
spring-beans
4.3.7.RELEASE
org.springframework
spring-context
4.3.7.RELEASE
org.springframework
spring-jdbc
4.3.7.RELEASE
org.springframework
spring-tx
4.3.7.RELEASE
org.aspectj
aspectjrt
1.9.1
com.mchange
c3p0
0.9.5.2
mysql
mysql-connector-java
5.1.25
dom4j
dom4j
1.6.1
commons-lang
commons-lang
2.6
org.springframework
spring-test
4.2.5.RELEASE
test
junit
junit
4.12
test
步骤二:编写XML解析文件
先看看ClassPathXmlApplicationContext源码: 我们会发现ClassPathXmlApplicationContext 继承了 AbstractXmlApplicationContext,一路追踪下去,会发现集成关系是这样的(继承了很多层):
ClassPathXmlApplicationContext
extends -> AbstractXmlApplicationContext
extends ->AbstractRefreshableConfigApplicationContext
extends ->AbstractRefreshableApplicationContext
extends ->AbstractApplicationContext
extends ->DefaultResourceLoader
下面来简单的写一个ClassPathXmlApplicationContext:
package com.ylw.ioc;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.StringUtils;
import java.io.InputStream;
import java.util.List;
public class ClassPathXmlApplicationContext {
// xml路径地址
private String xmlPath;
public ClassPathXmlApplicationContext(String xmlPath) {
this.xmlPath = xmlPath;
}
public Object getBean(String beanId) throws Exception {
// 1. 读取配置文件
List elements = readerXml();
if (elements == null) {
throw new Exception("该配置文件没有子元素");
}
// 2. 使用beanId查找对应的class地址
String beanClass = findXmlByIDClass(elements, beanId);
if (StringUtils.isEmpty(beanClass)) {
throw new Exception("未找到对应的class地址");
}
// 3. 使用反射机制初始化,对象
Class forName = Class.forName(beanClass);
return forName.newInstance();
}
// 读取配置文件信息
public List readerXml() throws DocumentException {
SAXReader saxReader = new SAXReader();
if (StringUtils.isEmpty(xmlPath)) {
new Exception("xml路径为空...");
}
Document read = saxReader.read(getClassXmlInputStream(xmlPath));
// 获取根节点信息
Element rootElement = read.getRootElement();
// 获取子节点
List elements = rootElement.elements();
if (elements == null || elements.isEmpty()) {
return null;
}
return elements;
}
// 使用beanid查找该Class地址
public String findXmlByIDClass(List elements, String beanId) throws Exception {
for (Element element : elements) {
// 读取节点上是否有value
String beanIdValue = element.attributeValue("id");
if (beanIdValue == null) {
throw new Exception("使用该beanId为查找到元素");
}
if (!beanIdValue.equals(beanId)) {
continue;
}
// 获取Class地址属性
String classPath = element.attributeValue("class");
if (!StringUtils.isEmpty(classPath)) {
return classPath;
}
}
return null;
}
// 读取xml配置文件
public InputStream getClassXmlInputStream(String xmlPath) {
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(xmlPath);
return resourceAsStream;
}
}
步骤三:编写ClassPathXmlApplicationContext 注解
1.通用的反射工具类
package com.ylw.ioc.util;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassUtil {
/**
* 取得某个接口下所有实现这个接口的类
*/
public static List getAllClassByInterface(Class c) {
List returnClassList = null;
if (c.isInterface()) {
// 获取当前的包名
String packageName = c.getPackage().getName();
// 获取当前包下以及子包下所以的类
List allClass = getClasses(packageName);
if (allClass != null) {
returnClassList = new ArrayList();
for (Class classes : allClass) {
// 判断是否是同一个接口
if (c.isAssignableFrom(classes)) {
// 本身不加入进去
if (!c.equals(classes)) {
returnClassList.add(classes);
}
}
}
}
}
return returnClassList;
}
/*
* 取得某一类所在包的所有类名 不含迭代
*/
public static String[] getPackageAllClassName(String classLocation, String packageName) {
// 将packageName分解
String[] packagePathSplit = packageName.split("[.]");
String realClassLocation = classLocation;
int packageLength = packagePathSplit.length;
for (int i = 0; i
关注
打赏