pom.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>com.example</groupId><artifactId>mySpring</artifactId><version>1.0</version><!--打包方式--><packaging>jar</packaging><dependencies><!--用于解析 xml 文件--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency><!--Java XPath 解析器XPath 是一种用于在 XML 文档中选择和查询数据的语言,可以认为它是一种针对 XML 文档的查询语言。Java 提供了许多库和工具来解析 XML,其中一个常见的用例是通过 XPath 查询指定的节点或数据,而 jaxen 提供了一种方便、灵活、易于使用、可扩展和全面的 API 来实现 XPath 查询--><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><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>17</source><target>17</target></configuration></plugin></plugins></build></project>
package com.example.demo.bean;public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public User() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
package com.example.demo.dao;public class UserDao {public void insert(){System.out.println("mysql is inserting data!");}}
package com.example.demo.service;import com.example.demo.dao.UserDao;public class UserService {private UserDao userDao;public void save(){userDao.insert();}public UserService(UserDao userDao) {this.userDao = userDao;}public UserService() {}public UserDao getUserDao() {return userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}
package com.example.spring;public interface ApplicationContext {//根据 bean 的名称获取 bean 对象Object getBean(String beanName);
}
package com.example.spring;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {//存放单例bean对象private Map<String,Object> singletonObjects = new HashMap<>();//configLocation 配置文件的路径public ClassPathXmlApplicationContext(String configLocation){//解析 xml 配置文件,根据配置文件实例化bean,将bean对象存放到 singletonObjects/*org.dom4j.io.SAXReader 的作用是使用SAX解析器读取XML文件并将其转换为DOM对象模型。它可以遍历XML文档的节点树,访问和操作各个节点及其属性值,并支持XPath表达式查询*/SAXReader reader = new SAXReader();//获取类路径下资源文件的输入流InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);try {//读取配置文件, 返回DOM对象模型Document document = reader.read(in);/*selectNodes() 方法接收一个XPath表达式作为参数,返回所有匹配该表达式的节点集合(List<Node>)。这些节点可以是元素节点、属性节点或者文本节点等。*/List<Node> beans = document.selectNodes("//bean");//遍历 所有 bean 节点beans.forEach((bean) ->System.out.println(bean));} catch (DocumentException e) {e.printStackTrace();}}@Overridepublic Object getBean(String beanName) {return null;}}
myspring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans><bean id="user" class="com.example.demo.bean.User"><property name="name" value="罗小黑"></property><property name="age" value="5"></property></bean><bean id="userDao" class="com.example.demo.dao.UserDao"></bean><bean id="userService" class="com.example.demo.service.UserService"><property name="userDao" ref="userDao"></property></bean></beans>
test
package demo;import com.example.spring.ApplicationContext;
import com.example.spring.ClassPathXmlApplicationContext;
import org.junit.Test;public class MySpring {@Testpublic void Test01(){ApplicationContext context = new ClassPathXmlApplicationContext("myspring.xml");}
}
result:
"C:\Program Files\Java\jdk-17\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 -Didea.launcher.port=50276 "-Didea.launcher.bin.path=C:\Minecloud\IDEA_2019\IntelliJ IDEA 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Minecloud\IDEA_2019\IntelliJ IDEA 2019.1\lib\idea_rt.jar;C:\Minecloud\IDEA_2019\IntelliJ IDEA 2019.1\plugins\junit\lib\junit-rt.jar;C:\Minecloud\IDEA_2019\IntelliJ IDEA 2019.1\plugins\junit\lib\junit5-rt.jar;C:\Minecloud\IDEA_workspace\spring_learn\mySpring\target\test-classes;C:\Minecloud\IDEA_workspace\spring_learn\mySpring\target\classes;C:\Users\29162\.m2\repository\org\dom4j\dom4j\2.1.3\dom4j-2.1.3.jar;C:\Users\29162\.m2\repository\jaxen\jaxen\1.2.0\jaxen-1.2.0.jar;C:\Users\29162\.m2\repository\junit\junit\4.13.2\junit-4.13.2.jar;C:\Users\29162\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.application.AppMainV2 com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 demo.MySpring,Test01
org.dom4j.tree.DefaultElement@11758f2a [Element: <bean attributes: [org.dom4j.tree.DefaultAttribute@33723e30 [Attribute: name id value "user"], org.dom4j.tree.DefaultAttribute@64f6106c [Attribute: name class value "com.example.demo.bean.User"]]/>]
org.dom4j.tree.DefaultElement@69b0fd6f [Element: <bean attributes: [org.dom4j.tree.DefaultAttribute@553a3d88 [Attribute: name id value "userDao"], org.dom4j.tree.DefaultAttribute@7a30d1e6 [Attribute: name class value "com.example.demo.dao"]]/>]
org.dom4j.tree.DefaultElement@4a87761d [Element: <bean attributes: [org.dom4j.tree.DefaultAttribute@5891e32e [Attribute: name id value "uerService"], org.dom4j.tree.DefaultAttribute@cb0ed20 [Attribute: name class value "com.example.demo.service"]]/>]Process finished with exit code 0
加入 log4j2 日志框架
pom.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>com.example</groupId><artifactId>mySpring</artifactId><version>1.0</version><!--打包方式--><packaging>jar</packaging><dependencies><!--用于解析 xml 文件--><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version></dependency><!--Java XPath 解析器XPath 是一种用于在 XML 文档中选择和查询数据的语言,可以认为它是一种针对 XML 文档的查询语言。Java 提供了许多库和工具来解析 XML,其中一个常见的用例是通过 XPath 查询指定的节点或数据,而 jaxen 提供了一种方便、灵活、易于使用、可扩展和全面的 API 来实现 XPath 查询--><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><!--log4j-slf4j2-impl 的作用是将应用程序中使用 SLF4J 接口的日志记录请求转发到 Log4j2 实现。这样做可以方便地在应用程序中使用 SLF4J 的统一日志接口,同时还能利用 Log4j2 强大的日志级别、过滤器和输出选项等功能。--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.19.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>17</source><target>17</target></configuration></plugin></plugins></build></project>
log4j2 的配置文件
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?><configuration><loggers><!--level指定日志级别,从低到高的优先级:ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF--><root level="DEBUG"><appender-ref ref="myspringlog"/></root></loggers><appenders><!--输出日志信息到控制台--><console name="myspringlog" target="SYSTEM_OUT"><!--控制日志输出的格式--><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/></console></appenders></configuration>
package com.example.spring;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {/*创建一个名为 "ClassPathXmlApplicationContext" 的日志记录器对象并赋值给 logger 变量。通过在程序中使用该 logger 对象输出日志信息,可以方便地追踪代码执行过程中产生的日志事件,从而帮助开发者进行调试和排查错误。*/private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);//存放单例bean对象private Map<String,Object> singletonObjects = new HashMap<>();//configLocation 配置文件的路径public ClassPathXmlApplicationContext(String configLocation){//解析 xml 配置文件,根据配置文件实例化bean,将bean对象存放到 singletonObjects/*org.dom4j.io.SAXReader 的作用是使用SAX解析器读取XML文件并将其转换为DOM对象模型。它可以遍历XML文档的节点树,访问和操作各个节点及其属性值,并支持XPath表达式查询*/SAXReader reader = new SAXReader();//获取类路径下资源文件的输入流InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);try {//读取配置文件, 返回DOM对象模型Document document = reader.read(in);/*selectNodes() 方法接收一个XPath表达式作为参数,返回所有匹配该表达式的节点集合(List<Node>)。这些节点可以是元素节点、属性节点或者文本节点等。*/List<Node> beans = document.selectNodes("//bean");//遍历 所有 bean 节点beans.forEach((bean) ->{//向下转型,为了使用Element的方法Element beanElement = (Element)bean;//获取 bean 的 idString id = beanElement.attributeValue("id");//获取 classNameString className = beanElement.attributeValue("class");//输出日志消息 是在INFO级别 level 记录消息,表示消息是普通的信息性质logger.info("beanName=" + id);logger.info("className" + className);});} catch (DocumentException e) {e.printStackTrace();}}@Overridepublic Object getBean(String beanName) {return null;}}
test:
package com.example;import com.example.spring.ClassPathXmlApplicationContext;public class Myspring {public static void main(String[] args) {new ClassPathXmlApplicationContext("myspring.xml");}
}
结果:
2023-05-20 09:37:18 114 [main] INFO com.example.spring.ClassPathXmlApplicationContext - beanName=user
2023-05-20 09:37:18 114 [main] INFO com.example.spring.ClassPathXmlApplicationContext - classNamecom.example.demo.bean.User
2023-05-20 09:37:18 114 [main] INFO com.example.spring.ClassPathXmlApplicationContext - beanName=userDao
2023-05-20 09:37:18 114 [main] INFO com.example.spring.ClassPathXmlApplicationContext - classNamecom.example.demo.dao
2023-05-20 09:37:18 114 [main] INFO com.example.spring.ClassPathXmlApplicationContext - beanName=uerService
2023-05-20 09:37:18 114 [main] INFO com.example.spring.ClassPathXmlApplicationContext - classNamecom.example.demo.serviceProcess finished with exit code 0
反射创建对象并加入map中 曝光
package com.example.spring;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {/*创建一个名为 "ClassPathXmlApplicationContext" 的日志记录器对象并赋值给 logger 变量。通过在程序中使用该 logger 对象输出日志信息,可以方便地追踪代码执行过程中产生的日志事件,从而帮助开发者进行调试和排查错误。*/private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);//存放单例bean对象private Map<String,Object> singletonObjects = new HashMap<>();//configLocation 配置文件的路径public ClassPathXmlApplicationContext(String configLocation){//解析 xml 配置文件,根据配置文件实例化bean,将bean对象存放到 singletonObjects/*org.dom4j.io.SAXReader 的作用是使用SAX解析器读取XML文件并将其转换为DOM对象模型。它可以遍历XML文档的节点树,访问和操作各个节点及其属性值,并支持XPath表达式查询*/SAXReader reader = new SAXReader();//获取类路径下资源文件的输入流InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);try {//读取配置文件, 返回DOM对象模型Document document = reader.read(in);/*selectNodes() 方法接收一个XPath表达式作为参数,返回所有匹配该表达式的节点集合(List<Node>)。这些节点可以是元素节点、属性节点或者文本节点等。*/List<Node> beans = document.selectNodes("//bean");//遍历 所有 bean 节点beans.forEach((bean) ->{//向下转型,为了使用Element的方法Element beanElement = (Element)bean;//获取 bean 的 idString id = beanElement.attributeValue("id");//获取 classNameString className = beanElement.attributeValue("class");//输出日志消息 是在INFO级别 level 记录消息,表示消息是普通的信息性质logger.info("beanName=" + id);logger.info("className=" + className);try {//加载类,得到类 对象Class<?> clazz = Class.forName(className);//反射 获取无参构造方法Constructor<?> constructor = clazz.getDeclaredConstructor();//利用无参构造方法创建对象Object o = constructor.newInstance();//将对象加入map集合 曝光singletonObjects.put(id,o);logger.info(singletonObjects.toString());} catch (Exception e) {e.printStackTrace();}});} catch (DocumentException e) {e.printStackTrace();}}@Overridepublic Object getBean(String beanName) {return null;}}
结果:
"C:\Program Files\Java\jdk-17\bin\java.exe" -Didea.launcher.port=59706 "-Didea.launcher.bin.path=C:\Minecloud\IDEA_2019\IntelliJ IDEA 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Minecloud\IDEA_workspace\spring_learn\mySpring\target\classes;C:\Users\29162\.m2\repository\org\dom4j\dom4j\2.1.3\dom4j-2.1.3.jar;C:\Users\29162\.m2\repository\jaxen\jaxen\1.2.0\jaxen-1.2.0.jar;C:\Users\29162\.m2\repository\org\apache\logging\log4j\log4j-core\2.19.0\log4j-core-2.19.0.jar;C:\Users\29162\.m2\repository\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;C:\Users\29162\.m2\repository\org\apache\logging\log4j\log4j-slf4j2-impl\2.19.0\log4j-slf4j2-impl-2.19.0.jar;C:\Users\29162\.m2\repository\org\slf4j\slf4j-api\2.0.0\slf4j-api-2.0.0.jar;C:\Minecloud\IDEA_2019\IntelliJ IDEA 2019.1\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMainV2 com.example.Myspring
2023-05-20 10:25:51 298 [main] INFO com.example.spring.ClassPathXmlApplicationContext - beanName=user
2023-05-20 10:25:51 298 [main] INFO com.example.spring.ClassPathXmlApplicationContext - className=com.example.demo.bean.User
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - {user=User{name='null', age=0}}
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - beanName=userDao
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - className=com.example.demo.dao.UserDao
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - {user=User{name='null', age=0}, userDao=com.example.demo.dao.UserDao@3e78b6a5}
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - beanName=uerService
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - className=com.example.demo.service.UserService
2023-05-20 10:25:51 314 [main] INFO com.example.spring.ClassPathXmlApplicationContext - {uerService=com.example.demo.service.UserService@41f69e84, user=User{name='null', age=0}, userDao=com.example.demo.dao.UserDao@3e78b6a5}Process finished with exit code 0
调用set方法注入属性
package com.example.spring;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ClassPathXmlApplicationContext implements ApplicationContext {/*创建一个名为 "ClassPathXmlApplicationContext" 的日志记录器对象并赋值给 logger 变量。通过在程序中使用该 logger 对象输出日志信息,可以方便地追踪代码执行过程中产生的日志事件,从而帮助开发者进行调试和排查错误。*/private static final Logger logger = LoggerFactory.getLogger(ClassPathXmlApplicationContext.class);//存放单例bean对象private Map<String,Object> singletonObjects = new HashMap<>();//configLocation 配置文件的路径public ClassPathXmlApplicationContext(String configLocation){//解析 xml 配置文件,根据配置文件实例化bean,将bean对象存放到 singletonObjects/*org.dom4j.io.SAXReader 的作用是使用SAX解析器读取XML文件并将其转换为DOM对象模型。它可以遍历XML文档的节点树,访问和操作各个节点及其属性值,并支持XPath表达式查询*/SAXReader reader = new SAXReader();//获取类路径下资源文件的输入流InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);try {//读取配置文件, 返回DOM对象模型Document document = reader.read(in);/*selectNodes() 方法接收一个XPath表达式作为参数,返回所有匹配该表达式的节点集合(List<Node>)。这些节点可以是元素节点、属性节点或者文本节点等。*/List<Node> beans = document.selectNodes("//bean");//遍历 所有 bean 节点beans.forEach((bean) ->{//向下转型,为了使用Element的方法Element beanElement = (Element)bean;//获取 bean 的 idString id = beanElement.attributeValue("id");//获取 classNameString className = beanElement.attributeValue("class");//输出日志消息 是在INFO级别 level 记录消息,表示消息是普通的信息性质logger.info("beanName=" + id);logger.info("className=" + className);try {//加载类,得到类 对象Class<?> clazz = Class.forName(className);//反射 获取无参构造方法Constructor<?> constructor = clazz.getDeclaredConstructor();//利用无参构造方法创建对象Object o = constructor.newInstance();//将对象加入map集合 曝光singletonObjects.put(id,o);logger.info(singletonObjects.toString());} catch (Exception e) {e.printStackTrace();}});//再次遍历bean标签,给属性赋值beans.forEach((bean) ->{try {//向下转型,为了使用Element的方法Element beanElement = (Element) bean;//获取 bean 的 idString id = beanElement.attributeValue("id");//获取 classNameString className = beanElement.attributeValue("class");//加载类Class<?> clazz = Class.forName(className);//获取该标签下的所有 property 标签List<Element> properties = beanElement.elements("property");//遍历所有的 property 标签properties.forEach(property ->{try {//获取属性名String propertyName = property.attributeValue("name");logger.info("propertyName=" + propertyName);//获取 value 属性的值String value = property.attributeValue("value");//获取 ref 的值String ref = property.attributeValue("ref");//通过 propertyName 获取 set 方法名String methodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);logger.info("methodName=" + methodName);//反射获取属性Field field = clazz.getDeclaredField(propertyName);//反射获取 set 方法Method method = clazz.getDeclaredMethod(methodName,field.getType());//value 转换类型后的值Object actualValue = null;if(value != null) {if( String.class != field.getType() ){//根据属性的类名将 value 转换为 相应的类型actualValue = convertValue( value, field.getType() );//调用 set 方法method.invoke( singletonObjects.get(id), actualValue );}else{method.invoke( singletonObjects.get(id), value );}}else if(ref != null){//调用 set 方法method.invoke( singletonObjects.get(id), singletonObjects.get(ref) );}}catch (Exception e){e.printStackTrace();}});}catch (Exception e){e.printStackTrace();}});} catch (DocumentException e) {e.printStackTrace();}}@Overridepublic Object getBean(String beanName) {return this.singletonObjects.get(beanName);}//将 value转换为 type 类型public static Object convertValue(String value, Class<?> type) {// Check if the type is a primitive typeif (type.isPrimitive()) {// Get the corresponding wrapper classtype = getWrapperClass(type);}try {// Get the valueOf method of the wrapper classMethod valueOfMethod = type.getMethod("valueOf", String.class);// Invoke the valueOf method to convert the value to the desired typereturn valueOfMethod.invoke(null, value);} catch (Exception e) {throw new RuntimeException("Error converting value", e);}}private static Class<?> getWrapperClass(Class<?> primitiveType) {if (primitiveType == boolean.class) return Boolean.class;if (primitiveType == byte.class) return Byte.class;if (primitiveType == char.class) return Character.class;if (primitiveType == short.class) return Short.class;if (primitiveType == int.class) return Integer.class;if (primitiveType == long.class) return Long.class;if (primitiveType == float.class) return Float.class;if (primitiveType == double.class) return Double.class;throw new IllegalArgumentException("Not a primitive type");}}
test
package com.example;import com.example.demo.bean.User;
import com.example.demo.service.UserService;
import com.example.spring.ApplicationContext;
import com.example.spring.ClassPathXmlApplicationContext;public class Myspring {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("myspring.xml");User user = (User) context.getBean("user");System.out.println( user.toString() );UserService userService = (UserService)context.getBean("userService");userService.getUserDao().insert();}
}
结果: