AOP专题

  探讨Spring框架使用真相

板桥里人 https://www.jdon.com 2004/08/25

  最近,Spring很热闹,因为实现IoC模式和AOP(见本站专栏),然后又成立公司,吸取上次JBoss的教训,文档不敢收费,结果迎来了一片祝贺声。

  Spring真正的精华是它的Ioc模式实现的BeanFactory和AOP,它自己在这个基础上延伸的功能有些画蛇添足。

  其实说白了,大家"惊奇"的是它的IoC模式(使用AOP功能需要了解AOP,比较难),那么,Spring之类的Ioc模式是什么? 就是:你在编制程序时,只要写被调用者的接口代码,具体子类实例可通过配置实现。

  Ioc模式是什么知道的人不多,但是,当他知道生成对象不用再使用new了,只要在配置文件里配置一下,他感到新鲜,其实这就是Ioc模式的实现,PicoContainer是另外一种真正轻量的Ioc模式实现,PicoContainer还是采取代码将对象注射一个小容器中,而Spring采取配置文件。

  配置式编码其实有利有弊,编码本来可通过开发工具或编译器检查错误,但是过分依赖配置时,就会经常出现因为粗心导致的小错误,如果调试程序出错经常是因为配置文件中小写字母写成大写字母,不知道你是怎么心情?

  Spring最近还发表了Spring without EJB的书,这倒是说了实话,Spring和EJB其实是相竞争,如同黑与白,如果硬是将两者搭配使用,显得不协调,更不是一些人所谓优化EJB调用的谣言,原因下面将会分析。既然Spring+EJB有缺陷,那么就直接使用Spring+Hibernate架构,但是又带来了新问题:无集群分布式计算性能,只能在一台机器上运行啊,具体分析见:可伸缩性和重/轻量,谁是实用系统的架构主选?

  下面来分析所谓Spring+EJB的不协调性,正如水和油搅拌在一起使用一样。
  目前,Spring+EJB有两种应用方式:

  1. Spring不介入EJB容器,只做Web与EJB之间的接口,这个位置比较尴尬,Web层直接调用EJB的方法比较直接快捷,为什么要中间加个Spring?可实现Web缓存?使用性能更好的AOP框架aspectwerkz啊;实现Web和EJB解耦?这样的工具更多,自己都可以做个小框架实现,就不必打扰背着AOP和IOC双重重担的Spring了吧。

  2. Spring介入EJB容器,这时,需要在你的ejb-jar.xml中配置beanFactoryPath值指向你为EJB配置的applicationContext.xml,那么你的EJB还需要继承Spring的SimpleRemoteStatelessSessionProxyFactoryBean。

  好了,现在你的SLSB(无状态Session Bean)成为下面这个样子:

  void updateUser(){
    
      myService.updateUser(); //委托给一个POJO的方法,真正业务逻辑封装在这个POJO中

  }

  这样做有很多“优点”,当然最大“优点”是:

  由于真正业务核心在POJO中实现,因此,只要改一下applicationContext.xml配置,这样,调试时,前台就可以直接调用POJO,不必通过EJB,调试起来方便了,这有一个前提:他们认为调试EJB复杂,其实不然,在JBuilder中,结合Junit,测试EJB如同测试POJO一样方便,这是其他分支,不在此讨论。当部署使用时,再改一下applicationContext.xml配置,指引前台调用到EJB。

  似乎很巧妙,这里有两个疑问,首先,指引到EJB的改变是什么时候做?持续集成前还是后,在前在后都有问题,这里不仔细分析。

  这种表面巧妙的优点带来最大的问题是:粗粒度事务机制。所谓粗粒度事务机制,最早见于Petstore的WEB调用EJB Command模式,在这个帖子中有讨论。

  下面以代码描述什么是粗粒度事务机制:

  ejb方法:
  public void updateUser(){
    service.updateUser();
  }

  service是一个POJO,具体方法可能是更新两个表:
  public void updateUser(){
    updateTabel1();//更新table1
    updateTable2(); //更新table2
  }

  当updateTable2()抛出异常,updateTable1()是不回滚的。这样,table1中就有一条错误的多余的记录,而table2则没有这条记录。

  那么,怎么做才能使两个表记录一致,采取事务机制,只有下面这样书写才能实现真正事务:
在EJB方法中写两个方法,因为EJB方法体缺省是一个事务。
  public void updateUser(){
    updateTabel1();//更新table1
    updateTable2(); //更新table2
  }

  关于EJB自动的事务机制,最近也有一个道友做了测试,对于JBoss中容器管理的事务的疑惑。

  如果你从事关键事务,就是带money相关操作的事务,这种粗粒度机制可能害苦你,那么,似乎有一种办法可弥补事务,不使用EJB容器事务(CMT),在service中使用Spring的事务机制。

  如果使用Spring事务机制,业务核心又在POJO中实现,那么我有一个疑问:还要套上EJB干什么?至此,你终于明白,Spring本质是和EJB竞争的,如果硬套上EJB使用,只是相借助其集群分布式功能,而这个正是Spring目前所缺少的。

  我太惊异Spring精巧的诡异了,他和EJB关系,正如异型和人的关系一样。

  为了避免你每次使用Spring时想到粘糊糊的异型,不如Spring without EJB,这也正是Spring的初衷,也是它的一个畅销书名。

参考文章:

Spring专题

Spring 和EJB终于统一融合

国人最早开源IOC/AOP框架JdonFramework

Ioc模式(又称DI:Dependency Injection)

IOC模式的思考和疑问

Ioc容器的革命性优点

Java企业系统架构选择考量

JBoss 5迎来Java的彻底的可配置时代

Jive论坛与Spring框架


发表讨论..

 

更多依赖注射专题

更多AOP专题

更多关于IOC讨论

更多关于AOP讨论

更多关于Spring讨论