简单实现spring的set依赖注入

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);
    }


}
相关推荐
卷心菜好6啊3 分钟前
特辣的海藻!2
java
心态与习惯6 分钟前
mac 下 java 调用 gurobi 不能加载 jar
java·jar·mac·cplex·gurobi
he258197 分钟前
centOS 7.9 安装JDK MYSQL
java·mysql·centos
找了一圈尾巴19 分钟前
Spring Boot 日志管理(官网文档解读)
java·spring boot
升讯威在线客服系统19 分钟前
如何通过 Docker 在没有域名的情况下快速上线客服系统
java·运维·前端·python·docker·容器·.net
AsBefore麦小兜21 分钟前
Vite vs Webpack
前端·webpack
LaughingZhu21 分钟前
PH热榜 | 2025-02-23
前端·人工智能·经验分享·搜索引擎·产品运营
s:1031 小时前
【框架】参考 Spring Security 安全框架设计出,轻量化高可扩展的身份认证与授权架构
java·开发语言
道不尽世间的沧桑2 小时前
第17篇:网络请求与Axios集成
开发语言·前端·javascript
diemeng11193 小时前
AI前端开发技能变革时代:效率与创新的新范式
前端·人工智能