zoukankan      html  css  js  c++  java
  • Spring技术内幕:SpringIOC原理学习总结

    前一段时候我把Spring技术内幕的关于IOC原理一章看完,感觉代码太多,不好掌握,我特意又各方搜集了一些关于IOC原理的资料,特加深一下印象,以便真正掌握IOC的原理。


    IOC的思想是:Spring容器来实现这些相互依赖对象的创建、协调工作。对象仅仅须要关系业务逻辑本身就能够了。


    SpringIOC容器的执行步骤是:
    1、资源定位,即首先要找到applicationContext.xml文件
    2、BeanDefinition的加载,把XML文件里的数据统一加载到BeanDefinition中,方便以后的处理
    3、向IOC容器中注入BeanDefinition数据
    4、将BeanDefinition中的数据进行依赖注入
    IoC的一个重点是在系统执行中,动态的向某个对象提供它所须要的其它对象。这一点是通过DI(Dependency Injection。依赖注入)来实现的。比方对象A须要操作数据库。曾经我们总是要在A中自己编写代码来获得一个Connection对象。有了 spring我们就仅仅须要告诉spring。A中须要一个Connection,至于这个Connection怎么构造。何时构造,A不须要知道。在系统执行时,spring会在适当的时候制造一个Connection,然后像打针一样。注射到A其中。这样就完毕了对各个对象之间关系的控制。A须要依赖 Connection才干正常执行,而这个Connection是由spring注入到A中的。依赖注入的名字就这么来的。

    那么DI是怎样实现的呢? Java 1.3之后一个重要特征是反射(reflection)。它同意程序在执行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
    举个现实生活中样例。如今有非常多中介公司,比如我爱我家。我爱我家会有各种各样的房源资料,当我们找房子时我们仅仅需把须要的房子告诉我爱我家,我爱我家会依据我们的需求给我们提供适合的房子。这样我们就不用自己去网上、小区广告等各个地方去搜集寻求适合自己的房子,整个过程由我爱我家中介来控制即可了,如今想想有个这个中介是不是使整个过程变得简单愉快了。当然,在实际生活中面对中介我们是须要交中介费的,好比SpringIOC我们也须要维护ApplicationContext这个配置文件,都是成本,面对Spring我们能够忽略成本,哈哈。
    以下让我看看SpringIOC的执行过程:
    1、首先加载ApplicationContext.xml,资源定位
    首先资源定位终于是在Springframe下的AbstractBeanDefinitionReader类中的LoaderBeanDefinitions(String location,Set<Resource> actualResources) line 98,以下举例说明:

    public static void main(String[] args) {
            ApplicationContext context = new FileSystemXmlApplicationContext(
                    "applicationContext.xml");
            User user= (User) context.getBean("user");
            user.write();
        }
     <bean id="user" class="com.jader.spring.Model.User">
            <property name="name" value="jader" />
     </bean>
     public class User{
        private String name;
        public void write() {
            System.out.println("my name is:"+name);
        }
        public void setName(String name) {
            this.name = name;
        }
    }

    执行程序会输出:my name is jader,非常明显,SpringIOC已经把property里的value注入到User的name属性其中。
    以下我们来分析Spring是怎么实现的
    2、BeanDefinition的加载
    加载和解析终于是在Springframework下的AbstractApplicationContext类的refresh()方法实现的,这种方法非常关键,里面包括了资源加载和解析,包括对lazy-init的额外处理等,line 445。以下举例说明:
    首先我们定义一个Bean,用来存放Bean拥有的属性

      /* Bean Id */
        private String id;
        /* Bean Class */
        private String type;
        /* Bean Property */
        private Map<String, Object> properties = new HashMap<String, Object>();

    接下来Spring 就開始加载我们的配置文件了,将我们配置的信息保存在一个HashMap中,HashMap的key就是Bean 的 Id 。HasMap 的value是这个Bean,仅仅有这样我们才干通过context.getBean(“user”)这种方法获得Animal这个类。我们都知道Spirng能够注入基本类型,并且能够注入像List。Map这种类型,接下来就让我们以Map为例看看Spring是怎么保存的

    
       <bean id="beanMap" class="BeanMap">
            <property name="myBeanMap">
                <map>
                    <entry key="name">
                        <value>jader</value>
                    </entry>
                    <entry key="age">
                        <value>26</value>
                    </entry>
                </map>
            </property>
        </bean>

    3、向IOC容器中注冊BeanDefinition
    注冊终于是在Spring frame的DefaultListableBeanFactory类下的registerBeanDefinition(String beanName,BeanDefinition beanDefinition)方法中实现,line 664;以下举例说明:

                if (beanProperty.element("map") != null) {
                        Map<String, Object> propertiesMap = new HashMap<String, Object>();
                        Element propertiesListMap = (Element) beanProperty
                                .elements().get(0);
                        Iterator<?> propertiesIterator = propertiesListMap
                                .elements().iterator();
                        while (propertiesIterator.hasNext()) {
                            Element vet = (Element) propertiesIterator.next();
                            if (vet.getName().equals("entry")) {
                                String key = vet.attributeValue("key");
                                Iterator<?> valuesIterator = vet.elements()
                                        .iterator();
                                while (valuesIterator.hasNext()) {
                                    Element value = (Element) valuesIterator.next();
                                    if (value.getName().equals("value")) {
                                        propertiesMap.put(key, value.getText());
                                    }
                                    if (value.getName().equals("ref")) {
                                        propertiesMap.put(key, new String[] { value
                                                .attributeValue("bean") });
                                    }
                                }
                            }
                        }
                        bean.getProperties().put(name, propertiesMap);
                    }

    4、依赖注入
    SpringIOC的终于依赖注入是是通过AbstractAutowireCapableBeanFactory的doCreateBean(finale String beanName,final RootBeanDefinition mbd,final Object[] args)方法(line 480)的,这种方法里的关键方法有populateBean()和createBeanInstance()。正在实现注入是通过BeanWrapperImpl extends AbstractPropertyAccessor类的setPropertyValue()方法实现 line 911
    原理是:通过反射机制实现的,在实例化一个类时。它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中

    public static Object newInstance(String className) {
            Class<?> cls = null;
            Object obj = null;
            try {
                cls = Class.forName(className);
                obj = cls.newInstance();
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            return obj;
        }
    public static void setProperty(Object obj, String name, String value) {
            Class<? extends Object> clazz = obj.getClass();
            try {
                String methodName = returnSetMthodName(name);
                Method[] ms = clazz.getMethods();
                for (Method m : ms) {
                    if (m.getName().equals(methodName)) {
                        if (m.getParameterTypes().length == 1) {
                            Class<?> clazzParameterType = m.getParameterTypes()[0];
                            setFieldValue(clazzParameterType.getName(), value, m,
                                    obj);
                            break;
                        }
                    }
                }
            } catch (SecurityException e) {
                throw new RuntimeException(e);
            } catch (IllegalArgumentException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
    }

    最后它将这个类的实例返回给我们。我们就能够用了。

    我们还是以Map为例看看它是怎么做的,我写的代码里面是创建一个HashMap并把该HashMap注入到须要注入的类中

              if (value instanceof Map) {
                    Iterator<?> entryIterator = ((Map<?, ?

    >) value).entrySet() .iterator(); Map<String, Object> map = new HashMap<String, Object>(); while (entryIterator.hasNext()) { Entry<?, ?> entryMap = (Entry<?, ?>) entryIterator.next(); if (entryMap.getValue() instanceof String[]) { map.put((String) entryMap.getKey(), getBean(((String[]) entryMap.getValue())[0])); } } BeanProcesser.setProperty(obj, property, map); }

    以上每一步的详细实现我都标注了类名、方法名和行数。大家能够自行查看Spring源代码,这里不展示了。
    面对Spring技术内幕的第一章介绍SpringIOC原理,难用理解,借助于这边文章能够帮我们理解一下。

    书读百遍。其义自现,当你读一遍不明确的时候能够重复阅读,这篇文章我都是从网上多方搜集的资料。在这里我表示感谢,希望我们共同进步。

  • 相关阅读:
    Spinnerd的功能和用法
    vagrant up ----失败 问题解决
    Yii2.0基础框架
    linux上nginx新建站点
    vagrant(二)配置文件vagrantfile详解 以及安装php、nginx、mysql
    vagrant(一)初识与安装
    cmd 使用gii的命令行用法
    mysql 使用shell时出现 ERROR 2006 (HY000): MySQL server has gone away 解决方法
    c++ virtual总结
    kartikgridGridView 合计,多选,导出excel,header修改 等方法集合!
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/7251858.html
Copyright © 2011-2022 走看看