通知 网站从因情语写改为晴雨,这个网站的模板也从calmlog_ex改为 whimurmur

Spring概述

1204人浏览 / 0人评论 / | 作者:因情语写  | 分类: spring  | 标签: java web整合开发王者归来  | 

作者:因情语写

链接:https://www.proprogrammar.com/article/20

声明:请尊重原作者的劳动,如需转载请注明出处


      说明:该专题所说的Spring内容基于spring2.0,最Spring最基础,最原始,最核心的内容。

  Spring框架是个轻量级的Java EE框架。所谓轻量级,是指不依赖于容器就能运行的。Struts、Hibernate也是轻量级的。

  轻量级框架是相对于重量级框架而言的,重量级框架必须依赖特定的容器,如如EJB框架就必须运行在Glassfish、JBOSS等支持EJB的容器中,而不能运行在Tomcat中。

  Spring框架

  Spring是应用最广泛的轻量级Java EE框架之一,它以IOC,AOP为主要思想,能够协同Struts,Hibernate,WebWork,JSF,IBatis等众多的框架。

  Spring背景

  Spring并不是官方的框架,而是Rod Johnson领导的开源的、免费的、民间的框架。Rod Johnson曾是Servlet 2.4规范专家组的成员,不过他对EJB等官方标准表示怀疑,认为过于复杂、臃肿的重量级官方框架并不能解决问题提供便利。

  为此,2002年他写了Expert one on one J2EE Design and Development(《精通J2EE设计开发》)一书,对现有的J2EE技术标准进行了反思。这是一本J2EE领域的畅销书。基于这本书的思想,Rod Johnson创立了一个实用的轻量级框架,这就是Spring。

  Spring容器

  Spring是一个轻量级的框架,不需要特殊容器的支持,不依赖于特定的规范如Java EE规范等。不同于Struts,Hibernate等,Spring不提供某种功能。它只是将所有的组件部署到Spring中,管理、维护、执行它们,因此Spring也被称为轻量级“容器”。官方网站为http://springframework.org

  一个依赖注入的例子

  Spring最主要的思想是IOC(Inversion of Control,控制反转、反向控制),或者称为DI(Dependency Injection,依赖注入)。IOC是对传统控制流程的一种颠覆。

  一个普通程序的例子

  在传统程序中,相互的依赖性是固定在程序中的,程序的运行也是一步一步的,完全按照程序代码执行,根据代码就能知道程序怎样运行。

  例如一个传统的程序可能是这样的,先实例化一个ServiceExample对象,然后调用该对象的service()方法服务用户,代码如下

package com.helloweenvsfei.spring.example;

public class Test {

    public static void main(String[] args) {

        String name = "Helloween";

        ServiceExample serviceExample = new ServiceExample();
        serviceExample.service(name);
    }
}

      而在ServiceExample中,先实例化一个DaoExample对象,通过DaoExample的sayHello()方法输出问候语。代码如下:

package com.helloweenvsfei.spring.example;

public class ServiceExample {

    private DaoExample daoExample = new DaoExample();

    public void service(String name) {
        System.out.println(daoExample.sayHello(name));
    }

}

      ServiceExample输出了欢迎语,而最终欢迎语的内容是由DaoExample决定的。代码如下:

package com.helloweenvsfei.spring.example;

import java.util.Calendar;

public class DaoExample {

    public String sayHello(String name) {
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        if (hour < 6)
            return "凌晨早, " + name;
        if (hour < 12)
            return "早上好, " + name;
        if (hour < 13)
            return "中午好, " + name;
        if (hour < 18)
            return "下午好, " + name;
        return "晚上好, " + name;
    }

}

      根据源代码就可以知道,本程序分为3层:应用层、Service层以及DAO层。应用层实例化了一个Service层对象,并调用其中的方法。Service层中实例化了一个DAO层对象,并调用了其中的方法。DAO层对象返回计算后的字符串。程序的执行流程可以从代码中阅读出来,都是正向运行的。

  而利用Spring的反向控制(IOC)思想,可以使用另一种方式实现,完全不同的思路。下面看一下Spring中的实现。

  Dao接口及实现

  新建Web项目spring,添加Spring特性。方法同添加Hibernate特性一样。先定义DAO层的接口。Spring推荐使用接口,Java中也推荐使用接口编程。IDao接口只有一个方法sayHello,参数为人名。该方法将返回对该人名的问候语。代码如下:

package com.helloweenvsfei.spring.example;

public interface IDao {
    
    public String sayHello(String name);

}

      实现IDao接口,并根据时间输出不同的问候语。代码如下:

package com.helloweenvsfei.spring.example;

import java.util.Calendar;

public class DaoImpl implements IDao {

    public String sayHello(String name) {
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        if (hour < 6)
            return "凌晨早, " + name;
        if (hour < 12)
            return "早上好, " + name;
        if (hour < 13)
            return "中午好, " + name;
        if (hour < 18)
            return "下午好, " + name;
        return "晚上好, " + name;
    }

}

      Service接口及实现

  定义Service层接口。Service层只有一个service()方法,没有任何DAO层的依赖,没有任何冗余的代码。IService代码如下:

package com.helloweenvsfei.spring.example;

public interface IService {

    public void service(String name);

}

      Service层实现中,定义了一个IDao类型对象,以及对应的getter,setter方法,注意这里没有实例化一个DaoImpl对象。该对象将被Spring注射进来。而注射动作是发生在运行时的,是在ServiceImpl代码写完之后,这个方向是反向的。Service接口实现代码如下:

package com.helloweenvsfei.spring.example;

public class ServiceImpl implements IService {

    private IDao dao;

    public void service(String name) {
        System.out.println(dao.sayHello(name));
    }

    public IDao getDao() {
        return dao;
    }

    public void setDao(IDao dao) {
        this.dao = dao;
    }

}

      组装DAO与Service

  注意前面的代码。IService中没有IDao的对象。ServiceImpl中只有IDao类型变量,及对应的getter、setter方法,也没有实例化任何的IService对象或者IDao。

  不过如果运行ServiceImpl的service方法,仍然要依赖IDao对象。这种依赖关系并不是写在程序中的,而是配置在Spring文件中,由Spring在运行时设置的。配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<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-2.0.xsd">
<!-- dao 实例 -->
    <bean id="dao" class="com.helloweenvsfei.spring.example.DaoImpl">
    </bean>

    <!-- service 实例 -->
    <bean id="serviceImpl"
        class="com.helloweenvsfei.spring.example.ServiceImpl">
        
            <property name="dao" ref="dao"></property>
                    <!--<property name="dao">
            <ref bean="dao" />
            </property>

        <property name="dao">
            <bean class="com.helloweenvsfei.spring.example.DaoImpl"></bean>
        </property>-->
        <!-- 
            <property name="someMap">
            <map>
            <entry key="yup an entry">
            <value>just some string</value>
            </entry>
            <entry key-ref="myDataSource">
            <ref bean="myDataSource" />
            </entry>
            </map>
            </property>
        -->

    </bean>

       配置文件中用<bean>配置了DaoImpl类与ServiceImpl类对象,Spring会负责实例化这两个对象。用<property>把Service的DAO属性设为daoImpl,相当于java代码:

service.setDao(daoImpl);  //Spring将通过反射执行该setter方法

      Spring会根据该配置在运行时使用setter、getter方法注入依赖的对象。

  运行代码

  Spring会负责IService、IDao对象的实例化,并设置彼此间的依赖。先创建一个Spring的工程,该工程会根据Spring配置文件加载配置文件中的Java Bean,并通过Java的反射机制调用getter、setter方法设置彼此间的依赖。然后从工程中获取Java对象,执行就可以了。代码如下:

package com.helloweenvsfei.spring.example;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

public class SpringTest {

    public static void main(String[] args) {

        XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(
                "applicationContext.xml"));

        // 从配置文件中获取对象
        IService hello = (IService) factory.getBean("service");
        hello.service("Helloween");

        factory.destroySingletons();
    }

}

      运行程序,会输出相同的结果:晚上好,Helloween。

  程序中没有实例化任何的DAO、Service对象,而是从Spring工程中直接获取的。也就是说,Spring实例化并维护这此对象。因此,Spring实际上是一个轻量级的容器,能生产、管理、维护各种实例。

  反向控制的原理

  在本例中,Service、DAO层是作为独立的组件出现的。在编码阶段,既没有实例化对象,也没有设置依赖关系,而把它交给Spring,由Spring在运行阶段实例化、组装对象。这种做法颠覆了传统的写代码实例化、组装对象、然后一步步执行的做法,因此被称为反向控制(Inverse of Control),或者反转控制。

    面向切面编程的原理

  由于组件是在运行期间组装、调用的,因此Spring即可以在执行完A组件后执行组件B,也可以执行完A组件后执行B组件前再执行C组件。也就是说,将C组件插入到A组件与B组件之间。

  如果把A、B、C看成是切面,这就是AOP、面向切面的编程。面向切面编程的思想就是在执行某些代码前执行另外的代码,使程序更灵活、扩展性更好,可以随便地添加,删除某些功能。

  Java Web机制中的Filter就是面向切面编程的例子。Tomcat会在程序运行的某个时机(即Servlet执行前后),执行与Servlet、JSP等毫无关系的Filter代码。

   一个面向切面编程的例子

  Spring的另一个重要思想是AOP(Aspect Oriented Programming,面向切面编程),切面编程提供了一种机制,在执行业务前后执行另外的代码。Servlet中的Filter便是一种AOP思想的实现。Spring提供非常灵活的AOP机制。

  实现拦截器接口

  跟Filter一样,Spring的AOP也需要实现特定的接口。Spring把这些实现了特定AOP接口的类称为拦截器(Interceptor)。Spring有若干种拦截器,例如在某些方法前执行的拦截器,在某些方法后执行的拦截器、异常拦截器等。例如下面的代码是在方法前执行拦截器:

package com.helloweenvsfei.spring.example;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.aop.MethodBeforeAdvice;

public class MethodBeforeAdviceImpl implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object obj)
            throws Throwable {
        System.out.println("运行前检查... ");
        System.out.println("Method: " + method.getName());
        System.out.println("Args: " + Arrays.asList(args));
        System.out.println("Object: " + obj);
    }
}

      Spring在执行某个实例的方法之前,会调用MethodBeforeAdvice的before()方法,参数分别为即将被调用的方法、方法的参数、该实例。该拦截器中没有定义执行时机,执行时机是在Spring配置文件中配置的。

  AOP配置拦截器

  修改上例中Spring的配置文件,使程序在执行sayHello()方法之前执行拦截器的代码。将上面的拦截器配置在applicationContext.xml中,并用通配符"*“配置在ServiceImpl的任意方法前执行拦截器代码。代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<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-2.0.xsd">

    <!-- 拦截器对象 -->
    <bean id="methodBeforeAdviceImpl"
        class="com.helloweenvsfei.spring.example.MethodBeforeAdviceImpl">
    </bean>

    <!-- 配置拦截器 -->
    <bean id="theAdvisor"
        class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="advice">
            <!-- 拦截器对象 -->
            <ref local="methodBeforeAdviceImpl" />
        </property>
        <!-- 拦截所有的方法 -->
        <property name="mappedName" value="*"></property>
    </bean>

    <!-- dao 实例 -->
    <bean id="dao" class="com.helloweenvsfei.spring.example.DaoImpl">
    </bean>

    <!-- service 实例 -->
    <bean id="serviceImpl"
        class="com.helloweenvsfei.spring.example.ServiceImpl">
        <!-- 
            <property name="dao" ref="dao"></property>
            <property name="dao">
            <ref bean="dao" />
            </property>
        -->
        <property name="dao">
            <bean class="com.helloweenvsfei.spring.example.DaoImpl"></bean>
        </property>
        <!-- 
            <property name="someMap">
            <map>
            <entry key="yup an entry">
            <value>just some string</value>
            </entry>
            <entry key-ref="myDataSource">
            <ref bean="myDataSource" />
            </entry>
            </map>
            </property>
        -->

    </bean>

    <bean id="service"
        class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 拦截器 -->
        <property name="interceptorNames" value="theAdvisor"></property>
        <!-- 被拦截的对象 -->
        <property name="target">
            <ref local="serviceImpl" />
        </property>
    </bean>
</beans>

      配置完毕后,不用对SpringTest代码做任何的修改。运行SpringTest,Spring会先执行拦截器代码,后执行ServiceImpl的方法。输出如下:

      Spring提供的AOP机制异常灵活,能够在任何类、任何方法的执行前、后添加拦截器。Spring不仅给开发者提供了IOC与AOP功能,Spring内置的许多功能也是基于IOC与AOP技术实现的。

  Spring框架的组成

  Spring是个轻量级的框架,但是它的功能却很庞大。Spring框架的所有组成如图:

      图中显示了Spring的7大模块。各个模块的功能如下:

  1、Core模块

  Core模块是框架的核心类库,Spring所有的功能均依赖于该类库。Core模块主要实现了IOC功能。Spring的所有功能都是借助IOC实现的。

  2、AOP模块

  Spring的AOP库,提供了AOP(也就是拦截器)机制,并提供各种常用的拦截器,允许自定义、配置方法拦截器、拦截的对象。

  3、ORM模块

  ORM模块提供对常用ORM框架的管理、辅助支持。Spring支持Hibernate、iBatis、JDO等各种ORM框架。Spring并不提供自己的ORM实现,只是对现有的ORM框架进行封装,并提供对它们的管理,例如事务管理等。

  4、DAO模块

  DAO模块提供JDBC支持,对JDBC进行封装,允许JDBC使用Spring的资源,并能统一管理JDBC的事务,Spring也不提供JDBC实现。

  5、Web模块

  Web模块提供对Struts、WebWork、JSF等各种Web框架的支持。Spring能够管理这些框架,将Spring的资源如数据源、Bean等注射给框架,也能在执行框架方法前后插入Spring的拦截器。

  6、Context模块

  Context模块提供框架式Bean访问方式,其他程序可以通过Context访问Spring的Bean资源。类似于JNDI。

  7、Web MVC模块

  Spring提供一套轻量级的MVC实现。在Spring框架中,开发者可以选择Struts作为MVC框架,也可以使用Spring自带的MVC框架。Spring MVC与Struts等框架相比,更加简洁、灵活。

  小结

  Spring是一个轻量级的框架,包括7个核心的模块。Spring最核心的思想是依赖注入(或者称为返向控制),它把离散的组件在运行时组装到一块。由于程序流程是在运行时组装的,因此可以很方便地添加功能,例如拦截器等。Spring是一种面向切面编程的框架。


亲爱的读者:有时间可以点赞评论一下

点赞(0) 打赏

全部评论

还没有评论!
广告位-帮帮忙点下广告