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

  • 相关阅读:
    CF1276F
    CF1082F
    CF1366G
    CF1221G
    CentOS7统计某个进程当前的线程数
    centos7备份系统日志
    mysql删除带外键约束的表的方法
    django.db.models.query.QuerySet格式的数据输出
    Linux命令大全
    django创建多对多表三种方法,和ORM操作增删改查
  • 原文地址:https://www.cnblogs.com/huntfor/p/3893571.html
Copyright © 2011-2022 走看看