zoukankan      html  css  js  c++  java
  • spring小结2:spring管理bean原理(转帖)

    接上回《spring概述及环境搭建
          上回讲到只需要在xml中配置一个 <bean><property name="msg" value="喜欢你,没道理! "></property></bean>配置一个子标签,便可以对Helloworld中msg行赋值,是否觉蛋疼?刚学习spring时,小飞我也觉得挺纳闷的,单单配置个属性就能进行赋值,这不是坑吗!其实,当熟悉原理之后,你会觉得,靠,原来也就那么一会事!现在小飞通过代码模拟一下spring实现Bean的原理!

    上回的xml配置文件

    <!-- 部分1 -->
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <!-- 部分2 -->
        <!-- 配置组件,上面编写的helloWold类 -->
        <bean id="sayBean" class="com.langfei.helloworld.HelloWorld">
            <!-- 依赖注入 -->
            <property name="msg" value="喜欢你,没道理! "></property>
        </bean>
    </beans>

    实体类
    public class HelloWorld {
        private String msg;
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
        public void say()
        {
            System.out.println(msg);
        }
    }
    测试类
    public class SayMsg {
       
    public static void main(String[] args) {
            ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
            HelloWorld hw = (HelloWorld) app.getBean("sayBean");
            hw.say();
           
        }
    }
    #########################【山寨版spring 依赖注入及bean实例化】#######################################

    第一步:导包
    dom4j-1.6.1.jar   xml解析使用包
    jaxen-1.1-beta-6.jar  dom4j依赖包

    第二步:模拟BeanDefinition类
    /**
     * 模拟spring中的BeanDefinition
     * 此处该类是一个简单的bean类,用于模拟id和classname对应关系
     * @author 狼飞
     */
    public class MyBeanDefinition {
        private String id;    //对应xml<bean>标签id属性值
        private String classname; //对应class 属性值
        public MyBeanDefinition(String id, String classname){
            this.id = id;
            this.classname = classname;
        }
        public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getClassname() {
            return classname;
        }
        public void setClassname(String classname) {
            this.classname = classname;
        }
    }

    第三步:模拟ClassPathXmlApplicationContext
    package com.langfei.helloworld;

    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.XPath;
    import org.dom4j.io.SAXReader;
    /**
     * 本类模拟spring ClassPathXmlApplicationContext类,对xml文件的进行解析,获取其中包含的实体类配置信息,
     * 通过反射,实现山寨版的spring依赖注入及bean实例化
     * @author 狼飞
     *
     */
    public class MyClassPathXmlApplicationContext {
        private List<MyBeanDefinition> beanDefinitions = new ArrayList<MyBeanDefinition>();
        // 用于保存解析xml中的bean实例,key为对应id value为class
        private Map<String, Object> sigletons = new HashMap<String, Object>();

        public MyClassPathXmlApplicationContext(String xmlName) {
            this.readXml(xmlName); // 解析xml
        }

        private void readXml(String xmlName) {
            SAXReader saxReader = new SAXReader();
            Document document = null;
            URL xmlPath = this.getClass().getClassLoader().getSystemResource(xmlName);
            try {
                document = saxReader.read(xmlPath);
            } catch (DocumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Map<String, String> nsMap = new HashMap<String, String>();    //用于缓存命名空间map集
            nsMap.put("ns", "http://www.springframework.org/schema/beans");// 命名空间
            XPath xsub = document.createXPath("//ns:beans/ns:bean"); // 创建beans/bean查询路径
            xsub.setNamespaceURIs(nsMap);    //设置命名空间uri
            List<Element> beansElements = xsub.selectNodes(document);    //获取对应空间下节点集

            for (Element element : beansElements) {
                String id = element.attributeValue("id");
                String clazz = element.attributeValue("class");    //<bean>标签的id属性值及class属性值
                MyBeanDefinition beanDefinition = new MyBeanDefinition(id, clazz);
                beanDefinitions.add(beanDefinition);

                List<Object> propNames = new ArrayList<Object>();    //bean子标签<property>的name属性对应的值,也即实体对象如HellowWorld的属性名
                List<Object> propValues = new ArrayList<Object>();//bean子标签<property>的value属性对应的值,也即实体对象如HellowWorld的属性值
                //采用迭代方法获取<bean>标签中子标签
                for (Iterator<Element> iterator = element.elementIterator(); iterator
                        .hasNext();) {
                    Element elementSon = (Element) iterator.next();
                    for (Iterator ia = elementSon.attributeIterator(); ia.hasNext();) {
                        ia.next();//获取子标签的name对应的属性值及value属性对应的值
                        propNames.add(elementSon.attributeValue("name"));
                        propValues.add(elementSon.attributeValue("value"));
                    }
                }
                try {
                    //将<bean>标签class属性值转换为Class实例
                    Class clazzClass = Class.forName(clazz);
                    Object object = clazzClass.newInstance();//通过反射,将class转换为实体对象实例
                    Field[] fields = clazzClass.getDeclaredFields();    //获取实体对象所有属性
                    for (Field f : fields) {
                        for (int i = 0; i < propNames.size(); i++) {
                            String propername = f.getName();
                            if (propNames.get(i).equals(propername)) {
                                StringBuilder sb = new StringBuilder();
                                String methodName = sb        //根据属性名拼接setXxx方法
                                        .append("set")
                                        .append(propername.substring(0, 1)
                                                .toUpperCase())
                                        .append(propername.substring(1)).toString();
                                Method method = clazzClass.getMethod(methodName,
                                        String.class);
                                method.invoke(object, propValues.get(i));        //执行set方法,为属性赋值,模拟spring的依赖注入
                            }
                        }
                    }
                    sigletons.put(id, object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                propNames.clear();
                propValues.clear();
            }
        }

        public Object getBean(String beanName) {
            return this.sigletons.get(beanName);
        }
    }
    第四步:测试
    实体类不需要任何改变,将测试类修改如下
    public class SayMsg {
        public static void main(String[] args) {
            /*ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
            HelloWorld hw = (HelloWorld) app.getBean("sayBean");
            hw.say();*/
           
            MyClassPathXmlApplicationContext applicationContext = new MyClassPathXmlApplicationContext("beans.xml");
            HelloWorld hWorld = (HelloWorld) applicationContext.getBean("sayBean");
            hWorld.say();              
        }
    }

    至此,spring bean原理模拟结束,相比正在的spring bean依赖注入实现,这可谓是小巫见大巫,不是同个级别,不过原理都是那么一回事!

    原文地址:http://blog.163.com/langfei520@yeah/blog/static/172710222201282472944140/

  • 相关阅读:
    从新注册 .DLL CMD 运行regsvr32 *.dll注册该DLL 或 regsvr32 /s *.DLL 求证
    短信猫 TIdTCPServer TIdTCPClient
    转:Delphi和Office程序开发 --不错可查阅
    主窗体里面打开子窗体&&打印饼图《Delphi 6数据库开发典型实例》--图表的绘制
    TeeChart Pro 5.0
    软件打开时间、窗体透明度、背景色---《用delphi开发共享软件》-15.1任务管理器
    设置随机启动--《用delphi开发共享软件》-15.1任务管理器
    实现窗体随着鼠标移动(控件)--《用delphi开发共享软件》-15.1任务管理器
    第二百六十一节,Tornado框架模板引擎本质
    第二百六十节,Tornado框架-内置模板方法
  • 原文地址:https://www.cnblogs.com/edison2012/p/2882677.html
Copyright © 2011-2022 走看看