简单实现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);
    }


}
相关推荐
芒果披萨几秒前
El表达式和JSTL
java·el
吕彬-前端17 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱19 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai29 分钟前
uniapp
前端·javascript·vue.js·uni-app
duration~41 分钟前
Maven随笔
java·maven
zmgst1 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD1 小时前
前后端分离,Jackson,Long精度丢失
java
blammmp1 小时前
Java:数据结构-枚举
java·开发语言·数据结构
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式