Maven依赖:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.myspringframework</groupId>
<artifactId>myspring</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 打包方式 jar-->
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- dom4j是一个能够解析XML文件的java组件 -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
<!-- 使用xpath时dom4j.jar会依赖jaxen,所以需要引入jaxen包。-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
<!-- 引入测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
java
public interface ApplicationContext {
/**
* 根据bean的名字获取对应的bean对象
* @param beanName myspring配置文件中bean标签的id
* @return 对应的bean对象
*/
<T> T getBean(String beanName,Class<T> type);
Object getBean(String beanName);
}
java
public class ClassPathXmlApplicationContext implements ApplicationContext{
// 对应一级缓存
private Map<String,Object> singletonObject=new HashMap<>();
/**
* 解析myspring的配置文件,然后初始化所有的bean对象。
* @param configLocation Spring配置文件的路径,注意,使用ClassPathXmlApplicationContext,配置文件应放在类路径中
*/
public ClassPathXmlApplicationContext(String configLocation) {
// 解析myspring.xml配置文件,实例化bean,把bean放到集合中
try {
// 获取一个解析器对象
SAXReader saxReader=new SAXReader();
// 获取所要读取的文件的输入流
URL resource = ClassLoader.getSystemClassLoader().getResource(configLocation);
// 获取文档对象
Document document = saxReader.read(resource);
// 获取指定标签 //bean 表示获得多个bean标签
List beans = document.selectNodes("//bean");
// 遍历所有的bean并放到集合中
beans.forEach(new Consumer() {
@Override
public void accept(Object o) {
//向下转型,拥有更丰富的方法
Element element= (Element) o;
//获取bean后,再获取属性值id和class 注:class是全类名
String id = element.attributeValue("id");
String className = element.attributeValue("class");
try {
//有了类名后,直接反射创建对象
Class clazz= Class.forName(className);
//获取无参构造方法
Constructor declaredConstructor = clazz.getDeclaredConstructor();
//创建对象并放到map中 进行曝光
Object bean = declaredConstructor.newInstance();
singletonObject.put(id,bean);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
});
// 进行set注入,为属性赋值
//首先得获得<property />标签,获取其中的属性name和value 或是 name和ref
beans.forEach(new Consumer() {
@Override
public void accept(Object o) {
try {
//获取bean的id和className
Element element= (Element) o;
String className=element.attributeValue("class");
String id=element.attributeValue("id");
//获取 <bean/>中的所有<property>标签
List properties = element.elements();
//遍历该bean所有<property>标签
properties.forEach(new Consumer() {
@Override
public void accept(Object o) {
Element property= (Element) o;
String fieldName = property.attributeValue("name");
String propertyValue = property.attributeValue("value");
String ref = property.attributeValue("ref");
try {
//利用反射
Object bean=singletonObject.get(id);
//获取set()方法
String setMethodName="set"+fieldName.toUpperCase().charAt(0)+fieldName.substring(1);
//获取全限定类型名
Class propertyType= bean.getClass().getDeclaredField(fieldName).getType();
//如果所获取的方法有参数的话,需要加上参数类型
Method setMethod = bean.getClass().getDeclaredMethod(setMethodName,propertyType);
//获取bean的set方法
if(propertyValue!=null){
Object propertyVal=null;
//对于基本数据类型,如果想要调用相应的set方法,必须知道类型是什么
String propertyTypeSimpleName=propertyType.getSimpleName();
switch (propertyTypeSimpleName) {
case "byte": case "Byte":
propertyVal = Byte.valueOf(propertyValue);
break;
case "short": case "Short":
propertyVal = Short.valueOf(propertyValue);
break;
case "int": case "Integer":
propertyVal = Integer.valueOf(propertyValue);
break;
case "long": case "Long":
propertyVal = Long.valueOf(propertyValue);
break;
case "float": case "Float":
propertyVal = Float.valueOf(propertyValue);
break;
case "double": case "Double":
propertyVal = Double.valueOf(propertyValue);
break;
case "boolean": case "Boolean":
propertyVal = Boolean.valueOf(propertyValue);
break;
case "char": case "Character":
propertyVal = propertyValue.charAt(0);
break;
case "String":
propertyVal = propertyValue;
break;
}
setMethod.invoke(singletonObject.get(id), propertyVal);
}else if(ref!=null){
//这个简单,直接把所需要的曝光后的对象赋值给它就行。
setMethod.invoke(bean,singletonObject.get(ref));
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}catch (Exception e){
e.printStackTrace();
}
}
// 加个泛型
@Override
public <T> T getBean(String beanName,Class<T> type) {
return (T)singletonObject.get(beanName);
}
@Override
public Object getBean(String beanName) {
return singletonObject.get(beanName);
}
}