Maven依赖:
<?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>
public interface ApplicationContext {/*** 根据bean的名字获取对应的bean对象* @param beanName myspring配置文件中bean标签的id* @return 对应的bean对象*/<T> T getBean(String beanName,Class<T> type);Object getBean(String beanName);
}
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() {@Overridepublic 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和refbeans.forEach(new Consumer() {@Overridepublic void accept(Object o) {try {//获取bean的id和classNameElement 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() {@Overridepublic 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();}}
// 加个泛型@Overridepublic <T> T getBean(String beanName,Class<T> type) {return (T)singletonObject.get(beanName);}@Overridepublic Object getBean(String beanName) {return singletonObject.get(beanName);}}