`
cprogrammer
  • 浏览: 10398 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论
  • 375: 业务需要积累的,也需要你能坚持。
    ...
  • protti: jkfzero 写道不是说BOSS的网际结算业务流程相当的繁琐 ...
    ...
  • cprogrammer: acd79258 写道正在体验BOSS中。。感觉如下: 以前 ...
    ...
  • yuxie: 人云亦云罢,俺做过BOSS,也做过财务、人力资源一方面的一些软 ...
    ...
  • jkfzero: 不是说BOSS的网际结算业务流程相当的繁琐么?没有人介绍下。 ...
    ...

Spring基础实践

阅读更多
Spring是一个非常优秀的轻量级框架,通过Spring的IoC容器,我们的关注点便放到了需要实现的业务逻辑上。对AOP的支持则能让我们动态增强业务方法。编写普通的业务逻辑Bean是非常容易而且易于测试的,因为它能脱离J2EE容器(如Servlet,JSP环境)单独进行单元测试。最后的一步便是在Spring框架中将这些业务Bean以XML配置文件的方式组织起来,它们就按照我们预定的目标正常工作了!非常容易!

本文将给出一个基本的Spring入门示例,并演示如何使用Spring的AOP将复杂的业务逻辑分离到每个方面中。

1.开发环境配置
2.编写Bean接口及其实现
3.在Spring中配置Bean并获得Bean的实例
4.编写Advisor以增强ServiceBean
5.总结
1.开发环境配置

首先,需要正确配置Java环境。推荐安装JDK1.4.2,并正确配置环境变量:

JAVA_HOME=<JDK安装目录>
CLASSPATH=.
Path=%JAVA_HOME%\bin;……

我们将使用免费的Eclipse 3.1作为IDE。新建一个Java Project,将Spring的发布包spring.jar以及commons-logging-1.0.4.jar复制到Project目录下,并在Project > Properties中配置好Java Build Path:

2.编写Bean接口及其实现

我们实现一个管理用户的业务Bean。首先定义一个ServiceBean接口,声明一些业务方法:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 * For more information, please visit:http://www.javaeedev.com
 */
package com.crackj2ee.example.spring;

/**
 * Interface of service facade.
 *
 * @author Xuefeng
 */
public interface ServiceBean {
    void addUser(String username, String password);
    void deleteUser(String username);
    boolean findUser(String username);
    String getPassword(String username);
}

然后在MyServiceBean中实现接口:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 */
package com.crackj2ee.example.spring;

import java.util.*;

public class MyServiceBean implements ServiceBean {

    private String dir;
    private Map map = new HashMap();

    public void setUserDir(String dir) {
        this.dir = dir;
        System.out.println("Set user dir to: " + dir);
    }

    public void addUser(String username, String password) {
        if(!map.containsKey(username))
            map.put(username, password);
        else
            throw new RuntimeException("User already exist.");
    }

    public void deleteUser(String username) {
        if(map.remove(username)==null)
            throw new RuntimeException("User not exist.");
    }

    public boolean findUser(String username) {
        return map.containsKey(username);
    }

    public String getPassword(String username) {
        return (String)map.get(username);
    }
}


为了简化逻辑,我们使用一个Map保存用户名和口令。

现在,我们已经有了一个业务Bean。要测试它非常容易,因为到目前为止,我们还没有涉及到Spring容器,也没有涉及到任何Web容器(假定这是一个Web应用程序关于用户管理的业务Bean)。完全可以直接进行Unit测试,或者,简单地写个main方法测试:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 */
package com.crackj2ee.example.spring;

public class Main {

    public static void main(String[] args) throws Exception {
        ServiceBean service = new MyServiceBean();
        service.addUser("bill", "hello");
        service.addUser("tom", "goodbye");
        service.addUser("tracy", "morning");
        System.out.println("tom's password is: " + service.getPassword("tom"));
        if(service.findUser("tom")) {
            service.deleteUser("tom");
        }
    }
}


执行结果:

3.在Spring中配置Bean并获得Bean的实例

我们已经在一个main方法中实现了业务,不过,将对象的生命周期交给容器管理是更好的办法,我们就不必为初始化对象和销毁对象进行硬编码,从而获得更大的灵活性和可测试性。

想要把ServiceBean交给Spring来管理,我们需要一个XML配置文件。新建一个beans.xml,放到src目录下,确保在classpath中能找到此配置文件,输入以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="service" class="com.crackj2ee.example.spring.MyServiceBean" />
</beans>

以上XML声明了一个id为service的Bean,默认地,Spring为每个声明的Bean仅创建一个实例,并通过id来引用这个Bean。下面,我们修改main方法,让Spring来管理业务Bean:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 */
package com.crackj2ee.example.spring;

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

public class Main {

    public static void main(String[] args) throws Exception {
        // init factory:
       XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
        // use service bean:
        ServiceBean service = (ServiceBean)factory.getBean("service");
        service.addUser("bill", "hello");
        service.addUser("tom", "goodbye");
        service.addUser("tracy", "morning");
        System.out.println("tom's password is \"" + service.getPassword("tom") + "\"");
        if(service.findUser("tom")) {
            service.deleteUser("tom");
        }
        // close factory:
       factory.destroySingletons();
    }
}


执行结果:

由于我们要通过main方法启动Spring环境,因此,首先需要初始化一个BeanFactory。红色部分是初始化Spring的BeanFactory的典型代码,只需要保证beans.xml文件位于classpath中。

然后,在BeanFactory中通过id查找,即可获得相应的Bean的实例,并将其适当转型为合适的接口。

接着,实现一系列业务操作,在应用程序结束前,让Spring销毁所有的Bean实例。

对比上一个版本的Main,可以看出,最大的变化是不需要自己管理Bean的生命周期。另一个好处是在不更改实现类的前提下,动态地为应用程序增加功能。
4.编写Advisor以增强ServiceBean

所谓AOP即是将分散在各个方法处的公共代码提取到一处,并通过类似拦截器的机制实现代码的动态织入。可以简单地想象成,在某个方法的调用前、返回前、调用后和抛出异常时,动态插入自己的代码。在弄清楚Pointcut、Advice之类的术语前,不如编写一个最简单的AOP应用来体验一下。

考虑一下通常的Web应用程序都会有日志记录,我们来编写一个LogAdvisor,对每个业务方法调用前都作一个记录:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 */
package com.crackj2ee.example.spring;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class LogAdvisor implements MethodBeforeAdvice {
    public void before(Method m, Object[] args, Object target) throws Throwable {
        System.out.println("[Log] " + target.getClass().getName() + "." + m.getName() + "()");
    }
}

然后,修改beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="serviceTarget" class="com.crackj2ee.example.spring.MyServiceBean" />

    <bean id="logAdvisor" class="com.crackj2ee.example.spring.LogAdvisor" />

    <bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces"><value>com.crackj2ee.example.spring.ServiceBean</value></property>
        <property name="target"><ref local="serviceTarget"/></property>
        <property name="interceptorNames">
            <list>
                <value>logAdvisor</value>
            </list>
        </property>
    </bean>
</beans>


注意观察修改后的配置文件,我们使用了一个ProxyFactoryBean作为service来与客户端打交道,而真正的业务Bean即 MyServiceBean被声明为serviceTarget并作为参数对象传递给ProxyFactoryBean,proxyInterfaces 指定了返回的接口类型。对于客户端而言,将感觉不出任何变化,但却动态加入了LogAdvisor,关系如下:

运行结果如下,可以很容易看到调用了哪些方法:

要截获指定的某些方法也是可以的。下面的例子将修改getPassword()方法的返回值:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 * For more information, please visit:http://www.crackj2ee.com
 */
package com.crackj2ee.example.spring;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class PasswordAdvisor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object ret = invocation.proceed();
        if(ret==null)
            return null;
        String password = (String)ret;
        StringBuffer encrypt = new StringBuffer(password.length());
        for(int i=0; i<password.length(); i++)
            encrypt.append('*');
        return encrypt.toString();
    }
}


这个PasswordAdvisor将截获ServiceBean的getPassword()方法的返回值,并将其改为"***"。继续修改beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="serviceTarget" class="com.crackj2ee.example.spring.MyServiceBean" />

    <bean id="logAdvisor" class="com.crackj2ee.example.spring.LogAdvisor" />

    <bean id="passwordAdvisorTarget" class="com.crackj2ee.example.spring.PasswordAdvisor" />

    <bean id="passwordAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice">
            <ref local="passwordAdvisorTarget"/>
        </property>
        <property name="patterns">
            <list>
                <value>.*getPassword</value>
            </list>
        </property>
    </bean>

    <bean id="service" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces"><value>com.crackj2ee.example.spring.ServiceBean</value></property>
        <property name="target"><ref local="serviceTarget"/></property>
        <property name="interceptorNames">
            <list>
                <value>logAdvisor</value>
                <value>passwordAdvisor</value>
            </list>
        </property>
    </bean>
</beans>


利用Spring提供的一个RegexMethodPointcutAdvisor可以非常容易地指定要截获的方法。运行结果如下,可以看到返回结果变为"******":



还需要继续增强ServiceBean?我们编写一个ExceptionAdvisor,在业务方法抛出异常时能做一些处理:

/**
 * Copyright_2006, Liao Xuefeng
 * Created on 2006-3-9
 */
package com.crackj2ee.example.spring;

import org.springframework.aop.ThrowsAdvice;

public class ExceptionAdvisor implements ThrowsAdvice {
    public void afterThrowing(RuntimeException re) throws Throwable {
        System.out.println("[Exception] " + re.getMessage());
    }
}

将此Advice添加到beans.xml中,然后在业务Bean中删除一个不存在的用户,故意抛出异常:

service.deleteUser("not-exist");

再次运行,注意到ExceptionAdvisor记录下了异常
5.总结

利用Spring非常强大的IoC容器和AOP功能,我们能实现非常灵活的应用,让Spring容器管理业务对象的生命周期,利用AOP增强功能,却不影响业务接口,从而避免更改客户端代码。

为了实现这一目标,必须始终牢记:面向接口编程。而Spring默认的AOP代理也是通过Java的代理接口实现的。
分享到:
评论

相关推荐

    SpringCloud基础教程

    本基础教程旨在帮助初学者全面理解并掌握SpringCloud的核心概念和技术,通过实践源码与配套文档,深入学习其工作原理和应用方式。 首先,我们需要了解SpringCloud的基础架构,它由多个子项目组成,如Eureka(服务...

    spring ioc aop基础理论实践笔记

    1,spring是一个开源的免费的框架(容器)。 2,spring是一个轻量级的,非入侵式的框架。 ​ 非入侵式:就是项目引入了这个框架之后,(不会改变你代码原来的任何情况)不会对之前的代码有什么影响,反而是引入了...

    Spring Cloud微服务实践.pdf

    Spring Cloud微服务实践的知识点可以从文档标题及内容中提炼出以下几点: ### 微服务架构 微服务架构是一套方法论,它提倡将单一应用程序划分成一组小的服务,每个服务运行在其独立的进程中,并围绕业务能力构建。...

    Spring核心技术与最佳实践

    《Spring核心技术与最佳实践》一书深入探讨了Java EE Web开发中的关键技术和Spring框架的应用。Spring作为一款强大的IoC容器,不仅提供了卓越的依赖注入功能,还具备完整的Web MVC框架,使得开发高效、可扩展的Web...

    spring Boot实践完整版

    1. **Spring Boot基础**:首先会介绍Spring Boot的基本概念,包括其核心特性,如自动配置、起步依赖和嵌入式服务器。自动配置是Spring Boot的一大亮点,它能根据项目中的依赖自动配置相应的Bean。 2. **起步依赖**...

    spring 2.5 开发基础包

    Spring 2.5 开发基础包是针对Spring框架2.5版本的一个重要资源集合,它为开发者提供了在Java环境中构建企业级应用的基础。这个压缩包包含了一系列必要的库和文档,帮助开发者快速上手并深入理解Spring 2.5的核心功能...

    Spring Boot整合Spring Batch,实现批处理

    在Java开发领域,Spring Boot和Spring Batch的整合是构建高效...通过学习和实践这个示例,你不仅可以掌握如何在Spring Boot中使用Spring Batch,还能了解批处理的最佳实践,这对于处理大数据量的应用场景非常有价值。

    Spring框架基础包和依赖包.zip

    总的来说,这个压缩包提供了Spring框架的基本组成部分,以及一些必要的依赖,适合初学者进行学习和实践。通过了解和使用这些资源,开发者可以逐步掌握Spring框架的核心概念,如依赖注入和面向切面编程,并能够构建出...

    spring boot 实践学习案例,与其它组件整合

    spring boot 实践学习案例,与其它组件结合如 mybatis、jpa、dubbo、redis、mongodb、memcached、kafka、rabbitmq、activemq、elasticsearch、security、shiro等 #### Spring Boot 版本 - 2.0.3.RELEASE #### 模块...

    Spring框架基础压缩包

    在"Spring_Project_1"这个压缩包中,可能包含了Spring框架的基础示例项目,包括配置文件、源代码、测试用例等,可以帮助初学者理解并实践Spring的基本用法和特性。通过学习和研究这些内容,你可以深入掌握Spring框架...

    spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践

    本资源将通过一系列真实的学习案例,帮助用户深入理解和掌握 Spring Boot 的核心技术和最佳实践。 ### 资源内容概述: 1. **Spring Boot 简介**: - 介绍 Spring Boot 的基本概念、优势以及其在现代应用开发中的...

    spring的一个适合初学者的项目

    Spring 框架是Java开发中的一个核心框架,尤其对于初学者来说,它是一个极好的起点,可以帮助理解企业级应用的构建方式。...通过动手实践,你可以更好地掌握Spring的精髓,为将来开发更复杂的项目打下坚实的基础。

    Spring基础包

    这个“Spring基础包”显然是为了帮助初学者搭建Spring环境并理解其核心概念而设计的。 首先,Spring的核心组件包括Spring Core、Spring Beans和Spring Context。Spring Core提供了DI的基础,使得对象之间的依赖关系...

    spring MVC基础学习

    下面我们将深入探讨Spring MVC的基础知识。 1. **核心组件**: - DispatcherServlet:作为Spring MVC的前端控制器,负责接收HTTP请求,并根据配置分发到相应的处理器。 - HandlerMapping:映射请求到对应的...

    spring基础实例源码

    《Spring基础实例源码解析》 在学习Spring框架的过程中,实例和源码是理解其核心概念的两大关键。本教程将通过一系列基础实例,深入剖析Spring的核心特性——控制反转(IOC)和依赖注入(DI)。以下是对每个压缩...

    spring基础教程.rar

    至于具体的学习资源,本压缩包“Spring基础教程”可能包含一系列PDF文档、视频课程或代码示例,它们将逐步引导你了解并掌握Spring的基本用法,包括环境搭建、基本配置、Bean的创建与管理、AOP的实现、Spring MVC的...

    Spring Boot 2.0深度实践之核心技术篇

    例如,`spring-boot-starter-web`提供了开发Web应用的基础。 2. **自动配置(Auto Configuration)**:Spring Boot根据项目中的类路径和已添加的起步依赖,自动配置相应的bean。例如,如果检测到`tomcat`和`spring-...

    Spring基础学习资料,很全面,很经典,手工整理,适合刚学习spring的同学

    这份“Spring基础学习资料”涵盖了Spring框架的基础知识,特别适合初学者系统地学习和掌握。 1. **Spring入门学习前导篇**: 在开始Spring的学习之前,了解Spring的基本概念和历史背景是必要的。Spring框架起源于...

    Spring基础的思维导图版+附带PDF版

    这个资源包含的是一个Spring基础的思维导图和PDF版,可以帮助学习者更直观、系统地理解Spring的核心概念。 首先,我们从"Spring AOP"开始。AOP(Aspect-Oriented Programming)是面向切面编程,它允许程序员定义...

    Spring基础知识汇总Java开发必看

    以下是对Spring基础知识的详细讲解: 1. **依赖注入(Dependency Injection, DI)** 依赖注入是Spring的核心特性,它允许组件之间松耦合。通过容器管理对象的创建和对象之间的依赖关系,而不是在代码中硬编码依赖。...

Global site tag (gtag.js) - Google Analytics