zoukankan      html  css  js  c++  java
  • Spring IOC原理(初级版)

    Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性的角度而言,绝大部分Java应用都可以从Spring中受益。

    ------------------------------------------------------------↑ 以上都是废话,我也不懂 ↑   ↓ 下面是整体架构,可以略过 ↓ --------------------------------------------------------

    整体框架:

    Spring框架式一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。

    组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下: 

    核心容器(下面几个模块与本文无关,可以暂时不用看):核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 
    Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 
    Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。 
    Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。 
    Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。 
    Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 
    Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。 

    ------------------------------------------------------------↑上面是介绍,我也不懂↑,↓ 下面是IOC ↓ ----------------------------------------------------------------------------

    核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

    本文介绍的IOC,如上所言,是spring核心模块的核心原理。

    IOC产生的背景

    脑补一下这样的场景,应该会经常遇到:当A、B、C类需要E类对象来协作完成一件事情的时候,传统做法:直接在A、B、C类中分别new一个E类对象。突然某一天,发现ABC类不再需要E对象来协作了,需要F对象。这是你该怎么办?只有一个办法,你需要修改A、B、C类的源代码,将E换成F,突然某一天,又改成G了,啥都不说了,改吧。突然某一天、突然某一天、突然某一天.....妈蛋!老子不干了!(当然说的夸张了点)这就是耦合

    如何解耦合呢?我们自然而然想到了接口,如果能弄一个接口,让所有的EFG....类都是这个接口的实现该多好啊。虽然从接口的实现来看是不太可能了。直到Michael Mattson提出了IOC,散播福音啊。

    什么是IOC

    上文背景中介绍到当A类需要E类对象来协作时,传统做法是自己new一个E类,这时候,控制权在你手里。IOC什么意思呢?Inversion of Control!控制反转!即:控制权反转到了其他地方。至于什么地方,一会儿再说。至少,你说了不算了。用参考资料2中的一个很有意思的事情,当你想谈恋爱的时候(需要一个异性协作,当然,也可能是同性),传统做法是:我自己去找一个女朋友男朋友,主动权在我手里(你别说妹子不答应啊,我呼死你)。IOC的做法是:当你说你想找个人谈恋爱,你说我想要一个完美的妹子,比如长得像刘亦菲,身材像林志玲,唱歌像孙燕姿,速度像梅西,技术像内马尔blahblah,有个人直接送给你一个,这个人可能是你父母,也可能是婚介所。反正不是你。明白了吧。控制权反转到了人家的手里了,人家塞给你谁就是谁,爱要不要。当然,你觉得不符合要求,不满意,可以对他们说“尼玛,这是凤姐”(抛出异常)。按照IOC的做法:你能做的,只能是到婚介所或者父母(Spring容器)那里,告诉对方,你是谁,想要什么样的妹子,然后spring登记了你的信息,并在你需要的时候给你想要的。这时候,控制权其实在spring容器手里,所有类的创建,销毁都是由spring控制,而不再由你(引用它的对象)来操心了。明白了吗?控制权反转到了spring容器手里了。还听不懂,下面的也不要看了,放弃吧。

    IOC的重点是在系统运行过程中,动态的像某个对象提供它所需要的其它对象。这个提供的方法是通过DI(依赖注入)来实现的。比如,A类需要一个B类对象来完成某个动作,以前是A类自己new一个B,有了Spring之后,只需要告诉spring,A中需要一个B,至于B怎么构造,何时构造,A完全不需要care,只需要在它需要的时候张嘴要就行了。在系统运行时,spring会在适当时候制造一个B,然后像打针一样,注射到A中,从而完成了对象之间的关联控制。A需要依赖B才可以正常运行,而B对象是由spring注入到A中去的。依赖注入就是这么来的。

    DI的实现

    DI是通过反射来实现的,反射允许程序通过某个类的名字或者对象来得到类本身。不了解反射机制的可以点这里。spring就是通过反射来完成注入的。

     

     接下来手动写一个屌丝版的Spring IOC容器。【以下内容摘自参考资料2】

    首先,我们定义一个Bean类,这个类用来存放一个Bean拥有的属性。

    1         /* Bean Id */
    2     private String id;
    3     /* Bean Class */
    4     private String type;
    5     /* Bean Property */
    6     private Map<String, Object> properties = new HashMap<String, Object>();
    View Code

    一个Bean包括id,type(类全域名),和Properties(属性域)。 

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

    Map配置可以像下面的。

    <bean id="test" class="Test">
            <property name="testMap">
                <map>
                    <entry key="a">
                        <value>1</value>
                    </entry>
                    <entry key="b">
                        <value>2</value>
                    </entry>
                </map>
            </property>
        </bean>
    View Code

    Spring是怎样保存上面的配置呢?,代码如下:

     1 if (beanProperty.element("map") != null) {
     2                     Map<String, Object> propertiesMap = new HashMap<String, Object>();
     3                     Element propertiesListMap = (Element) beanProperty
     4                             .elements().get(0);
     5                     Iterator<?> propertiesIterator = propertiesListMap
     6                             .elements().iterator();
     7                     while (propertiesIterator.hasNext()) {
     8                         Element vet = (Element) propertiesIterator.next();
     9                         if (vet.getName().equals("entry")) {
    10                             String key = vet.attributeValue("key");
    11                             Iterator<?> valuesIterator = vet.elements()
    12                                     .iterator();
    13                             while (valuesIterator.hasNext()) {
    14                                 Element value = (Element) valuesIterator.next();
    15                                 if (value.getName().equals("value")) {
    16                                     propertiesMap.put(key, value.getText());
    17                                 }
    18                                 if (value.getName().equals("ref")) {
    19                                     propertiesMap.put(key, new String[] { value
    20                                             .attributeValue("bean") });
    21                                 }
    22                             }
    23                         }
    24                     }
    25                     bean.getProperties().put(name, propertiesMap);
    26                 }
    View Code

    接下来就进入最核心部分了,让我们看看Spring 到底是怎么依赖注入的吧,其实依赖注入的思想也很简单,它是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。让我们看看具体它是怎么做的吧。 
    首先实例化一个类,像这样

     1 public static Object newInstance(String className) {
     2         Class<?> cls = null;
     3         Object obj = null;
     4         try {
     5             cls = Class.forName(className);
     6             obj = cls.newInstance();
     7         } catch (ClassNotFoundException e) {
     8             throw new RuntimeException(e);
     9         } catch (InstantiationException e) {
    10             throw new RuntimeException(e);
    11         } catch (IllegalAccessException e) {
    12             throw new RuntimeException(e);
    13         }
    14         return obj;
    15     }
    View Code

    接着它将这个类的依赖注入进去,像这样

     1 public static void setProperty(Object obj, String name, String value) {
     2         Class<? extends Object> clazz = obj.getClass();
     3         try {
     4             String methodName = returnSetMthodName(name);
     5             Method[] ms = clazz.getMethods();
     6             for (Method m : ms) {
     7                 if (m.getName().equals(methodName)) {
     8                     if (m.getParameterTypes().length == 1) {
     9                         Class<?> clazzParameterType = m.getParameterTypes()[0];
    10                         setFieldValue(clazzParameterType.getName(), value, m,
    11                                 obj);
    12                         break;
    13                     }
    14                 }
    15             }
    16         } catch (SecurityException e) {
    17             throw new RuntimeException(e);
    18         } catch (IllegalArgumentException e) {
    19             throw new RuntimeException(e);
    20         } catch (IllegalAccessException e) {
    21             throw new RuntimeException(e);
    22         } catch (InvocationTargetException e) {
    23             throw new RuntimeException(e);
    24         }
    25 }
    View Code

    最后它将这个类的实例返回给我们,我们就可以用了。我们还是以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);
                }
    View Code

    这样我们就可以用Spring 给我们创建的类了(虽然细节没太弄明白,里面一些方法都不知道具体实现是什么)

    当然Spring能做到的远不止这些,这个示例程序仅仅提供了Spring最核心的依赖注入功能中的一部分。 

     【评注】:从上文中,可以感觉到Ioc的实质有点想工厂模式,只不过这个工厂不再是java类,而是一个Ioc容器,生成对象的方法也不再由工厂直接生成,而是通过配置文件和反射来动态生成。毫无疑问:这样使得代码具有更好的灵活性、可扩展性。同时进一步的解耦合。

    参考资料:http://blog.csdn.net/m13666368773/article/details/7802126

    http://blog.csdn.net/it_man/article/details/4402245

  • 相关阅读:
    Microsoft Enterprise Library 5.0 系列(二) Cryptography Application Block (初级)
    Microsoft Enterprise Library 5.0 系列(五) Data Access Application Block
    Microsoft Enterprise Library 5.0 系列(八) Unity Dependency Injection and Interception
    Microsoft Enterprise Library 5.0 系列(九) Policy Injection Application Block
    Microsoft Enterprise Library 5.0 系列(三) Validation Application Block (高级)
    软件研发打油诗祝大家节日快乐
    从挖井的故事中想到开发管理中最容易忽视的几个简单道理
    ITIL管理思想的执行工具发布
    管理类软件设计“渔”之演化
    20070926日下午工作流与ITILQQ群 事件管理 讨论聊天记录
  • 原文地址:https://www.cnblogs.com/huntfor/p/3893571.html
Copyright © 2011-2022 走看看