栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

简单地模拟实现Spring解析配置文件并实例化对象

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

简单地模拟实现Spring解析配置文件并实例化对象

目录

1.首先要创建一个maven项目,并导入相关依赖(dom4j)

2.在srcmainresources目录下创建一个spring.xml配置文件。

3.然后在srcmainjava目录下编写相关类,详细说明已在注释中写出

3.1 User 类

3.2 BeanDefinition 类

3.3 ApplicationContext 接口

3.4 ClasspathXmlApplicationContext 类

3.4.1 关于为什么要是有暴力反射?

3.5 测试类 SpringTest 

4. 执行结果


1.首先要创建一个maven项目,并导入相关依赖(dom4j)

可以通过 https://mvnrepository.com/ 获取相关依赖代码,复制到pom.xml文件中的标签里。

注意:因为是模拟实现spring,所以不需要导入spring相关依赖。

2.在srcmainresources目录下创建一个spring.xml配置文件。

3.然后在srcmainjava目录下编写相关类,详细说明已在注释中写出

3.1 User 类
package com.funny.entity;

public class User {
    public User() {
        System.out.println("User.User");
    }

    public void show() {
        System.out.println("User.show()方法被调用");
    }
}

3.2 BeanDefinition 类
package com.funny.spring;


public class BeanDefinition {
    private String id;
    private String clazz;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getClazz() {
        return clazz;
    }

    public void setClazz(String clazz) {
        this.clazz = clazz;
    }
}

3.3 ApplicationContext 接口
package com.funny.spring;


public interface ApplicationContext {
    //通过字节码获取Bean
     T getBean(Class clazz);

    //通过bean名称获取Bean
    Object getBean(String beanName);
}

3.4 ClasspathXmlApplicationContext 类
package com.funny.spring;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.*;


public class ClasspathXmlApplicationContext implements ApplicationContext {
    //利用List集合存放 Bean 对象属性的集合
    private List beanDefinitionList;
    //单例池 利用Map集合存放
    private Map singleton;

    public ClasspathXmlApplicationContext() {
        this("spring.xml");
    }


    public ClasspathXmlApplicationContext(String configName) {
            this.beanDefinitionList = new ArrayList<>();
            this.singleton = new HashMap<>();

            //解析 xml 配置文件
            parseXmlConfigurationFile(configName);
            //实例化对象
            instance();
    }

    //用于解析 xml 配置文件
    private void parseXmlConfigurationFile(String name){
        try {
            //创建类装载器
            ClassLoader classloader = Thread.currentThread().getContextClassLoader();
            //创建字节输入流对象
            InputStream in = classloader.getResourceAsStream(name);
            //创建SAXReader对象
            SAXReader reader = new SAXReader();
            //调用这个对象的read方法来读取文件
            Document document = reader.read(in);
            
            //获取根节点
            Element root = document.getRootElement();
            
            //获取根节点下的所有子节点
            Iterator childElements = root.elementIterator();
            //循环处理所有子节点
            while (childElements.hasNext()){
                Element childElement = childElements.next();
                
                //创建 BeanDefinition 对象
                BeanDefinition beanDefinition = new BeanDefinition();
                for (Iterator it = childElement.attributeIterator(); it.hasNext();) {
                    //获取点前节点属性
                    Attribute attribute = it.next();
                    //判断如果属性名是id 就 setId,否则setClazz
                    if("id".equals(attribute.getName())){
                        beanDefinition.setId(attribute.getValue());
                    }else{
                        beanDefinition.setClazz(attribute.getValue());
                    }
                    
                }
                beanDefinitionList.add(beanDefinition);
            }
        } catch (DocumentException e) {
            throw new RuntimeException("读取配置文件出错,错误信息为"+e.getMessage());
        }
    }

    //实例化对象
    private void instance() {
        for (BeanDefinition beanDefinition : beanDefinitionList) {
            try {
                //通过反射获取对象
                Class clazz = Class.forName(beanDefinition.getClazz());
                //获取构造器对象
                Constructor constructor = clazz.getDeclaredConstructor();
                constructor.setAccessible(true); //暴力反射
                Object o = constructor.newInstance();
                
                //把实例化对象放入单例池中
                singleton.put(beanDefinition.getId(),o);
                singleton.put(clazz.getSimpleName(),o);
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
    }

    //通过字节码获取Bean
    @Override
    public  T getBean(Class clazz) {
        if(singleton.containsKey(clazz.getSimpleName())){
            return (T)singleton.get(clazz.getSimpleName());
        }
        throw new RuntimeException("bean不存在");
    }

    //通过名称获取Bean
    @Override
    public Object getBean(String beanName) {
        if(singleton.containsKey(beanName)){
            return singleton.get(beanName);
        }
        throw new RuntimeException("bean不存在");
    }
}

3.4.1 关于为什么要是有暴力反射?

        暴力反射是除了public的甚至是连private都可以获取。

        如果一个类的构造方法是私有的,也就是private 修饰的,是不能在外部直接使用new 来创建对象。这个时候你要是使用反射会出错,暴力反射正好解决这个问题。当然不只是构造方法,其他方法,属性等也同样。

        所以使用暴力反射是为了避免出现不必要的错误。

3.5 测试类 SpringTest 
package com.funny.test;

import com.funny.entity.User;
import com.funny.spring.ApplicationContext;
import com.funny.spring.ClasspathXmlApplicationContext;


public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClasspathXmlApplicationContext("spring.xml");
        //User user = (User) context.getBean("user");
        User user = context.getBean(User.class);
        user.show();
    }
}

4. 执行结果

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/889217.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号