zoukankan      html  css  js  c++  java
  • 【Spring深度分析】IoC/DI机制 配置文件式 基本实现

    Youzg Logo


    首先,本人来提供一个 容器接口

    容器接口 —— ApplicationContext接口:

    package edu.youzg.simulate_IoC.bean;
    
    public interface ApplicationContext {
        public Object getBean(String beanId);
    }
    

    现在,本人来给出这个接口的实现类

    容器接口实现类 —— ClassPathXmlApplicationContext类:

    package edu.youzg.simulate_IoC.bean;
    
    import edu.youzg.simulate_IoC.entity.BeanDefinition;
    import org.dom4j.Attribute;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import java.io.InputStream;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class ClassPathXmlApplicationContext implements ApplicationContext {
        //以id为键,相应的BeanDefinition为值,封装从xml配置文件中所需读取到的的信息
        private static Map<String, BeanDefinition> xmlBeans = new HashMap<String, BeanDefinition>();
        //IOC容器,以id为键,对象为值,封装new出来的信息,以便我们进行“依赖注入”工作
        private static Map<String, Object> beanIoc = new HashMap<String, Object>();
    
        /**
         * 加载配置文件路劲,配置文件是一个xml文件
         *
         * @param path 配置文件的路径
         */
        public ClassPathXmlApplicationContext(String path) {
            try {
                //解析xml文件
                //SAXReader:可以类比是一个管道,用流的方式,把xml文件读出来
                SAXReader reader = new SAXReader();
                InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("beans.xml");
                //获取 整个文档对象
                Document document = reader.read(inputStream);
                //将 根节点 封装为 一个Element对象
                Element rootElement = document.getRootElement();
                //遍历子节点
                List<Element> beanList = rootElement.elements();
    
                //读取bean配置的时候,需要读取到 id、class、init、destory、autowire....等属性
                //将bean节点属性,以及 子节点“集合” 封装起来
                for (Element bean : beanList) {
                    //封装bean
                    BeanDefinition beanDefinition = new BeanDefinition();
    
                    //取得bean元素的属性 属性被封装为 Attribute对象
                    Attribute idatt = bean.attribute("id");
                    Attribute classatt = bean.attribute("class");
                    Attribute initatt = null;
                    try {
                        initatt = bean.attribute("init");
                    } catch (Exception e) {
                    }
                    Attribute scopeatt = null;
                    try {
                        scopeatt = bean.attribute("scope");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    String idVal = idatt.getValue();
                    String classVal = classatt.getValue();
    
                    beanDefinition.setId(idVal);
                    beanDefinition.setClasspath(classVal);
                    String value = null;
                    try {
                        value = initatt.getValue();
                    } catch (Exception e) {
                    }
                    String scope = null;
                    try {
                        scope = scopeatt.getValue();
                    } catch (Exception e) {
                    }
                    beanDefinition.setInit(value);
                    beanDefinition.setScope(scope);
                    //储存起来
                    xmlBeans.put(idVal, beanDefinition);
                }
                /*System.out.println("解析xmlbean完成,解析的结果为:");
                System.out.println("	" + JSON.toJSONString(xmlBeans, true));*/
                //对xmlBeans进行java的解析,解析为实际的xml中配置的java对象
                Set<String> keys = xmlBeans.keySet();
                for (String key : keys) {
                    Object obj = newInstance(key);
                    //将id和obj对应的储存储到IOC容器中,以便我们之后获取使用
                    beanIoc.put(key, obj);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public Object getBean(String beanId) {
            //首先获取beanId对应的 scope配置信息
            BeanDefinition beanDefinition = xmlBeans.get(beanId);
            if (beanDefinition == null) {
                throw new RuntimeException("[Youzg Error]:
    	索引[" + beanId + "]不存在!");
            }
    
            Object result = null;
            //获知 “单例性”,默认为 单例模式
            String scope = beanDefinition.getScope();
            if (null!=scope && scope.equals("propotype")) {
                result = newInstance(beanDefinition.getId());
                return result;
            } else if (scope.equals("singleton") || null==scope) {
                result = beanIoc.get(beanId);
                if (result == null) {
                    throw new RuntimeException("[Youzg Error]:
    	IoC容器中不存在[" + beanId + "]的对象");
                }
                return result;
            } else {
                throw new RuntimeException("[Youzg Error]:
    	scope属性值[" + scope + "]无法识别!");
            }
        }
    
        //通过反射机制,创建Java对象
        private Object newInstance(String beanId) {
            Object obj = null;
            try {
                BeanDefinition beanDefinition = xmlBeans.get(beanId);
                //需要对xml解析后的java对象BeanDefinition 进行加工【将配置变为java对象】 还要存放在IOC容器中
                String classPath = beanDefinition.getClasspath();
                //加载这个类
                Class cls = Class.forName(classPath);
                //创建类的对象
                obj = cls.newInstance();
                //判断有没有配置生命周期
                if (beanDefinition.getInit() != null && !beanDefinition.getInit().equals("")) {
                    //配置的初始化方法名称
                    String initMethod = beanDefinition.getInit();
                    //此刻调用obj的initMethod方法
                    Method method = cls.getDeclaredMethod(initMethod);
                    method.invoke(obj);//执行方法
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }
    
    }
    

    接下来,本人再来给出一个 用于封装xml文件中 每一个bean节点信息BeanDefinition类

    封装节点信息 —— BeanDefinition类:

    package edu.youzg.simulate_IoC.entity;
    
    /**
     * 用于封装xml文件中 每一个bean节点信息
     */
    public class BeanDefinition {
        private String id;
        private String classpath;
        private String init;
        private String scope;
    
        public String getInit() {
            return init;
        }
    
        public void setInit(String init) {
            this.init = init;
        }
    
        public String getScope() {
            return scope;
        }
    
        public void setScope(String scope) {
            this.scope = scope;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getClasspath() {
            return classpath;
        }
    
        public void setClasspath(String classpath) {
            this.classpath = classpath;
        }
    
    }
    

    那么,通过上述的接口与类,我们就基本实现配置文件式的IoC/DI机制

    测试:

    现在,本人来提供一个测试类 以及 一个测试配置文件来测试下我们上面的代码是否复合要求:
    首先是一个 要被自动注入的类:

    package edu.youzg.simulate_IoC.test;
    
    public class AccountService {
    
        public AccountService() {
            System.out.println("目标类的 构造方法");
        }
    
        public void sayHello() {
            System.out.println("hello xml IoC!");
        }
    
        public void doSomething() {
            System.out.println("目标类的 某方法");
        }
    
    }
    

    接下来是配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans id="nihao" class="">
        <!--将service交给 自定义的IOC容器-->
        <bean id="accountService" class="edu.youzg.simulate_IoC.test.AccountService" scope="singleton"></bean>
    </beans>
    

    那么,现在本人最后再来给出一个Demo类:

    package edu.youzg.simulate_IoC.test;
    
    import edu.youzg.simulate_IoC.bean.ApplicationContext;
    import edu.youzg.simulate_IoC.bean.ClassPathXmlApplicationContext;
    
    /**
     * @Author: Youzg
     * @CreateTime: 2020-04-26 00:35
     * @Description:带你深究Java的本质!
     */
    public class Demo {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            AccountService service1 = (AccountService) context.getBean("accountService");
            AccountService service2 = (AccountService) context.getBean("accountService");
            service1.sayHello();
            System.out.println(service1 == service2);
        }
    
    }
    

    现在,本人来展示下运行结果:
    运行结果 展示

    那么,可以看到,我们基本实现了IoC/DI机制!

    接下来我们只需要处理一下子标签的注入就ok了


  • 相关阅读:
    VS2005 DataGridView 和 GirdView 横向大比拼
    表结构信息查询
    在自己的网页中嵌入搜索引擎
    自定义AJAX请求获取地图范围
    oracle远程连接配置
    oracle账户被锁定问题
    JDK环境配置
    PythonWin运行出错解决办法
    HDF库的调试过程
    ajax入门详解
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/12776478.html
Copyright © 2011-2022 走看看