Why is Spring So Important?

Jul 28 2009 Published by Tony under Java

        Java EE 平台主要希望解决复杂的分布式的应用程序的开发,在中间件厂商与开源社区的大力支持下,传统的JavaEE架构在标准的low-level 中间件服务平台之上,通过一系列的APIs(EJB,JTA,JMS)也可以成功的开发。由于这些陈旧的JavaEE项目首要关注点都在标准化服务上,而忽略了开发的简单性原则。所以基于JavaEE平台的项目往往投入巨大。
         Java EE平台目标是用来开发基于模块的应用。而模块是指一个单独的程序,一段可以在复杂项目中简单重用的代码。例如:一个order模块包含一个用来持久化的 entity bean,一个用来处理业务流程的的session bean,理论上,这样的模块在很大程度上是可以重用的,但是,现实中,这些模块往往使用率不高。Java EE 程序的复杂性主要表现在编写model的时候,开发java EE model 往往需要写很多不必要的重复的代码和测试。这其中至少包括一段典型的在JBDI tree上查阅EJB对象的代码,获得一个数据库链接,拼装并执行数据库查询,并且最终释放数据库资源。首先,这样的程序极大地破坏了OO的封装原则,而且无谓的浪费了大量的程序员的人力。EJBs 的设计初衷是解决分布性事物的,虽然大部分的JavaEE项目包含数据库操作,进而需要一些事物操作,但是这些项目不需要分布性事物。但是一旦使用了 EJBs,项目中就引入了大量的用语处理分布性事务的代码。而且这个本来不需要分布性的项目也就成了一个分布性应用,由于有分布性的特性(虽然没用到),所以也对部署和硬件提出了更高的要求。而且由于基于EJBs的程序对JavaEE容器有比较大的依赖,所以Unit Test也变得很困难。所以TDD基本变得不可能。
          由于JavaEE开发的复杂性。Java社区提出了许多新的框架来代替传统的 JavaEE架构。其中Struts是一个基于servlet API的MVC实现。Hibernate解决了entity bean的痛苦旅程,它提供了一个基于POJOs的持久化框架,由于POJO不是一个分部式的对象,所以和entity bean相比,它有着更加出色的性能。而且Hibernate不依赖任何容器,所以单元测试也就变得很容易了。
          不同于Struts与 Hibernate,Spring Framework 并不是为了提供单独某一层的框架。他实际上提供了一种跨曾的框架支持,在分层的应用体系中,它帮助各层的独特框架更好的交互,而有不用意识到其他层的存在,由于Spring提供一个简单的基于POJOs,并且脱离JavaEE容器的开发环境,所以单元测试也就更加容易了。

No responses yet

Spring包结构以及各个包之间引用关系说明

Jul 28 2009 Published by Tony under Java

Spring 包结构说明:
spring.jar
包含有完整发布的单个jar包。他包含有除spring-mock.jar之外的所有 jar。原因是,spring-mock.jar只有在开发环境中才会用到,而且仅仅是作为一个辅助测试类存在。除了spring.jar,spring 还包括13个独立的jar文件,他们各自包含这spring各自的组件。所以,如果你可以明确知道使用spring的哪些资源文件时,就没必要去直接引入 spring.jar,但有时候spring.jar的引入也是最偷懒和最直接的方式。
spring-core.jar
这个jar包含spring框架基本的核心工具类,spring其他组件都要使用到这个包里的类。是其他组件的基本核心。
spring-beans.jar
这个jar是所有应用都要用到的,他包含访问配置文件,创建和管理bean以及进行Inversion of Control / Dependency Injection(IoC/DI)操作相关的所有类如果应用只需基本的IoC/DI支持,引入spring-core.jar和spring- beans.jar就已经足够了。
spring-aop.jar
包含一些使用AOP特性时需要用到的一些类。在使用spring 的AOP特性如Declarative Transaction Management(事务管理)就需要用到这个jar文件。
spring-context.jar
这个jar文件为spring提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类。JNDI所需的全部类,用来跟模板引擎集成(Velocity,FreeMarker,JasperReports)的类,以及校验相关类。
spring-dao.jar
包含Spring DAO、Spring Transaction进行数据访问的所有类,为了使用声明性事务支持还需要在自己的应用里包含spring-aop.jar
spring-hibernate.jar
是对Hibernate支持的所有类。
spring-orm.jar
该jar对spring DAO特性集合进行了扩展,使其支持iBATIS、JDOOJB、TopLink,由于spring将hibernate独立成包了,因此在这里没有在支持hibernate。这个文件里大部分的类都依赖spring-dao.jar中的类。
spring-remoting.jar
这个包提供对EJB、JMS以及远程调用(RMIHessianBurlapHttp Invoker JAX-RPC)相关的类
spring-support.jar
该组件提供对Cache(ehcache)、JCA、JMX,邮件服务(Java Mail、COS Mail),计划任务Scheduling(Timer、Quartz)支持的类
spring-web.jar
如果web开发中开发,而且用到用到spring框架,那就应该引入这个包,该组件包括WebApplicationContext特性的类、struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。
spring-webmvc.jar

该组件包含Spring MVC框架相关的所有类,包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。如果使用了独立的MVC框架则该组件不再需要。
spring-mock.jar

这个文件中包含Spring一整套mock类来辅助应用的测试。spring测试套件使用了大量的mock类,这样测试就更加简单了。由于可以对HttpServletRequest和HttpServletResponse进行模拟,使得对web进行单元测试更加方便。

包间引用关系:
Spring中各个包引入之前都需要保证引入 commons-logging.jar

spring-core.jar需 commons-collections.jar,spring-core.jar 是以下其他各个组件的基础。

spring-beans.jar需 spring-core.jar/cglib-nodep-2.1_3.jar

spring-aop.jar需 spring-core.jar/spring-beans.jar/cglib-nodep-2.1_3.jar/aopalliance.jar

spring-context.jar 需spring-core.jar/spring-beans.jar/spring-aop.jar/commons-collections.jar/aopalliance.jar

spring-dao.jar需 spring-core.jar/spring-beans.jar/spring-aop.jar/spring-context.jar

spring-jdbc.jar需 spring-core.jar/spring-beans.jar/spring-dao.jar

spring-web.jar需 spring-core.jar/spring-beans.jar/spring-context.jar

spring-webmvc.jar需 spring-core.jar/spring-beans.jar/spring-context.jar/spring-web.jar

spring-hibernate.jar 需 spring-core.jar/spring-beans.jar/spring-aop.jar/spring-dao.jar/spring-jdbc.jar/spring-orm.jar/spring-web.jar/spring-webmvc.jar

spring-orm.jar 需 spring-core.jar/spring-beans.jar/spring-aop.jar/spring-dao.jar/spring-jdbc.jar/spring-web.jar/spring-webmvc.jar

spring-remoting.jar 需 spring-core.jar/spring-beans.jar/spring-aop.jar/spring-dao.jar/spring-context.jar/spring-web.jar/spring-webmvc.jar

spring-support.jar 需 spring-core.jar/spring-beans.jar/spring-aop.jar/spring-dao.jar/spring-context.jar/spring-jdbc.jar

spring-mock.jar 需 spring-core.jar/spring-beans.jar/spring-dao.jar/spring-context.jar/spring-jdbc.jar

No responses yet

Spring Annotation(IOC篇)

Jul 28 2009 Published by Tony under Java

首先在application_context的xml配置文件中加入

<context:component-scan base-package="org.bean"/>

而且保证xml的schema中包括context名称空间。
@Component

//例如
@Component("member")
public class Member {
   private String id;
   }

这个Annotation主要用来定义bean。
@Service,@Controller,@Repository
这3个目前与@component同意,以后版本会细化。
@Autowired

//例如
@Component("member")
public class Member {
   private String id;
   @Autowired
   private Project project;
   }

这个Annotation主要用来自动查找context,并且关联其中的bean。
@Qualifier

@Component("member")
public class Member {
   private String id;
   private String name;
   @Autowired
   @Qualifier("project")
   private Project project;
   }

这个Annotation主要用来自动关联时的微调
@Scope

    @Scope("singleton")
    @Component("member")
    public class Member {
        private String id;
        private String name;
        @Autowired
        @Qualifier("project")
        private Project project;
        }

这个Annotation用来指定bean作用域与生成状态,默认为singleton,其他还有prototype(多个实例),request,session,global session,这3个是用在基于Spring ApplicationContext的Web项目。
在bean中我们已经看到了最基本的使用Java annotation的方式了,但是Spring对于Annotation还存在一些问题,比如:@Autowired同样可以应用于Collection中,比如List中。但是如果在List的属性中加上这个Annotation,那么通过容器初始化的bean会自动往 List中存放一个通过@Autowired自动查找出来的对象,这么做我也很难说它不对,但是还是感觉怪怪的。希望大家注意。
另外谈一下自动检测组件名称的方式(针对于@Component,@Service,@Controller,@Repository):如果给组件命名了,则按照这个名称注册到BeanFactory中,如果没有命名,则把小写开头的类名注册为组件名称。

@Component("project")
public class MyProject {
//......
}

如果是@Component,那么在ApplicationContext或者BeanFactory中注册的Bean名称是”myProject”,如果是@Component(“project”),则注册的Bean名称是”project”。
@Resource

    @Resource
    public void setOwner(Member owner) {
        this.owner = owner;
    }

或者

    @Resource(name="member")
    public void setOwner(Member owner) {
        this.owner = owner;
    }

其中特别之处在于@Resource如果加载属性或者setter之上,则按照属性名或者根据setter名称得到bean名称查找,如果找不到则按照类型查找。如果给@Resource加了name属性,则相当于按照这个名称查找,这种方式查找的优先级最高。

No responses yet

Spring Annotation(AOP篇)

Jul 28 2009 Published by Tony under Java

本文主要简单了解一下使用Java annotation的情况下,先介绍一下比较主流和简单的用法,Spring对AspectJ的支持。在ApplicationContext中加入关于AOP的命名空间,具体内容见Spring 使用AspectJ来配置AOP.首先明确一点,用作通知(Advice)的类也应该受到ApplicationContext的管理,之后再使用AspectJ的标签来管理通知动作,见代码:

//import ...
@Component
@Aspect
public class Alert {
    @Before("execution(* get*(..))")//方法运行前通知
    public void show() {
        System.out.println("before");
    }
    @After("execution(* get*(..))")//最终通知
    public void show2() {
        System.out.println("after");
    }
    @Pointcut("execution(* get*(..))")
    public void afterReturn(){}
    //方法返回值通知,注意这个通知需要与@Pointcut配合使用
    @AfterReturning(pointcut="afterReturn()",returning="value")
    public void returning(Object value){
        System.out.println("returning");
    }
    @AfterThrowing(pointcut="afterReturn()",throwing="ex")
    //异常通知,这个通知复用了afterReturn的pointcut。当然你也可以使用新的pointcut
    public void doRecoveryActions(Exception ex){
        //...
    }
    @Around("afterReturn()")
    //环绕通知。真正的方法实际上是joinPoint.proceed();
    public Object doSomeForAround(ProceedingJoinPoint joinPoint) throws Throwable
    {
       System.out.println("before around");
       Object retVal=joinPoint.proceed();
       System.out.println("after around");
      return retVal;
    }
}

这段代码的意思就是在所有以get开头的方法被调用之前和之后都会执行show和returning,show2方法,其运行顺序是 show(),returning(),show2()。注意*与get*之间有一个空格。对一个方法,你可以同时使用Before Advice,Around Advice,AfterReturning Advice,After Advice,Throwing Advice。那么这些通知的顺序是什么呢?一个方法运行时,最先触发的是Around Advice,之后是Before Advice 是 AfterReturning(如果有的话),之后是After Advice,最后还要再通知Around。
就拿上面代码这个例子说,打印的顺序是:

before around
before
returning
after
after around

下面着重介绍一下除了execution之外的其他类型的pointcut。
within:within指的是在某个范围内所有的方法执行。
例如:
@pointcut(“within(com.xyz.project.web..*)”)就是指在com.xyz.project.web包及其子包中所有的方法被执行的时候,都会触发这个pointcut。within(com.xyz.project.web.*)这样写就只是针对这个包,而不包括这个包的子包。
this:this指的是实现了某个确定的接口的代理对象中的方法被执行。
target:target指的是实现了某个确定的接口的代理对象中的方法被执行。

No responses yet

JRuby On Spring在spring框架中使用Jruby

Apr 23 2009 Published by Tony under Ruby

昨天尝试在Spring中使用脚本语言,比如jruby,发现非常不方便,最主要的一点就是ruby class必须继承某一个java的接口,而其他bean调用时也是调用这个接口类型的对象。jruby的动态性基本丧失了。唉!

No responses yet