Monthly Archives: May 2012

开发环境要不要和测试环境隔离?  

开发环境要不要和测试环境隔离?  要就是说,是不是要各用一套数据库等基础设施?

能隔离当然最好,开发人员和测试人员不会互相干扰。 但隔离是有代价的,它意味着你要多引一个数据库,如果你的系统是分布式的,你还要多维护一套MQ、RPC中间件等。

依我看,需不需要隔离要看系统是否满足下面的三个条件:

1. 两个环境的系统总是要接触到同一份数据

2. 数据被一个系统接触后,业务状态会改变;导致这份数据对另一个系统不再可用

3. 很难禁止两个系统在同一时刻接触到同一份数据

解释:

条件1. 如果两个环境共享数据库,但开发环境只处理北方数据,测试环境只处理南方的,那不用隔离

条件2. 即使两个环境都会处理北方数据,但如果这种处理是只读的,也就是开发环境用了,测试环境可以再用,那也无所谓

条件3. 即使数据被一个环境处理后,另一个不能用;但如果对数据的接触是人为触发的,也就是说开发环境被人触发数据改动时,不会干扰测试环境的测试,那也无所谓。

具体的场景:

1. 纯读的网站不必隔离,它不满足条件2

2. 有写、但所有操作都由用户触发的网站也不必隔离,因为它不满足条件3

3. 以全局数据为目标的自启应用需要隔离,比如 Quartz, Cron, MQ消费者等,因为它们不满足条件1。 以MQ应用为例,如果外部发来的某个数据被测试环境消费过了,开发环境就无法再消费了,这时你应该为开发和测试环境各配一个MQ

4. 对自启应用,如果实在不想隔离,就要在代码里做一些env-specific的东西,使得不同环境不会访问到相同的数据,比如开发环境只能访问数据库里flag=Dev的记录。不过,这种作法对程序和数据的侵入都很大,不值得提倡。 但这种做法可以应用到其他环境的隔离上,比如预发环境和正式环境,它们必须使用相同的数据库。

未必是好习惯:方法的返回类型用List,而不是ArrayList

如果你使用java超过一年,你可能会这样定义方法的签名:

List getList(){
  List list = new ArrayList();
  ...
  return list; 
}

也就是说,你会让方法返回抽象的List,而不是具体的ArrayList, 这样你可以获得比较强的封装性。

然而,这种强封装同时意味着损失了一定的信息量。 当客户端拿这个list对象时,它不知道这个list是不是modifiable的,也不知道执行list.get(n)的时间复杂度是O(1) (链表)、还是O(n) (数组)。

所以,当有必要向客户端透露返回值的特性时,直接用具体类型会更好些:

ArrayList getList(){
  ArrayList list = new ArrayList();
  ...
  return list; 
}

spring支持Bean的继承

原文:
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-child-bean-definitions

Bean的继承和类的继承一样,都是为了减少重复键入:父Bean里的属性可被子Bean自动继承,在写子Bean时就不用再次键入这些属性了。

当然,子Bean可以覆盖父Bean的属性

最后,父Bean还可以做成abstract的。抽象的父Bean可以不与任何java类绑定

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
    parent="inheritedTestBeanWithoutClass" init-method="initialize">
  <property name="name" value="override"/>
  <!-- age will inherit the value of 1 from the parent bean definition-->
</bean>

不过,子Bean并不会继承父Bean的所有特性。文档说: The remaining settings will always be taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.

与其把类命名为ABCService, 不如叫AbcService

ABC是个专有名词,一般情况下对应的service应该叫做ABCService; 然而,我建议还是叫AbcService,否则对应的实例名会很别扭:

    private ABCService aBCService;
    public void setABCService(ABCService aBCService) {
        this.aBCService = aBCService;
    }

你会说变量名可以这样写:

    private ABCService abcService;
    public void setAbcService(ABCService abcService) {
        this.abcService = abcService;
    }

这当然没问题。但很多代码生成器会因此失效,因为这些工具一般都期望类名和实例名只有第一个字母的大小写不同。

所以,还不如换成AbcService,虽然这种命名中失去了“专有名词”的信息,但可以保证你写代码的流畅度:

    private AbcService abcService;
    public void setAbcService(AbcService abcService) {
        this.abcService = abcService;
    }

分布式架构中系统间使用异步通信的好处

1.性能

a.
降低平均响应时间,提高总体吞量

    这是因为异步通信时,一个系统向另一个系统发出请求后不必等待对方返回即可继续干自己的事。详细的推导可见
http://www.cnblogs.com/chenjianjx/archive/2012/03/27/2420262.html

(待续)

2.高可用

  a.
单个系统的故障不会立即导致另一个系统的某些功能不可用

     同步通信时,如果Provider当机,则Consumer的调用就会立即失败,既而造成Consumer系统中的某些功能不可用;换成异步通信时,如果Provider不可用,Consumer不受影响,因为Consumer只是把消息丢进了消息队列,并没有跟Provider直接交互。 消息队列一般有消息持久化的功能,当Provider恢复时,会收到队列发过来的消息。

     当然,如果Provider一直当机,Consumer发出的请求一直得不到处理,Consumer本身的功能可能终究也会出问题,并最终导致不可用。 具体情况取决于具体的业务逻辑。

(待续)

3.软件发布

   a.
Provider发布重启时,Consumer在短期内不受影响

     原因与上面的2.a相同。这里

(待续)

无废话:如何使用ibatis type handler  

使用ibatsi时,如果你的javabean中有个属性不是string, date, int等数据库直接支持的类型,那么就要用自定义ibatis type handler,来告诉ibatis在对它进行数据库存取时应该如何做java type与sql type的互转。

1. 建一个类实现TypeHandlerCallback接口, 如

  public class SomeTypeHandlerCallback implements TypeHandlerCallback {
     ....
  }
 

2.在sql map文件中使用它。为了避免写起来太啰嗦,建议先定义一下typeAlias

<typeAlias alias="someTypeHandlerCallback "
	type="com.some....SomeTypeHandlerCallback" />

  

3.在用于查询的resultMap中引用一下

	<resultMap id="helloResult" class="hello">
                ...
		<result property="some" column="SOME"
			typeHandler="someTypeHandlerCallback"/>
                ...

4.在用于增、改的parameter中也要引用一下

<insert id="insertHello" parameterClass="hello">  
     <![CDATA[  
       insert into 
       		hello
       (			 
	        ...,
                SOME
       )values
       (		 
                ...
		#some,handler=someTypeHandlerCallback#       ,
       );
     ]]>

特别注意: 上面的","和"handler"之间不能有空格