avtivemq和规则引擎资料(旧)

10年时接触activemq和drools时收集的一些资料

activeMQ资料

activeMQ官方网站
JMS消息类型模型
实战activeMQ
ActiveMQ4.1 +Spring2.0的POJO JMS方案(上)整理版
ActiveMQ4.1 +Spring2.0的POJO JMS方案(下)整理版
ActiveMQ5.0实战一: 安装配置ActiveMQ5.0
ActiveMQ5.0实战二: 基本配置
ActiveMQ5.0实战三:使用Spring发送,消费topic和queue消息
ActiveMQ测试报告,这是一个很棒的报告
ActiveMQ 高级特性
Articles on ActiveMQ, Messaging and JMS 来自官网的文章集锦

客户端

关于客户端都可以在相应的官网上找到,这里要说的一个客户端是openamq-jms,简单来说,这是针对java JMS的客户端, 可用于OpenAMQ和其他AMQP服务器。还有一个是StompConnect,当然这是走stomp协议的,特色就是把JMS弄成一个Stomp Broker, 具体是怎样的,还没实践过。不过,要跨语言消息交互,更好的选择是使用已经提供的本地Stomp支持。另外,关于stomp的erlang客户端可以选择gigix推荐的stomperl

书籍

其实官方文档已经非常丰富,书籍的意义并没有那么大~~另一方面,关于ActiveMQ的书籍暂时还没有上市,只有本期书(activeMQ in action), 现在可以在网上找到这本书的手稿版~确实找不到的话,可以找我要,呵

activemq和rabbitmq

activemq和rabbitmq都是非常有名的开源消息队列。activemq是java写的,而rabbitmq是erlang写的。 activemq支持的是stomp和openwire,xmpp等协议,而rabbitmq支持的是amqp(Advanced Message Queuing Protocol)。 stomp是一个简单的容易实现的基于文本的协议,openwire是一种快速的二进制协议,activemq计划在amqp协议1.0版本完成的时候提供amqp协议的支持。 通过这些协议,activemq可以支持多种客户端,如C, C++, C#, Ruby, Python, Perl, PHP等等。而amqp同时定义了消息中间件的语意层面和协议层面, 并且是语言中立的,它可以让MQ成为一个可编程的消息中间件,可以想象这样的场景: 你使用java写的消息通过Erlang编写的中间件来和一个C编写的遗留系统进行消息交互。所以amqp前途是光明的~~

2009-01-15附加

activemq的failover功能配置很简单~例如简单修改brokerURL为”failover:(tcp://caixiaojian.hnjk.com:61616?wireFormat.maxInactivityDuration=0)”,正常情况是会出现下面的信息:

ActiveMQ Task 15/01 16:52:43,672 DEBUG [failover.FailoverTransport]-802 Waiting 5120 ms before attempting connection.
ActiveMQ Task 15/01 16:52:45,569 DEBUG [failover.FailoverTransport]-593 urlList connectionList:[tcp://caixiaojian.hnjk.com:61616?wireFormat.maxInactivityDuration=0]
ActiveMQ Task 15/01 16:52:45,569 DEBUG [failover.FailoverTransport]-712 Attempting connect to: tcp://caixiaojian.hnjk.com:61616?wireFormat.maxInactivityDuration=0
ActiveMQ Task 15/01 16:52:45,570 DEBUG [failover.FailoverTransport]-753 Connect fail to: tcp://caixiaojian.hnjk.com:61616?wireFormat.maxInactivityDuration=0, reason: java.net.ConnectException: Connection refused
ActiveMQ Task 15/01 16:52:45,570 DEBUG [ tcp.TcpTransport]-458 Stopping transport tcp://null:0

2009-01-16附加

结合spring和activemq的时候,发现启动挺慢的。因为老是会去网上寻找xsd文件,把xml里边的schemaLocation换成下面这个样子就可以了: http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd ActiveMQ的Virtual Destinations和Mirrored Queues非常有价值,5.3新增的Message Groups也是很有用的特性来的

规则引擎资料

Java规则引擎与其API(JSR-94) 介绍jsr94标准
使用 Drools 规则引擎实现业务逻辑 一个简单的例子
在你的企业级java应用中使用Drools 提供web层和dao层的简单继承,不过rule用的xml格式~
drools和spring的集成 集成spring好像是必备功能似的
规则引擎实现探讨 一个小讨论,还看到一段Erlang代码
应用规则引擎组织业务规则的注意要点 里边提到一些建议和规范
看惯中文的,感觉这个blog还行,但是内容是基于drools3的
一个小学题目的解: 采用规则引擎Drools实现 一个喝汽水的智力题,一个比较不错的例子
springside里边用的jboss rules
另外还有drools官方文档,关于最重要的rule language和example部分是在Drools Expert上

其他想法

我对规则引擎理解不深,从drools的例子可以看到一些AI,workflow,专家系统的影子,看似用途很广很强大,可是规则引擎不是这么个用法的把
按照我的想法,规则引擎应该用在局部复杂的流程控制上(局部复杂的if else…),应该是基于业务走向的判断。
如上面yimlin提到的,我觉得规则引擎是来简化工作的,所以要避免任何具有实际意义的业务操作,很容易让人混淆。
怎么说这些规则也不大可能是客户来维护的了,因为可能涉及事实库的修改,dsl顶多也是对程序员友好的方式。
哪些业务规则适合抽象出来由规则引擎处理,规则引擎和业务系统的交互方式是主要问题。

引入规则引擎真的会带来很多好处么?对很多系统来说,这种java应用中嵌入groovy的方案还算满经济的。

maven学习要点(旧)

我感觉maven这东西比ant容易上手(ant每个项目规则都不一样),看那个100页的迷你书+例子(推荐basecrm或spring3.0)基本就ok了~~ 哎,本来想写的很多,发现写出来的却很少。多多包涵!

  • maven是一个项目管理工具,跟ant相比亮点在于它遵守了COC规则,只要遵守就好处多多
  • maven可以分为三部分:maven本身(提供基本功能),仓库(提供jar),maven插件(提供更多的集成功能)
  • maven的配置文件是settings.xml,maven项目的配置文件是pom.xml
  • settings.xml主要是配置仓库镜像,本地仓库,网络访问设置等信息,常用配置:
 <localRepository>D:/repository</localRepository> --本地仓库
   <proxy>  --网络代理
     <id>optional</id>
     <active>true</active>
     <protocol>http</protocol>
     <username>proxyuser</username>
     <password>proxypass</password>
     <host>proxy.host.net</host>
     <port>80</port>
     <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
   </proxy>
  <mirror>  --仓库镜像
    <id>nexus</id>
    <mirrorOf>*</mirrorOf>
    <name>Mirror for maven central.</name>
    <url>http://10.137.27.223:8080/nexus/content/groups/public</url>
  </mirror>
  • pom.xml主要分为三部分:项目本身的信息,使用的插件,依赖的jar
  • 项目本身的信息,用于唯一标识(groupid-artifactId-version, 通常是这3部分),例如
 <modelVersion>4.0.0</modelVersion> --maven3.x都是使用4.0.0
 <groupId>com.huawei.boss</groupId>
 <artifactId>boss-common</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

类似这个,默认就会被打包成boss-common-0.0.1-SNAPSHOT.jar。同样,项目的依赖库也是通过这种坐标在仓库中寻找的。

  • artifactId通常推荐使用项目名当前缀,当项目是打包成war的时候,通常需要制定发布后的命名:
 <build>
   <finalName>bossbase</finalName>
 </build>
  • 可以通过properties定义一些常量,并通过${spring.version}之类来引用
 <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
       <spring.version>2.5.6</spring.version>
 </properties>
  • jar包依赖常用的有如下配置(仅举例说明):
 <dependencies>
     <dependency>
           <groupId>org.springframework</groupId>
               <artifactId>spring-core</artifactId>
             <version>${spring.version}</version>  --常量引用,在引用同个项目多个模块的时候相当有效
           <type>jar</type>  --默认就是jar
             <scope>compile</scope>  --默认是compile,表示对编译,测试,运行都有效
       </dependency>
    <dependency>
          <groupId>geronimo-spec</groupId>
            <artifactId>geronimo-spec-jta</artifactId> --这个是为了不依赖sun的专用东东
           <version>1.0.1B-rc4</version>
                <type>pom</type>
          <scope>provided</scope>  --在运行的时候不依赖,我们常见的时候j2ee规范之类的api,如servlet-api
  </dependency>
       <dependency>
             <groupId>junit</groupId>
               <artifactId>junit</artifactId>
           <version>4.8.2</version>
             <type>jar</type>
               <scope>test</scope>  --只在测试的时候生效,另外还有个ruuntime的scope,用于运行时依赖(如jdbc驱动等)
      </dependency>
   <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate</artifactId>
     <version>3.2.5.ga</version>
     <exclusions>  --这里是排除依赖,因为jta官方版是在maven仓库中找不到的
       <exclusion>
         <groupId>javax.transaction</groupId>
         <artifactId>jta</artifactId>
       </exclusion>
     </exclusions>
   </dependency>
 </dependencies>
  • 当项目是分模块进行的时候,通常会考虑使用modules,如:
   <modules>
       <module>basecrm-parent</module>
       <module>common</module>
       <module>systemmgr</module>
       <module>prodmgr</module>
   </modules>

这个时候至少会有两级pom.xml,这样像properties,dependency等都是可以继承的(可参考basecrm项目或者spring3.x)

  • plugin资源非常多,简单举几个常用插件(配置请上网找)
    maven-compiler-plugin 主要是配置编译方面的选项(例如使用什么版本的jdk)
    maven-surefire-plugin 跟测试有关的,例如配置测试失败是否继续,是否跳过测试等
    build-helper-maven-plugin 用于配置项目的目录结构,例如配置多个源代码目录等
    maven-shade-plugin 我只知道可以用来给打包加点料~~
    tomcat-maven-plugin 顾名思义,用于集成tomcat
    maven-jetty-plugin 顾名思义,用于集成jetty

  • others
    maven仓库代理推荐nexus(网内已经有个现成的:http://10.137.27.223:8080/nexus)
    eclipse中的maven插件推荐m2eclipse(update-site: http://m2eclipse.sonatype.org/sites/m2e)
    maven实战迷你书(http://www.infoq.com/cn/minibooks/maven-in-action)

jstl学习经验(旧)

为了在公司里边推广jstl,而总结的一些jstl使用技巧:

jstl可以很方便的处理NullPointException,访问越界等常见问题

<c:set var=”SPExtraInfoList” value=”${queryresult[3]}”/>
<c:out value=”${queryresult[3]}”/>

这2个表达式不会因为没有第四个元素而报错

这2个表达式一般情况下表现是一样的,只是用c:out可以带上default的参数来处理NullPointException

<td><c:out value=”${spservice.m_SpID}”/></td>
<td>${spservice.m_SpID}</td>

即使担心其他Exception,也可以通过c:catch来做防御

<c:catch><c:out value=”${values[9]/1000.00}”/></c:catch>

fn:length的使用

用来判断集合类型或String的长度,不过只是用来判断obj是否为空的话,用le语言${empty obj}更方便(同样支持多种类型)

关于fn:split

用这个方法切割会丢失空字符串,原因是这个标签使用StringTokenizer来处理而不是split方法。

<% String[] values = ((CEntityString)pageContext.getAttribute(“service”)).EntityString.split(“,”);
   pageContext.setAttribute(“values”, values);  %>

这是比较丑的例子,对格式依赖比较严重,所以最好就使用比较清晰的结构

关于if-else和三元表达式

jstl做判断分支是比较麻烦的,只提供了c:otherwise的方式,只好将就点先用着吧。如

<c:choose><c:when test=”${’1′ eq spextrainfo[0]}”>是</c:when><c:otherwise>否< /c:otherwise></c:choose>

jstl改变操作

jstl里边要做访问操作是比较方便的,不过涉及改变就挺麻烦的,如对某个字符串加个头,然后在Map里边检索,这样就不能在一个表达式里边写完,需要先c:set一下,如

<c:set var=”bzType” value=”BizType${spservice.m_SpBizType}”/>
<c:out value=”${BizTypeMap[bzType]}”/>

ibatis进阶(旧)

Ibatis比较少人使用的配置语法

简单来说,ibatis3虽然没有ognl,不过也支持基本的表达式(看起来有点像el表达式的样子) 上次有个问题,说到两个表单数据(两个javabean),入同一个表,传参就应该不成问题了

java代码1:

   Map map = new HashMap();
   ComplexBean bean = new ComplexBean();
   bean.setMap(new HashMap());
   bean.getMap().put("id", new Integer(1));
   map.put("bean", bean);
   Account account = new Account();
   account.setId(2);
   Account anotherAccount = new Account();
   anotherAccount.setId(3);
   map.put("accounts", new Account[] {account, anotherAccount});
   Integer id = (Integer) sqlMap.queryForObject("mapBeanMap", map);

ibatis配置1:

 <select id="mapBeanMap"
   parameterClass="map"
   resultClass="int" >
   select count(ACC_ID) from Account where ACC_ID in (#bean.map.id#,#accounts[0].id#,#accounts[1].id#)
 </select>

java代码2:

   Map map = new HashMap();
   ComplexBean bean = new ComplexBean();
   bean.setMap(new HashMap());
   Account account = new Account();
   account.setId(2);
   Account anotherAccount = new Account();
   anotherAccount.setId(3);
   bean.getMap().put("accounts", new Account[] {account, anotherAccount});
   map.put("bean", bean);

ibatis配置2:

 <select id="mapBeanMap2"
   parameterClass="map"
   resultClass="int" >
   select count(ACC_ID) from Account where ACC_ID in
   <iterate close=")" open="(" conjunction="," property="bean.map.accounts">
     #bean.map.accounts[].id#
   </iterate>
 </select>

ibatis与泛型

当使用复杂配置并且参数带有泛型的时候,使用比较标签有可能导致如下错误:There is no READABLE property named ‘XXX’ in class ‘java.lang.Object’.这是因为进行比较的时候,ibatis是通过反射获取类型而不是先计算值的,这样泛型的时候会获取到Object类而不能得到真实的类型,自己简单打个补丁先:

Index: src/com/ibatis/sqlmap/engine/mapping/sql/dynamic/elements/ConditionalTagHandler.java
===================================================================
--- src/com/ibatis/sqlmap/engine/mapping/sql/dynamic/elements/ConditionalTagHandler.java (revision 1079874)
+++ src/com/ibatis/sqlmap/engine/mapping/sql/dynamic/elements/ConditionalTagHandler.java (working copy)
@@ -72,14 +72,13 @@

     if (prop != null) {
       value1 = PROBE.getObject(parameterObject, prop);
-      type = PROBE.getPropertyTypeForGetter(parameterObject, prop);
     } else {
       value1 = parameterObject;
-      if (value1 != null) {
-        type = parameterObject.getClass();
-      } else {
-        type = Object.class;
-      }
+    }
+    if (value1 != null) {
+     type = value1.getClass();
+    } else {
+     type = Object.class;
     }
     if (comparePropertyName != null) {
       Object value2 = PROBE.getObject(parameterObject, comparePropertyName);

关于inlineParameterMap

例如#name#(标准配置),#name:NUMBER#(以:分割),#myVar:javaType=int#都是有效的 其中以:分割的有两种方式,#name:jdbcTypeName#,#name:jdbcTypeName:nullvalue#(如果后面还有则会被加到nullvalue上去) 这是老配置方法,个人不推荐使用。 最后一种是新的配置方式,可以带上javaType,jdbcType,mode,nullValue,numericScale,handler等参数(这个文档有详细描述)

jdbcType,javaType和TypeHandler

首先要说明一点的是,配置里边的jdbcType和javaType两个配置参数是为了生成TypeHandler(如果没有指定的话); 查找typeHandler的内部结构是Map<javaType, Map<jdbcType, typeHandler>>,其中javaType是一个类,jdbcType是一个字符串; 所以jdbcType其实和数据库的字段类型没什么关系,只要能找到相应的TypeHandler即可(当然通常都会对应上); typeHandler主要是做什么用的呢?无非就是使用jdbc api的时候选择setString/setInt还是getString/getObject之类

只指定resultClass,没有resultMap

如果没有指定resultMap,ibatis会根据parameterClass生成一个AutoResultMap对象; 对于AutoResultMap,里边的每个属性的映射对应的typeHandler是什么?

resultClass TypeHandler
Map ObjectTypeHandler
原型类型 相应类对应的typeHandler(javaType=?,jdbcType=null)
Bean 会对实例变量名称进行大写并和ResultSetMetaData信息进行对比,最后生成typeHandler(javaType=?,jdbcType=null)

所以使用parameterClass是map的时候,某些字段的处理可能会有点问题,例如oracle的NUMBER类型会被转成BigDecimal类;

只指定parameterClass,没有parameterMap

如果没有指定parameterMap,就会根据配置的sql解析inlineParameterMap; 其中每个参数的TypeHandler如果没有指定,会根据参数的类型来寻找,例如#name,jdbcType=NUMBER# 会根据name计算后的类型来制定javaType 这个typeHandler的好处可以对jdbc api友好,例如对于int默认会采用IntegerTypeHandler,这样会调用PreparedStatement#setInt, 而不是统统setString或者setObject。 通常参数类型和jdbc类型不对应的时候,需要考虑设置typeHandler或者使用更强类型的Bean而不是统统使用map;

findbugs使用有感(旧)

最近抽出点时间来处理项目上庞大的findbugs问题,处理过程中总结了下面几类参见的毛病:

关于IO流

见过的有写response的outputStream,文件下载,数据导出。这些场景涉及流读取、写入和最后的关闭,是findbugs检查的重灾区. 解决办法是使用common-io库,常用的方法有IOUtils#copy,IOUtils#write,IOUtils#closeQuietly。

关于无效变量操作

包括变量使用后置null,没有被使用的变量,虽然这种findbugs问题很低级,不过在系统中仍然存在很多。 处理办法是

  1. 变量使用后置null是没什么用的,JVM的GC比想象中智能多了;
  2. 假如变量在稍后的处理过程一定会被赋值,则init是没有意义的。
    遵循的原则是相关的变量和操作集中在一起,缩短变量的作用域(同时,这样也对JVM比较友好)

关于对象的延时加载

系统中有些类实现了延时加载的singleton模式,还有的Action类中的实例变量使用了延时加载的方式。 很不幸的是,singleton的延时加载实现几乎都是错的, Action类的实例变量延时加载也没什么意义。 要实现singleton,最简单的方式是预加载方式,如果想做延时加载,可以使用内部静态类的实现方式。

关于执行效率

包括string的修改操作,map的遍历操作。如果有string的大量修改操作,应该使用StringBuffer或者StringBuilder (在jdk5以上,StringBuilder适用于大多数场合)。而对于map的遍历,应该使用entrySet而不是keySet,这些注意一下就ok了。 另外系统有很多DateFormater的东西,用了很多静态变量来提高效率,可惜jdk的日期库是非常烂的,DateFormater也不是线程安全的东西,应该避免使用静态变量。

关于异常处理

Exception is caught when Exception is not thrown 这个findbugs问题在系统出现非常多,也是最难处理的问题。从这个点 就可以看出系统实现非常混乱,本来属于不同抽象层次的代码都堆在一起了,没有层次之分。这个问题一般是需要修改到那段逻辑的时候才会去 解决,通过抽取方法/类的方式,把异常进行抽象化,最后借助框架层次上的异常统一处理逻辑就通常可以把Action上面的所有的try-catch干掉。

关于注释

这其实不是findbugs问题。可以发现java代码里边很多注释是没什么用的,包括一些显而易见的注释,方法注释(通常只有方法描述是有点意义,其他都是抄模板的) 注释写不好,还不如不写,正确的做法是尽量写出自文档化的代码。