jBPM中的assignment

ZhangV

在jbpm的流程定义文件(processdefinition.xml)中当定义一个task的assignment的时候有几种选择:

  • Swimlane
  • Pooled Actors
  • Expression
  • Actor
  • Handler

这里分别描述一下每种的用法,以及使用场景。使用场景的理解很重要,只有清楚每一种用法的所适合的情形,以及他们之间的相互转换才能说是真的“会用了”。

Swimlane
泳道是用来处理一个流程中的多个任务必须由同一个人来处理的机制。所以,当一个流程的第一个任务实例被创建到指定的泳道后,第一个任务实例中的执行人被保 存,该泳道中的后续任务的处理人都是第一个任务的处理人。所以一个泳道有一个人员被分配,并且泳道中的任务不需要再分配人员。这里是指这个流程中的参与者或者角色。在实际的业务系统中,他可能根本就不是一个业务角色,可能是一个外部应用,也可能是一个处理过程,或者是几个业务角色的结合。所以要清楚他是指“在该流程中”的角色。在jPDL的user guide中写的很清楚也反复强调 – “process role”。
通过在流程定义文件中定义:
<swimlane name=”leader”>
<assignment class=”com.modofo.engine.swimlane.LeaderSwimlane”></assignment>
</swimlane>
同样可以实现运行时的结合实际应用进行灵活的任务分配。这也是目前我看到的使用比较多的方式。

Actor
相当于设置TaskInstance的actorId属性,主要用于获取某个actor的所有任务列表。设置方法在定义中描述actor-id属性,或者调用TaskInstance.setActorId(String)方法,或者在AssignmentHandler中调用assignable.setActorId(String)方法。

Pooled Actors
用于定义所有的任务参与人(candidates for task instance)。在查找某个参与者可参与的任务时使用,其实就是一个actor的集合,jBPM通过TaskMgmtSession.findPooledTaskInstances(String actorId)或者TaskMgmtSession.findPooledTaskInstances(List actorIds) 来查找任务集合。
注意:actor的优先级比pooled actors要高,所以如果同时设置两者,那jBPM只会用actor来查找,而忽略pooled actors。

一句话: actor被用来获取某个参与者的个人任务列表,pooled actors用来获取某个参与者可以参与的所有任务列表,或者说组任务列表。
使用这个actor集合的初衷就是为了不让任务分配和角色体系耦合。流程定义中始终都是只有参与者的名称和集合,而不存在用户,角色和用户组的具体设计。而使用Expression就耦合了这些信息在流程定义里。

Expression
如果你使用jBPM的identity component的话。你可以使用表达式定义的任务分配模式。通常这个表达式的形式是:

<assignment expression=’previous –> group(hierarchy) –> member(boss)’ />
我看了之后也不是很清楚,group和member是jBPM的identity componenet的概念,这个表达的意思大概是:使用之前的actor,然后在hierarchy组,并且member(角色)是boss的所有actor。这种方法仅限于使用jBPM的IC时使用。

Handler

指定你自己的AssignmentHandler实现。该接口只有assign方法。这种任务分配方式主要用于运行时的任务分配,而不是hardcode到定义文件里。使用场景,如果不想让原本应用中的访问控制与jBPM耦合起来,就可以使用这种方法来将jBPM中的任务分配代理出来。当然更好的定义是用swimlane,这样可以让定义文件看起来不是很凌乱。

Java桌面应用程序发布

java桌面,java桌面应用,桌面应用发布,java,exe,jsmooth,installer,安装包

最近用Java做了一个单机桌面程序, 就是想看看用Java开发桌面程序到底能够达到什么样的程度.

通常网上介绍的开发桌面程序(这里没有特指则都指用Java开发桌面程序)都是说用工具打包成一个jar,然后通过配置MANIFAST.MF来配置主程序和第三方类库.以后就可以通过双击jar使用本地的jvm来执行.

我这里在用一些工具把jar包装成exe,再把依赖的资源文件和exe一起发布为windows安装包.
使用的工具:
ant/eclipse – 把程序打包为jar
proguard4.0beta -混淆
jsmooth0.9.9 – 把jar打包为exe
HM NIS Edit2.0.3 -制作安装包程序

一个完整的发布过程应该还包括:加密,签名,这里暂不涉及。
下面我详细的说一下这四个步骤

第一步:把程序打包为jar
首先用ant或者eclipse打包程序为可执行的jar。也就是要在MANIFEST.MF指定main class,然后如果又第三方库的话还要指定Class-Path,如:
Manifest-Version: 1.0
Main-Class: com.modofo.mobarbr.Launcher
Class-Path: lib/ibatis.jar lib/spring.jar lib/commons- logging.jar lib/quaqua.jar lib/commons-dbcp.jar lib/commons-pool.jar lib/alloy.jar

注意:
1.Manifest-Version必须要指定,否则MANIFEST.MF文件将无效,也就是和没有一样
2.Class-Path里每一个jar要以一个空格隔开
3.如果用Eclipse打包的话,最好是使用自己写一个MANIFEST.MF,而不要让Eclipse自己去生成,因为自动生成的无法设置Class-Path
4.Class-Path中的路径指的是打包好的jar包执行所在的路径的相对路径,好像有点表达的不清楚:),例如
如果你打包好的jar叫modofo.jar并放到了D盘的根目录下,那么你需要在D:/lib中放入那些第三方依赖包,这样你的jar才能执行。
(我一开始以为是要把这些也打包到jar里)
第二步:混淆
使用proguard4.0beta,这是一个很强大的优化混淆工具,使用很简单,可以用。不详细介绍。还有一个国内的Java混淆器,感觉不是很好用,可能是不会用吧。
我的程序因为用到了spring,所以混淆起来不太方便,后来也就没有混淆。看来用spring做桌面程序有点问题,DI的信息都暴露了?有没有把文本文件也混淆掉的工具呢?-这个似乎把问题搞复杂了。-为什么要混淆呢? – 2007-11-11

第三步:把jar打包为exe
jsmooth,最新版本0.9.9,
可以设置依赖包的位置,jre的位置,这样你可以同时在制作安装包时捆绑一个jre,用你随同程序发布的jre。不过这样的代价是在发布的时候把jre也打包进去,80多兆阿!
jsmooth同时支持ant,你可以把这个过程也整合到build.xml里不需要每次都手动生成

<taskdef name=”jsmoothgen” classname=”net.charabia.jsmoothgen.ant.JSmoothGen” classpath=”resources/jsmoothgen-ant.jar” /> –定义task,指定路径
<target name=”genexe” depends=”archive”>
<copy todir=”${dist.dir}/db”>
<fileset dir=”db” />
</copy>
<copy todir=”${dist.dir}/lib”>
<fileset dir=”lib” />
</copy>
<jsmoothgen project=”resources/mobarbr.jsmooth” skeletonroot=”resources/skeletons” /> –必须要指定jsmooth配置文件,是你用jsmooth的配置程序生成的文档,skeletons是jsmooth用到的骨架文件,必须要指定
</target>

打包之后的文件路径结构:
projectroot
|_dist
| |_lib/*.jar
| |_db/*.*
| |_jre/*.* (如果有jre,你需要把jre所有文件copy到这里)
| |_myapp.jar
| |_myapp.exe
|_build.xml

这个时候如果把dist下的文件做成压缩包就可以发布了,绿色且跨平台的。如果这个已经满足了要求,下面的可以不用看了 。

第四步:制作安装包程序
NSIS是一个很很牛x的制作安装程序工具,但是它是要自己编写脚本。我懒,但我知道我不是第一个懒人,所以在sf上找到了 HM NIS Edit,可以通过一个配置向导直接生成NSIS脚本,进而生成安装包,向导很简单基本不需要看帮助,试几次就应该可以用的很熟了。
生成好的安装包在安装时可以选择安装的component,可以配置jre作为可选组件,这样用户在安装你的程序时可以选择不安装jre。
NSIS还会自动帮你生成卸载程序。
这样一个 myapp-setup.exe文件就生成了,运行起来和一般的window程序几乎没有差别。(启动稍稍慢一点),但它只是在window下使用的。

此外还试用了其他的安装包程序:
advanced installer:很强大,但是收费,推荐
installjammer:开源,但安装过程不支持中文
小兵安装包制作工具:国产,但收费
NSIS开源社区最流行的打包程序,需要学习脚本,但有NIS Edit,一切就简单了。
上面的过程基本没有涉及很细节的地方,如果要细节的话每一步都需要一篇详细介绍还要截图(都说了我很懒了),我觉得最重要的是工具的使用,怎么在各种各样的工具里找到最适合你使用的。
如果有问题可以一起探讨

如何实现改变JTable中的曾选中过的cell的背景

 

2006/5/14

扩展一个JTable,增加一个List记录每次点击选择的cell,将其index记录.然后用一个Renderer,如果cell被选择过,则修改背景颜色为红色.使用时候先实例化一个MyTable,在setCellRenderer.

public class MyTable extends JTable {

private ArrayList selected;

public MyTable() {
super();
selected = new ArrayList();

}
//将选中的cell列,行数记录
public void addSelected(Point p){
if(selected.contains(p)){
selected.remove(p);
}else{
selected.add(p);
}
}

//某个cell是否被记录过

public boolean hasSelected(int row, int column) {
return selected.contains(new Point(row,column));
}

}
实现一个renderer,当cell的index在记录历史中,则修改其背景

public class MyRenderer extends DefaultTableCellRenderer{
public MyRenderer(){
super();
setHorizontalAlignment(SwingConstants.CENTER);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
MyTable mt = (MyTable)table;
if(isSelected){
mt.addSelected(new Point(row,column));
}
if(mt.hasSelected(row,column)){
this.setBackground(Color.RED);
}else{
this.setBackground(Color.WHITE);
}
return this;
}
}

AOP与OOP

(最初发布在JavaResearch.org,现在整理好放到自己的地方.)

作者:Narayanan A.R. June 15, 2005
翻译:ZhangV 2005-06-28
原文出自:DevX.com
原文链接:http://www.devx.com/Java/Article/28422/0/page/1

首先你要明确的一点,AOP和OOP是两种不同的认识事物的角度,并不是说有了AOP就不要用OOP.AOP所关注的是传统OOP不能优雅解决的问 题.(程序员通常都是完美主义者,当解决某个问题不优雅的时候,那就意味着不完美.)下面将就一个简单的例子来说明他们到底如何的不同.

作为一个使用OOP多年的人来说,当我听说AOP可以解决一些OOP一直都不能优雅地解决的问题时,我觉得应该去探个究竟了.对两种技术的比较最能给我们实际应用提供见解.这里我设计了一个例子:一个OOP应用,其中某些方面适合使用AOP.

本文展示了一个简单的例子.一开始介绍了问题域,然后分别给出传统OOP的解决方法与结合了AOP解决方法.后者使用了 JDK5.0,JUnit,和 AspectWerkz.最后我会说明如何编写代码.读完本文后,我希望你能知道AOP到底是什么,用来解决什么样的问题.

问题域描述
一个软件公司雇佣一个程序员,指定给他一个业务部门并要求他随时向经理报告.当团队成员完成他们的目标时,经理会给他们相应的奖金.公司所需要的方案必须能够增加一个新的雇员并给当前的员工增加奖金.为了方便,我们用CSV文件存储数据.


图1 解决方案模型

类Manager(经理)继承自类Employee,包含一个额外的属性,Managing Project.一个部门可能包含很多员工.多个部门构成了公司.暂不考虑公司这样的一个类,因为它在问题域之外.

解决方案设计
以下流程图描述了解决方案设计.


图2 对象之间的交互(增加一个新的员工,指派给他一个部门和经理)

出于简单的考虑,本文只关注必需的细节.你也可以深入代码得到你想要的其他信息.
下载
EmployeeServiceTestCase, 一个JUnit测试用例,模拟一个最终用户,创建新员工记录,指派部门和经理.它获取所有可用的部门和经理数据并显示在图形界面上.为了实例化域对象 BusinessUnit和Manager,获得的记录将传递给工厂类.之后,通过给EmployeeService传递一个引用来创建一个 Employee对象.这个服务类使用EmployeeFactory创建对象,并把这个对象传给EmployeeRepository 来进行持久化操作.

应用程序中需要面向哪些”Aspect”
到目前为止,对模型和设计的讨论还限于一个较抽象的层面.现在,我转向这个应用的其他方面 – 这对理解AOP的价值至关重要.

操作所需的资源

<pre lang=”java”>

public static Set findAllBusinessUnits() throws RepositoryException {
Set businessUnits = new HashSet();
try {
FileReader businessUnitFile = null;
BufferedReader bufferedBusinessUnitFile = null;
try {
businessUnitFile = new FileReader(FILE_NAME);
bufferedBusinessUnitFile = new BufferedReader(businessUnitFile);
String businessUnitRecord;
while((businessUnitRecord = bufferedBusinessUnitFile.readLine()) != null) {
BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);
businessUnits.add(businessUnit);
}
} finally {
if(bufferedBusinessUnitFile != null) {
bufferedBusinessUnitFile.close();
}
if(businessUnitFile != null) {
businessUnitFile.close();
}
}
} catch(IOException ioe) {
String message = “IOError. Unable to find Business Unit records”;
logger.log(SEVERE, message, ioe);
throw new RepositoryException(message, ioe);
}

logger.log(INFO, “Manager Records returned:” + businessUnits.size());
return businessUnits;
}
</pre>

上面的代码通过FileReader和BufferedReader来读取CSV文件中的业务数据.
应用程序重复地从资源文件中取得数据然后在操作完成后释放. 我们会发现:去掉程序的这两个”Aspect”将提高代码的可读性并达到一个更好的设计,因为去掉这些”多余”的东西,剩下的代码才是这个方法真正的精 髓.这个方法的作用是读取业务单位数据.所以不应该也不需要去知道”如何获取和释放资源以及这个过程中出现的异常”这个”切面”.同样地,使用AOP处理 异常也变得不同.(后面将详细介绍)

持久层
传统的OOP使用持久化类(repository classes)来持久应用程序的持久层.即:

<coolcode lang=”java” linenum=”off”>
public class EmployeeRepository {

public static void createEmployee(Employee employee) throws RepositoryException {
//使用print writer把数据放入csv文件
}

public static String findEmployeeRecordById(String id) throws RepositoryException {
//使用file reader来获得指定id的员工数据
}

public static Employee findEmployeeById(String id) throws RepositoryException {
//使用该方法获取员工数据,Employee对象由工厂类创建
}

public static void updateEmployee(Employee employee) {
//更新员工数据
}
}
</coolcode>

类EmployeeService 使用一个EmployeeRepository给应用中相关雇员提供服务,在一个企业应用中,从域模型 (domain model)中去掉持久层代码是一种设计上的改进.模型设计者和程序员就可以关注各自的业务逻辑和持久层处理.后面你将会看到如何通过 AOP来达到这样的效果.

日志
删除用于调试的日志代码将会极大地改进代码的可读性.考虑下面的代码片断:

1.
2. public Employee createEmployee(String name,
3. String contactNumber,
4. BusinessUnit businessUnit,
5. Manager manager)
6. throws EmployeeServiceException {
7. String id = createNewEmployeeId();
8. Employee employee =
9. EmployeeFactory.createEmployee(id, name, contactNumber, businessUnit, manager);
10. try {
11. EmployeeRepository.createEmployee(employee);
12. } catch(RepositoryException re) {
13. String message = “Created employee successfully:” + employee;
14. logger.log(SEVERE, message);
15. throw new EmployeeServiceException(message, re);
16. }
17. logger.log(INFO, “Created employee successfully:” + employee);
18. return employee;
19. }

上面的代码里包含了一个致命错误和一个成功信息.输出日志这一”Aspect”同样可以移到业务模型外独立实现.

异常处理
异常处理的例子我这里不再赘述,但这节已经通过上面的代码讨论了潜在的问题.当你调用EmployeeRepository 对象的 createEmployee 方法时,你可能会得到一个RepositoryException异常.传统的解决方法是,在这个类中处理.另一种方法是,当 RepositoryException 异常被抛出时createEmployee 方法返回null,catch块中的其他逻辑可以在类外处理这一错误.
错误处理在不同的情况中也会不同.但是,通过AOP可以区分开每种情况.

图3

图3中描述了AOP方法的设计以及在一个更抽象的层次上类间的交互.你可以通过对比图1和图3来更好地理解AOP.
程序的目的是通过BusinessUnit对象读取CSV文件中的记录然后填入类BusinessUnitService 中的map.使用AOP来填充这个map有点类似后门(backdoor)方法 — 控制被委派给BusinessUnit 来读取存储介质中的记录.

AOP就是定义一些切入点(pointcut)和处理方法(advice).一个”切入点”是源代码中一个执行点.前面的例子定义了一个”切入点” — 类 BusinessUnitService中的findBusinessUnits方法.一个”处理方法”顾名思义就是当执行到某个”切入点”时的一块代 码.类BusinessUnitPersistentAspect 包括advice方法findAllBusinessUnits,该方法从存储介质中载入数据,然后使用工厂类创建BusinessUnit 对象.然后这个对象被加入map,map对象的引用通过 BusinessUnitService 对象获得.”切入点”和”处理方法”组成了所谓的”aspect”.

为了读取存储介质中的数据,OOP方法通过一个DAO类来做.而AOP中,你只要定义一个”切入点”和相应的”处理方法”来读取数据.AOP框架会以advice的形式注入代码,既可以在执行期也可以在编译期.

总而言之,当类BusinessUnitService 中的findAllBusinessUnits 方法被调用时,AOP框架会在”切入点”处注入处理方法,通过BusinessUnit 对象预先读取数据来填充map对象.这样,持久层方面的代码就可以移到业务代码之外了.

新方法里的”Aspect”

本节讨论如何用AOP为应用程序的各个”切面”建模

操作资源

类BusinessUnitPersistenceAspect 的持久方法使用了一个buffered reader.你甚至可以定义”切面”的”切面”,但为了简单,这里只关注类的查找方法.

1.
2. @Aspect(“perJVM”)
3. public class BufferedFileReaderAspect {
4.
5. @Expression(“execution(* org.javatechnocrats.aop.withaop.aspects.BusinessUnitPersistenceAspect.find*(..))”)
6. Pointcut businessUnitPersistenceAspect;
7.
8. // 其他”切入点”定义
9.
10. @Expression(“businessUnitPersistenceAspect ||
11. employeePersistenceAspect ||
12. managerPersistenceAspect”)
13. Pointcut allPersistencePointcuts;
14.
15. private Map<Class, String> fileNames;
16.
17. public BufferedFileReaderAspect() {
18. System.out.println(“BufferedFileReaderAspect created”);
19. fileNames = new HashMap<Class, String>();
20. fillFileNames();
21. }
22.
23. @Before(“allPersistencePointcuts”)
24. public void assignReader(JoinPoint joinPoint) throws Throwable {
25. System.out.println(“assignReader advice called”);
26. Object callee = joinPoint.getCallee();
27. IBufferedFileReaderConsumable bufReaderConsumable = (IBufferedFileReaderConsumable)callee;
28. Class persistenceClass = callee.getClass();
29. String fileName = fileNames.get(persistenceClass);
30. FileReader fileReader = new FileReader(fileName);
31. BufferedReader bufferedReader = new BufferedReader(fileReader);
32. bufReaderConsumable.setBufferedReader(bufferedReader);
33. }
34.
35. @AfterFinally(“allPersistencePointcuts”)
36. public void releaseReader(JoinPoint joinPoint) throws Throwable {
37. //释放buffered reader等资源
38. }
39. //其他方法
40. }

上面的代码试图为每一个方法创建”切入点”– 所有以find开头的方法.无论何时这些方法被调用,assignReader方法都会被提前执行.这里它获取被调用的类实例然后设置新建的BufferedReader.

同样地,在releaseReader 方法里,代码会预先关闭buffered reader集合.本节只解释@before和@
AfterFinally 这两个”切入点”.(以J2SE 5.0的标记定义).另外,你也可以在方面定义的xml文件中声明他们.你可以查看例程源代码中的aop.xml文件.

下载

持久化

前面提到,OOP方法使用BusinessUnit 来为应用的持久层填充Map.在下面的高亮代码中(@before一行,以及while循环代码 – 译者注),当BusinessUnitService 中的方法findAllBusinessUnits 被调用时”处理方法 “findAllBusinessUnits 也将被调用.

1.
2. @Aspect(“perJVM”)
3. public class BusinessUnitPersistenceAspect implements IBufferedFileReaderConsumable {
4.
5. private BufferedReader buffFileReader;
6.
7. @Before(“execution(Collection org.javatechnocrats.aop.withaop.BusinessUnitService.findAllBusinessUnits())”)
8. public void findAllBusinessUnits(JoinPoint joinPoint) throws Throwable {
9. System.out.println(“findAllBusinessUnits advice called”);
10. Map<String, BusinessUnit> businessUnits =
11. ((BusinessUnitService)joinPoint.getThis()).getBusinessUnits();
12. String businessUnitRecord;
13. while((businessUnitRecord = buffFileReader.readLine()) != null) {
14. BusinessUnit businessUnit = BusinessUnitFactory.createBusinessUnit(businessUnitRecord);
15. businessUnits.put(businessUnit.getId(), businessUnit);
16. }
17. }
18.
19. public void setBufferedReader(BufferedReader buffFileReader) {
20. System.out.println(“BusinessUnitPersistenceAspect.setBufferedReader called”);
21. this.buffFileReader = buffFileReader;
22. }
23.
24. public BufferedReader getBufferedReader() {
25. System.out.println(“BusinessUnitPersistenceAspect.getBufferedReader called”);
26. return this.buffFileReader;
27. }
28. }

“处理方法”从数据存储中读取记录,使用工厂类创建一个BusinessUnit实例.然后这个实例被加入到Map.该Map掌管程序的所有持久化”aspect”.

日志
本文中的例子没有包含一个完整的日志AOP解决方案.但是,它为java.lang.Object类的toString方法定义了一个”切入点”来获取类 的调试信息.因此,域中的类不需要实现toString方法.通常情况下你可能需要为每一个类都要实现toString方法.

1.
2. @Aspect(“perJVM”)
3. public class LoggingAspect {
4.
5. @Around(“execution(String org.javatechnocrats.aop.withaop..*.toString())”)
6. public Object toStringAdvice(JoinPoint joinPoint) throws Throwable {
7. System.out.println(“toStringAdvice called”);
8. String toString = (String)joinPoint.proceed();
9. Object target = joinPoint.getThis();
10. Field fields[] = target.getClass().getDeclaredFields();
11. List members = new ArrayList(fields.length + 1);
12. members.add(toString);
13. for(Field field : fields) {
14. field.setAccessible(true);
15. Object member = field.get(target);
16. members.add(field.getName() + “=” + member);
17. }
18. return members.toString();
19. }

你也可以用这个样例代码完成错误处理”切面”.

深入源代码

为了理解样例需求的OOP设计,请参看源代码并思考以下几个问题:
下载

* 首先分析oldway包中EmployeeServiceTestCase 类中的代码
* 查看testEmployeeCredit 方法
* 搞懂业务类Employee和BusinessUnit
* 学习 service,repository和factory这些概念.这些是业务驱动设计的主要概念.
* 更深入地理解oldway包中的service,repository和factory类

而AOP地理解则应该是:
* 分析newway包中EmployeeServiceTestCase 类
* 查看service,repository和factory类,基本和前一种差不多.只是你要让”处理方法”截获程序的执行流程.
* 研究aspect类学习”切入点”的定义

要执行程序,你需要做的工作:
* 下载AspectWerkz 2.0 http://aspectwerkz.codehaus.org/
* 设置以下的环境变量:
set JAVA_HOME=c:Program FilesJavajdk1.5.0
set ASPECTWERKZ_HOME=C:aw_2_0_2
set PATH=%PATH%;%ASPECTWERKZ_HOME%bin
set CLASSPATH=
C:aw_2_0_2libaspectwerkz-2.0.RC2.jar;C:aw_2_0_2libaspectwerkz-jdk5-2.0.RC2.jar; classes;C: junit3.8.1resourceslibjunit.jar
* 解压缩源代码和其他文件
* 编译Java文件,但不要编译测试用例否则你调试时会遇到一个错误.
* 进行离线调试.假设你把文件解压缩到c:aop ,类文件解压到c:aopclasses,在c:aop目录下执行以下命令:
% ASPECTWERKZ_HOME%binaspectwerkz -offline etc/aop.xml -cp classes classes
* AOP框架会修改类来注入必要的字节码
* 编译测试用例,使用JUnit运行它.

后记
当你完成了上面的这些工作,你应该有以下的领悟:
* 程序中的交叉关联
* 关于AOP中”切面”的含义
* 如何用AOP来把程序业务层中的交叉关联分离出来,使用”切入点”和”处理方法”
* OOP和AOP时在程序控制流上的不同

从本文你应该也得到一种看待实际开发的新视角.你应该有信心使用AOP来改进项目中的设计,建模,提高代码的重用性.至少,你可以开始使用AOP来处理日志,错误和持久化.

个人觉得,AOP的学习曲线相对较陡,尤其在理解定义”切入点”的句法时.理想的情况是,使用OOP来设计业务模型,使用AOP把业务模型中的交叉关联移出,从而使代码简洁并提高可读性.

AOP的一个缺点是会使调试变得困难,因为不同于OOP,程序流变的复杂了,交互是由编译期或执行期决定.我准备将来做一些自动化工具来解决这个问题.

啥是Spring

(最初发布在JavaResearch.org,现在整理好放到自己的地方.)

有人说spring aop+ spring ioc, 才~~~是spring
简单一点,是一个容器. 什么容器,容纳什么?是对象,或者说bean的容器.
那为什么叫轻量级容器呢?相对于EJB container,使用spring不需要写符合容器规范的代码,即容器不会”侵入”了你的代码.

这 个容器会提供你的应用(程序)中用到的所有对象,并对这些对象进行统一的生命周期管理和组装.在通常的开发中,我们在需要某个对象的时候只是 new MyObject(). 在Java中,这样没有什么不好,因为gc会打理好”善后”工作,是系统级的. 而用spring,在需要某个对象 时,只要向容器请求相应的对象,spring会找到并准备好这些对象并提供给你.她也会打理好”善后”工作,但是是在应用级的.
另一方面,spring还会帮助你打理对象之间的依赖关系.
比如原来的做法:

class A{
}
class B{
A a ;
public B(){ a = new A();}
}

而使用spring的做法
class A{
}
class B{
A a;
public B(){}
void setA(A a){this.a=a}
A getA(){return this.a}
}
(希望你不要单纯地认为spring会写很多代码)
但 从前一个方面,你可能觉得spring只是一个对象容器.从这里你就应该看出,spring是bean容器,因为spring需要你的类符合bean规 范:相应于每一个成员域,都需要提供setter和getter方法.spring要使用这些方法来注入依赖关系,也就是 dependence injection, 或者inversion of control. 我个人觉得还是di更容易理解,直到现在我还是要考虑 怎么去向别人很好的解释ioc.控制反转(倒转),我的理解是就如同上面的两个例子里看到的,依赖(控制)不在体现在代码逻辑里(如第一个例子),而是在 配置文件里,而在代码中我们只提供注入点(也就是setter和getter).

希望我对IoC的概念的讲解能够给你一些启发.
你 可能要问了,为什么我要这样做呢?原来的做法有什么不妥的地方么?没有什么不妥,只是两种理念而已,没有绝对的好还是不好,但我还是给你我的解释–我理 解的IoC的好处,希望有所帮助.通常在程序设计的时候,我们在需要某些功能时,会相应的去设计一些方法,然后根据OO去将方法和一成员变量组成一个类. 实际上,我们最终设计出的程序是:一组类的实例互相交互完成某个特定的任务.
除了一些核心的业务方法,以外我们还要做组装对象的工作.比如我有了 一个工厂,里面有很多机器,机器在开动时要装配相应的模具.那么在工厂的生产过程中, 首先我要有工厂,机器,模具这样三个类.然后我的”动作”有:装 配,开机.通常的做法我们要做装配,然后再去开机.而用spring,我们只是专注于开机.这样我们就把装配这个动作抽离出了核心的”生产过程”.当某些 机器改变了装配模具时,不在需要修改核心业务代码.这就是解耦.如:

public class Production{
public static void main(String[] args){
Factory factory = (Factory)BeanFactory.getBean(“factory”);
factory.launchProduction();
}
}

class Factory{
Machine machine1,machine2;
void launchProduction(){
machine1.start(); machine2.start();
}
// setters and getters
}

class Machine{
Tool tool;
void start(){
}
// setters and getters
}

在launchProduction()方法中只需要开动每台机器即可.而不需要每次都装配机器.装配的工作交给了别人.现在只要按下start按钮.生产就开始了!要是原来:

void launchProduction(){
machine1 = new MachineA();
machine1.setTool(new ToolA());
machine2 = new MachineB();
machine2.setTool(new ToolB());
machine1.start();
machine2.start();
}

这就是工作分工,是不是感觉轻松了许多?从此以后,我们都是面向构件去开发,而不需要过多地在代码中体现构件之间的依赖关系.

AOP
推荐你看一下<<effective enterprise java>>的第一章,对AOP有很清晰,易懂的解释.其实AOP并非很艰深晦涩的概念,但是从架构角度去理解她的重要性可能不是我这样的new fish一时半会儿可以领悟到的.
我这里只是想说,有些概念你要知道是怎么回事,但理解到多深,除了天赋以外更多的是经验和悟.所以不要心急.–像是在自我解嘲.
也许在不知不觉中你就使用了很多AOP的概念,比如servlet里的filter,比如在写一个command类时,给她的调用类在每次调用command时前后加上:preProcess和postProcess…
我不想解释太多,<<eej>>的解释已经足够.

Hope helps.

alloy破解[转贴]

alloy的许可证分成四个部分,每个部分之间用#号分隔,第一部分是许可证过期时间,第二部分是用户名,第三和第四部分是两个36进制的整数,其中第三部分是校验码,第四部分是一个随机数(我是这么认为的,第四部分写死成一个常量也没有什么关系)。
好了,了解了许可证的构造之后,我们来了解一下alloy检验许可证是否合法和过期的过程。
一:分离许可证的各个部分。
二:判断日期部分的长度,如果长度大于1,就构造一个过期时间,否则过期时间为null。(这下子我们就可以通过使日期部分的长度不超过1来让alloy永不过期了^-^)。
三:调用Long.parseLong(String, int)方法解析出第三和第四部分两个36进制整数的10进制的值。
四:使用java.util.zip.CRC32来计算校验值,计算的过程是把从第四部分得到的10进值整数对127取模,然后加上第一、二两个部分(包括中间的#号),这样就构造出一个字符串,然后调用CRC32.update()方法计算这个字符串的校验值。
五:使用getValue()方法从CRC32中取得校验值,然后将这个校验值与从第三部分获得的10进制数值比较,如果相等,则校验成功。随后就是判断当前日期是否过期的操作了。
这大致就是alloy验证许可证的过程,我们反过来做一遍,就可以得到我们自己的许可证了。下面就是我写的构造许可证的方法,供大家参考。

public String generate(String user)
{
String exp = “x”;
String rand = “torresg”;
long l = Long.parseLong(rand, 36);
CRC32 crc32 = new CRC32();
crc32.update((l % 127L + exp + “#” + user).getBytes());
String checksum = Long.toString(crc32.getValue(), 36);
return exp + “#” + user + “#” + checksum + “#” + rand;
}

另外就是过期时间不能为空,因为alloy中另外某个地方要对这个时间进行处理。为空的话也会验证失败。所以过期时间要使用一个长度为1的字符串。

com.incors.plaf.alloy.AlloyLookAndFeel.setProperty(“alloy.licenseCode”,
“v#ej_technologies#uwbjzx#e6pck8”);
try {
javax.swing.LookAndFeel alloyLnF = new com.incors.plaf.alloy.AlloyLookAndFeel (); javax.swing.UIManager.setLookAndFeel(alloyLnF);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
// You may handle the exception here
ex.printStackTrace();
}