# 逻辑流拦截器(handler-engine.xml)
与逻辑流拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler-engine.xml | eosserver\working\应用名\config\handler- engine.xml | 可以在配置文件中配置逻辑流的拦截器,实现业务开发的功能 |
IHandler | com.eos.engine.core.IHandler | 逻辑流拦截器接口类、用户需要实现该接口 |
IRuntimeContext | com.primeton.ext.engine.core.IRuntimeContext | 参数类、用于获取逻辑流上下文的参数信息 |
HandlerTerminateException | com.eos.engine.core.exception.HandlerTerminateException | 如果希望在handler中终止流程的执行,可以抛出HandlerTerminateException,引擎碰到该异常的时候,会终止流程的继续执行 |
说明
逻辑流和页面流共用一个配置文件handler-engine.xml;通过type属性的值来区分对页面流的拦截还是对逻辑流的拦截。
- pageflow:表示对页面流进行拦截;
- businesslogic:表示对逻辑流进行拦截。
# 功能描述
EOS6为逻辑流提供了Handler拦截机制,可以在执行逻辑流的某个图元之前、之后、发生异常、无论正确执行还是发生异常的情况下都会执行的finally四种情况下进行拦截;也可以对整个逻辑流执行之前、执行之后、发生异常、无论正确执行还是发生异常的情况下都会执行的finally四种情况下进行拦截;可以在Handler实现中插入用户期望执行的具体代码。
# 配置文件与关键类
配置文件:handler-engine.xml 关键类:IHandler、IRuntimeContext
# 配置文件格式说明
文件路径:eosserver\working\应用名\config\handler-access.xml handler-access.xml文件格式如下:
<handles>
<handle
name="aName"
match-pattern="*[CHAR]**"
handle-class="com.primeton.engine.handler.logHandler"
type="pageflow,businesslogic"
nodeType="start"
nodeID=""/>
</handles>
说明
所有的Handler在系统运行期间都是单实例的,在实现IHandler接口时,实现类不能定义全局变量,否则,在多线程的情况下会有并发的问题。 Handler支持两种级别的拦截:对单个图元进行拦截/对整个逻辑流进行拦截。
格式说明:
handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。
handler节点:
name属性:配置拦截器的名字,在配置文件中多个handler节点的name属性值不能重复。
match-pattern属性:拦截对象的匹配规则,表示对哪些逻辑流的名称进行匹配。此处的逻辑流名称是全名称,包括逻辑流的包名。支持通配符*,并且最多只能有一个*。如果match-pattern="",表示对所有的逻辑流进行拦截。通配符使用举例: [字符串] [字符串] [字符串] [字符串]*[字符串]
handle-class属性:拦截器的实现类,需要指定类的全名。该类必须实现com.eos.engine.core.IHandler接口。
type属性:拦截对象的类型,支持的拦截类型如下表所示。
type值 | 说明 |
---|---|
pageflow | 对页面流进行拦截 |
businesslogic | 对逻辑流进行拦截 |
* | 对页面流、逻辑流都进行拦截 |
- nodeType属性:拦截器拦截图元的类型。逻辑流当中每种不同的图元都有不同的类型对象,可以为拦截器按照图元的类型设置拦截方式。如果有多个,可以用英文逗号","分开。 逻辑流中支持的图元类型如下表所示:
图元类型 | 说明 |
---|---|
Start | 对逻辑流开始图元进行拦截 |
End | 对逻辑流结束图元进行拦截 |
assign | 对逻辑流赋值图元进行拦截 |
Invoke | 对逻辑流调用运算逻辑、服务图元进行拦截 |
subprocess | 对逻辑流调用子逻辑流图元进行拦截 |
loopstart | 对逻辑流循环开始图元进行拦截 |
loopend | 对逻辑流循环结束图元进行拦截 |
transactionBegin | 对逻辑流事务开始图元进行拦截 |
transactionCommit | 对逻辑流事务提交图元进行拦截 |
transactionRollback | 对逻辑流事务回滚图元进行拦截 |
Switch | 对逻辑流空操作图元进行拦截 |
Throw | 对逻辑流异常抛出图元进行拦截 |
webservice | 对Web Service调用图元进行拦截 |
* | 表示对所有的图元进行拦截 |
nodeID属性:拦截器可以按照图元的ID进行精确的拦截,当希望拦截多个图元ID的时候,可以用英文逗号","分开。"*"表示对所有的图元都进行拦截。
注意
- nodeType和nodeID是或的关系,既当nodeType和nodeID满足任何其中的一个时候,都会进行拦截;其他的元素之间是与的关系;
- 当nodeType和nodeID同时为""的时候,表示对逻辑流进行拦截,而不是拦截某一个具体的图元。
# 关键类
- IHandler类: 用户需要实现该接口,实现类可以在调用逻辑流特定图元的时候,执行特定的用户业务操作,达到对页面流拦截的目的。 类定义如下:
public interface IHandler {
public static final int RET_OK = 1;
public static final int RET_BREAK = 7;
public static final int RET_TERMINATE = 9;
int doBefore(IRuntimeContext context);
int doAfter(IRuntimeContext context);
int doException(IRuntimeContext context,Throwable t);
int doFinalize(IRuntimeContext context);
}
IHandler类操作说明:
方法签名 | 功能说明 |
---|---|
int doBefore(IRuntimeContext context) | 在执行目标之前触发动作,如果发生错误应该抛出HandlerTerminateException类型异常 |
int doAfter(IRuntimeContext context) | 在执行目标之后触发动作,如果发生错误应该抛出HandlerTerminateException类型异常 |
int doException(IRuntimeContext context,Throwable t) | 在执行目标发生异常时触发动作,如果发生错误应该抛出HandlerTerminateException类型异常 |
int doFinalize(IRuntimeContext context) | 在执行目标最后(无论是完成还是发生异常)触发动作,如果发生错误应该抛出HandlerTerminateException类型异常 |
IHandler定义了如下表所示的常量:
常量 | 功能说明 |
---|---|
RET_OK | 表示拦截器执行成功,继续执行逻辑流 |
RET_BREAK | 系统保留,目前没有使用 |
RET_TERMINATE | 在执行目标发生异常时触发动作,如果发生错误应该抛出HandlerTerminateException类型异常 |
- IRuntimeContext类: 在handler执行的可以获取逻辑流执行的上下文,通过IRuntimeContext参数可以获取逻辑流上下文。 IRuntimeContext类操作说明:
方法签名 | 功能说明 |
---|---|
String getCurrentActivityName() | 获取当前图元的名字 |
String getCurrentActivityType() | 获取当前图元的类型 |
String getCurrentActivityID() | 获取当前图元的ID |
String getCurrentActivityValue() | 获取当前图元执行的Value值 |
public String getProcessName() | 获取当前逻辑流的名称 |
- HandlerTerminateException类: 该类没有任何方法,当用户希望Hanlder终止业务流程的时候,可以抛出该类型的异常。
# 应用示例
# 场景说明
逻辑流运行过程中,可能会出现异常。用户希望在逻辑流运行出现异常的时候,能够在日志中记录日志,便于问题的跟踪与管理。用户记录的异常希望记录到那个图元发生了异常、发生了什么异常,而且不希望记录日志的时候影响流程的执行(即不能因为记录日志而影响正常逻辑流流程的执行)。
为了达到上面记录逻辑流出错的日志记录问题,可以采用EOS6中提供的拦截器的功能。对逻辑流的每个图元进行拦截,当发生异常的时候,调用日志服务组件记录日志;对于记录日志时发生的任何异常都需要用户catch,避免影响业务的流程。
# 操作步骤
- 实现IHandler接口,完成ExceptionLogHandler.java的开发。 实现类的代码如下:
public class ExceptionLogHandler implements IHandler {
private static final Logger logger = TraceLoggerFactory
.getLogger(ExceptionLogHandler.class);
public int doAfter(IRuntimeContext arg0) {
return IHandler.RET_OK;
}
public int doBefore(IRuntimeContext arg0) {
return IHandler.RET_OK;
}
//逻辑流发生异常时候执行日志记录功能
public int doException(IRuntimeContext arg0, Throwable arg1) {
try{
String processorName = arg0.getProcessName();//逻辑流名称
String currentID = arg0.getCurrentActivityID();//当前图元ID
String currentName = arg0.getCurrentActivityName();//当前图元名字
String currentType = arg0.getCurrentActivityType();//当前图元类型
logger.error(processorName + " " + currentID + " " + currentName + " "
+ currentType + " make an error "
+ arg1.getMessage().toString());
}catch(Throwable t){
}
return IHandler.RET_OK;
}
public int doFinalize(IRuntimeContext arg0) {
return IHandler.RET_OK;
}
}
- 在配置文件handler-engine.xml中配置逻辑流拦截器。 下面是配置文件的信息:
<handles>
<handle
name="exceptionLogHandler"
match-pattern="*"
handle-class="com.primeton.engine.handler. ExceptionLogHandler "
type=" businesslogic"
nodeType="*"
nodeID="*"/>
</handles>
参数配置说明: 例子中handler-engine.xml内容的说明:
属性 | 值 | 说明 |
---|---|---|
name | exceptionLogHandler | 当前逻辑流拦截器的名字为exceptionLogHandler |
match-pattern | * | 表示对所有的逻辑流进行拦截 |
handle-class | com.primeton.engine.handler. ExceptionLogHandler | 当前逻辑流拦截器的全称:包名+类名 |
type | businesslogic | businesslogic表示对逻辑流进行拦截 |
nodeType | * | *表示对所有类型的节点进行拦截 |
nodeID | * | *表示对所有的id进行拦截 |
# 命名SQL拦截器(handler-namedsql.xml
与命名SQL拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler- namedsql.xml | eosserver\working\应用名\config\handler- namedsql.xml | 可以在配置文件中配置命名SQL的拦截器,实现业务开发的功能 |
INamedSqlHandler | com.primeton.das.sql.impl.handler.INamedSqlHandler | 命名SQL拦截器接口类、用户需要实现该接口 |
InterceptorContext | com.primeton.das.sql.impl.ibatis.sqlmap.client.InterceptorContext | 命名SQL拦截器上下文,通过该上下文可以获取有关命名SQL的相关信息 |
# 功能描述
EOS6为命名SQL提供了Handler拦截机制,可以在命名SQL执行过程中设置拦截器。有如下的拦截时机:
- 在查询(Query)之前;
- 在更新(Update)之前;
- 在插入(Insert)之前;
- 在删除(Delete)之前。
上面的时机,是指通过EOS6提供的数据服务(DAS)功能进行命名SQL操作中发生的。开发人员可以在上述的任何一个时机,实现对命名SQL操作的拦截功能。例如:开发人员可以在对数据库表数据的任何修改的时机都记录操作人员,达到跟踪什么时间、谁修改了数据库中的数据。
# 配置文件与关键类
配置文件:handler-namedsql.xml 关键类:INamedSqlHandler、InterceptorContext
# 配置文件格式说明
文件路径:eosserver\working\应用名\config\handler- namedsql.xml handler- namedsql.xml文件格式如下:
<handlers>
<!--命名SQL拦截器-->
<!--
class:拦截器实现类,必须实现com.primeton.das.sql.impl.handler.INamedSqlHandler
matchName:匹配的命名SQL编号.isRegex:是否允许matchName使用通配符
-->
<!--
<handler id="NameSQLHandler"
class="com.primeton.server.das.namedsql.handler.Handler1">
<match matchName="test.selectSchoolByKey"></match>
<match matchName="test.insertSchool"></match>
<match matchName="test.updateSchool"></match>
<match matchName="test.deleteSchool*" isRegex="true" ></match>
</handler>
--> </handlers>
格式说明:
handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。
handler节点:
id属性:配置命名SQL拦截器的名字,在配置文件中多个handler节点的id属性值不能重复。
class属性:命名SQL拦截器的实现类,需要指定类的全名。该类必须实现com.primeton.das.sql.impl.handler.INamedSqlHandler接口。
match节点:用于定义命名SQL和命名SQL拦截器的匹配规则,在一个handler节点中可以有多个match条目。
matchName属性:需要拦截的命名SQL名字,必须是全名,支持通配符*,需要注意通配符仅仅支持一个。 通配符使用举例: [字符串]:表示所有以[字符串]结尾的实体都能被拦截; [字符串]:表示所有以[字符串]开头的实体都能被拦截; [字符串]:表示只有和[字符串]相匹配的实体都能被拦截; [字符串1]*[字符串2]:表示所有以[字符串1]开头并且以[字符串2]结尾的实体都能被拦截。
isRegex属性:是否支持通配符*,取值范围为true、false,如下表所示。
isRegex值 | 说明 |
---|---|
true | 表示matchName属性支持通配符*,matchName属性可以按照下面的格式定义那些命名SQL需要被拦截: [字符串] [字符串] [字符串] [字符串]*[字符串] |
false | 表示matchName属性不支持通配符*,如果matchName中有*,表示当前的命名SQL就包含这个字符串。 举例:com.primeton.order.sql.Oder 表示当前的命名SQL本身包含*字符。 |
# 关键类
INamedSqlHandler类:
用户需要实现该接口,实现类可以在对持久化实体操作的时候,执行特定的用户业务操作,达到对在执行持久化得时候进行拦截的目的。
类定义如下:
public interface INamedSqlHandler {
public void beforeQuery(InterceptorContext context);
public void beforeUpdate(InterceptorContext context);
public void beforeInsert(InterceptorContext context);
public void beforeDelete(InterceptorContext context);
}
INamedSqlHandler类操作说明:
方法签名 | 功能说明 |
---|---|
beforeQuery(InterceptorContext context) | 在查询之前调用该拦截方法 |
beforeUpdate(InterceptorContext context) | 在更新之前调用该拦截方法 |
beforeInsert(InterceptorContext context) | 在新增之前调用该拦截方法 |
beforeDelete(InterceptorContext context) | 在删除之前调用该拦截方法 |
InterceptorContext类:
该类用于获取当前命名SQL的上下文信息,通过InterceptorContext可以获取如下的信息:
Unknown macro: {span}
- 命名SQL的ID
- 执行的SQL语句
- 参数信息
- 执行Statement的类型(Insert,Update,Delete,Select,Procedure)
InterceptorContext类操作说明:
方法签名 | 功能说明 |
---|---|
String getMappedId() | 获取命名SQL的ID |
List<Param> getParameters() | 获取参数信息 |
String getSql() | 获取执行的SQL语句 |
StatementType getStatementType() | 获取执行Statement的类型 有如下常量选择: |
# 应用示例
# 场景说明
用户开发的业务系统中存在一个工单表,该表中存在一个lastUpdateTime字段,在进行业务开发的时候希望每次修改工单表数据后,都要把修改时间记录到字段lastUpdateTime中。用户可以在自己的业务中自己去实现,也可以通过命名SQL拦截器的方式去实现。如果采用命名SQL拦截的方式实现,可以避免在业务逻辑中实现,大大节省了业务逻辑开发的时间。
通过命名SQL拦截器实现原理,对工单表对应的命名SQL配置一个拦截器,在拦截器的beforeUpdate()中,修改lastUpdateTime字段的值为当前的系统时间;字段lastUpdateTime 的值会自动持久化到数据库中。
# 操作步骤
实现INamedSqlHandler接口,完成LastUpdateTimeNamedSqlHandler.java的开发。
在beforeUpdate操作中需要实现功能:将lastUpdateTime字段的值设置为当前的系统时间,这样可以在修改数据之前能够自动将lastUpdateTime字段值自动保存到数据库中。
实现类的代码如下:
public class LastUpdateTimeNamedSqlHandler implements INamedSqlHandler {
public void beforeQuery(InterceptorContext context) {}
public void beforeDelete(InterceptorContext context) {}
public void beforeInsert(InterceptorContext context) {}
public void beforeUpdate(InterceptorContext context) {
//现在SQL语句的最后一个参数是修改时间,通过在拦截器中设置lastUpdateTime字段
//为当前的系统时间,达到记录每次修改工单表的时间
List<Param> list = context.getParameters();
Param lastUpdateTimeParam = list.get(list.size());
lastUpdateTimeParam.setValue(System.currentTimeMillis());
}
}
在配置文件handler- namedsql.xml中配置实体拦截器。
下面是配置文件的信息:
<handles>
<handler id="LastUpdateTimeNamedSqlHhandler"
class="com.primeton.server.das.handler. LastUpdateTimeNamedSqlHandler ">
<match matchName="com.primeton.order.sql.updateSqlOrder" isRegex="true"/>
</handler>
</handles>
该配置文件表示,对于命名SQL:com.primeton.order.sql. updateSqlOrder使用命名SQL拦截器LastUpdateTimeNamedSqlHhandler进行拦截,在对命名SQL updateSqlOrder执行更新操作的时候,会自动将lastUpdateTime字段保存到数据库中,而不需要在业务中来实现该功能。
参数配置说明:
例子中handler- namedsql.xml内容的说明:
属性 | 值 | 说明 |
---|---|---|
id | LastUpdateTimeNamedSqlHhandler | 当前实体拦截器的名字为LastUpdateTimeNamedSqlHhandler |
class | com.primeton.server.das.handler.LastUpdateTimeNamedSqlHandler | 命名SQL拦截器的全名:包名+类名 |
matchName | com.primeton.order.sql.updateSqlOrder | 表示对命名SQL com.primeton.order.sql.updateSqlOrder进行拦截 |
isRegex | true | 表示matchName支持通配符* |
# 实体拦截器(handler-entity.xml)
与实体拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler- entity.xml | eosserver\working\应用名\config\handler- entity.xml | 可以在配置文件中配置数据实体的拦截器,实现业务开发的功能 |
IEntityHandler | com.primeton.das.entity.impl.handler.IEntityHandler | 实体拦截器接口类、用户需要实现该接口 |
# 功能描述
EOS6为实体持久化提供了Handler拦截机制,可以在实体持久化执行过程中设置拦截器。有如下的拦截时机:
- 在装载数据(Load)之前;
- 在装载数据(Load)之后;
- 在保存数据(Save)之前;
- 在修改数据(Update)之前;
- 在删除数据(Delete)之后。
上面的时机,是指通过EOS6提供的数据服务(DAS)功能进行数据库的持久化操作中发生的。开发人员可以在上述的任何一个时机,实现对持久化操作的拦截功能。例如:开发人员可以在对数据库表数据的任何修改的时机都记录操作人员,达到跟踪什么时间、谁修改了数据库中的数据。
注意
在通过基础构件库进行数据的批量操作(如insertEntityBatch、updateEntityBatch和deleteEntityBatch)时,配置的实体拦截器将不起作用。
# 配置文件与关键类
配置文件:handler-entity.xml 关键类:IIEntityHandler
# 配置文件格式说明
文件路径:eosserver\working\应用名\config\handler- entity.xml handler- entity.xml文件格式如下:
<handlers>
<!--
实体拦截器,拦截器的执行顺序与配置定义顺序一致
class:拦截器具体实现类名,必须实现
com.primeton.das.entity.impl.handler.IEntityHandler
match可以有多个,matchName,匹配的实体全名
-->
<!--
<handler id="handler1"
class="com.primeton.server.das.persistententity.handler.MyHandler">
<match matchName="*" isRegex="true"/>
</handler>
-->
</handlers>
格式说明:
handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。
handler节点:
id属性:配置实体拦截器的名字,在配置文件中多个handler节点的id属性值不能重复。
class属性:拦截器的实现类,需要指定类的全名。该类必须实现com.primeton.das.entity.impl.handler.IEntityHandler接口。
match节点:用于定义实体和拦截器的匹配规则,在一个handler节点中可以有多个match条目。
matchName属性:需要拦截的实体名字,必须是全名,支持通配符*,需要注意通配符仅仅支持一个。 通配符使用举例: [字符串]:表示所有以[字符串]结尾的实体都能被拦截; [字符串]:表示所有以[字符串]开头的实体都能被拦截; [字符串]:表示只有和[字符串]相匹配的实体都能被拦截; [字符串1]*[字符串2]:表示所有以[字符串1]开头并且以[字符串2]结尾的实体都能被拦截。
isRegex属性:是否支持通配符*,取值范围为true、false;如下表所示。
isRegex值 | 说明 |
---|---|
true | 表示matchName属性支持通配符*,matchName属性可以按照下面的格式定义那些数据实体需要被拦截: [字符串] [字符串] [字符串] [字符串]*[字符串] |
false | 表示matchName属性不支持通配符*,如果matchName中有*,表示当前的数据实体就包含这个字符串。 举例:com.primeton.order.data.Oder 表示当前的数据实体本身包含*字符。 |
# 关键类
IEntityHandler类: 用户需要实现该接口,实现类可以在对持久化实体操作的时候,执行特定的用户业务操作,达到对在执行持久化得时候进行拦截的目的。 类定义如下:
public interface IEntityHandler {
public abstract void afterLoad(DataObject entity, Serializable primaryKey,
String[] propertyNames, Object[] values);
public abstract void beforeLoad(String entityName,IDASCriteria criteria);
public abstract void beforeSave(DataObject entity, Serializable primaryKey,
String[] propertyNames, Object[] values);
public abstract void beforeUpdate(DataObject entity,
Serializable primaryKey, String[] propertyNames,
Object[] previousValues, Object[] currentValues);
public abstract void afterDelete(DataObject entity,
Serializable primaryKey, String[] propertyNames, Object[] values);
}
IEntityHandler类操作说明:
方法签名 | 功能说明 |
---|---|
abstract void afterLoad() | 在取出数据成为一个entity后,handler可以修改values。修改后的值仅仅是显示给用户,并不影响数据库的值。 |
abstract void beforeLoad () | 当查询一个entity之前,可以修改criteria,改变查询的结果。 |
abstract void beforeSave() | 在DAS把一个entity保存到数据库之前,handler可以修改values。修改过的属性将会持久化到数据库中。 |
abstract void beforeUpdate() | 在修改一个表的数据前,handler可以修改currentValues。修改过的值将会更新到数据库中。 |
abstract void afterDelete() | 在删掉某个记录后,可能要做配套的操作,操作实现可以写在方法中。 |
# 应用示例
# 场景说明
用户开发的业务系统中存在一个工单表,该表中存在一个lastUpdateTime字段,在进行业务开发的时候希望每次修改工单表数据后,都要把修改时间记录到字段lastUpdateTime中。用户可以在自己的业务中自己去实现,也可以通过实体拦截器的方式去实现。如果采用实体拦截的方式实现,可以避免在业务逻辑中实现,大大节省了业务逻辑开发的时间。
通过实体拦截器实现原理,对工单表对应的数据实体配置一个拦截器,在拦截器的beforeUpdate()中,修改lastUpdateTime字段的值为当前的系统时间;字段lastUpdateTime 的值会自动持久化到数据库中。
# 操作步骤
- 实现IEntityHandler接口,完成LastUpdateTimeEntityHandler.java的开发。 在beforeUpdate操作中需要实现功能:将lastUpdateTime字段的值设置为当前的系统时间,这样可以在修改数据之前能够自动将lastUpdateTime字段值自动保存到数据库中。 实现类的代码如下:
public class LastUpdateTimeEntityHandler implements IEntityHandler {
public void afterLoad(DataObject entity, Serializable primaryKey,
String[] propertyNames, Object[] values) {}
public void beforeSave(DataObject entity, Serializable primaryKey,
String[] propertyNames, Object[] values) {}
public void beforeLoad(String entityName, IDASCriteria criteria) {}
public void afterDelete(DataObject entity, Serializable primaryKey,
String[] propertyNames, Object[] values) {}
//在修改数据之前,将修改时间设置到字段lastUpdateTime中,
//可以将该字段自动持久化到数据库中
public void beforeUpdate(DataObject entity, Serializable primaryKey,
String[] propertyNames, Object[] previousValues,
Object[] currentValues) {
for(int i=0;i<propertyNames.length;i++){
if("lastUpdateTime".equals(propertyNames[i])){
currentValues[i]=System.currentTimeMillis();
break;
}
}
}
}
- 在配置文件handler-entity.xml中配置实体拦截器。 下面是配置文件的信息:
<handles>
<handler id="LastUpdateTimeEntityHhandler"
class="com.primeton.server.das.handler. LastUpdateTimeEntityHandler ">
<match matchName="com.primeton.order.data.salaryData" isRegex="true"/>
</handler>
</handles>
该配置文件表示,对于数据实体com.primeton.order.data.salaryData使用实体拦截器LastUpdateTimeEntityHandler进行拦截,在对salaryData实体执行更新操作的时候,会自动将lastUpdateTime字段保存到数据库中,而不需要在业务中来实现该功能。 参数配置说明: 例子中handler-entity.xml内容的说明:
属性 | 值 | 说明 |
---|---|---|
id | LastUpdateTimeEntityHhandler | 当前实体拦截器的名字为LastUpdateTimeEntityHhandler |
class | com.primeton.server.das.handler.LastUpdateTimeEntityHandler | 实体拦截器的全名:包名+类名 |
matchName | com.primeton.order.data.salaryData | 表示对实体com.primeton.order.data.salaryData进行拦截 |
isRegex | true | 表示matchName支持通配符* |
# Web请求拦截器(handler-web.xml)
与Web请求拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler- web.xml | eosserver\working\应用名\config\handler- web.xml | web请求的拦截器配置,支持配置多个拦截器;如配置用于国际化的拦截器等。 |
IWebInterceptor | com.eos.access.http.IWebInterceptor | 请求的拦截器,类似于filter。 用户需要实现该接口。 |
# 功能描述
在处理Web请求拦截方面,J2EE的Web容器提供了Filter的功能,用于拦截特定的请求,然后处理请求,最后将请求交给后面的Filter或者Servlet处理;为了实现该功能需要在web.xml文件中进行配置filter、filter-mapping等。在EOS6中提供了类似的功能用于拦截请求,而无须在web.xml中配置;只需要在handler-web.xml中进行配置即可,简化了web.xml的复杂度。
# 配置文件与关键类
配置文件:handler- web.xml 关键类:IWebInterceptor
# 配置文件格式说明
文件路径:eosserver\working\应用名\config\handler- web.xml handler- web.xml文件格式如下:
<handlers>
<!--
请求过滤扩展注册
国际化拦截器
sortIdx[optional]:排序编号,数字小的先执行
pattern:请求URL匹配模式,几种方式
1) *.xxx,例如,*.do,*.jsp等等;
2) /* 拦截所有请求;
3) xxx 精确匹配,例如,/samples/test.jsp
4) xxx/* 混合匹配,xxx必须精确匹配,例如,/samples/test/*;
class:具体的实现类,必须实现接口com.eos.access.http.WebInterceptor
-->
<handler id="WSInterceptor" sortIdx="0" pattern="/*"
class=" com.eos.access.http.UserLoginCheckedFilter "/>
</handlers>
格式说明:
- handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照sortIdx的大小先后执行,数字小的先执行。
- handler节点:
- id属性:请求过滤拦截器的唯一id号,多个handler之间不能重复。
- sortIdx属性:排序编号,数字小的先执行。
- pattern属性:请求URL匹配模式,支持如下的几种方式: .xxx,例如,.do,.jsp等等; / 拦截所有请求; xxx 精确匹配,例如,/samples/test.jsp; xxx/* 混合匹配,xxx必须精确匹配,例如,/samples/test/*。
- class属性:具体的实现类,必须实现com.eos.access.http.WebInterceptor。
# 关键类
- IWebInterceptor类: Web请求拦截器必须实现接口IWebInterceptor,在实现方法中可以对请求进行处理;需要注意,在实现类的最后需要将请求的流程继续传递到后面的拦截器中,因为handler-web.xml中多个handler之间是一个链式结构。 类定义如下:
public interface IWebInterceptor {
/**
* 拦截请求
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param interceptorChain WebInterceptorChain
* @throws IOException
* @throws ServletException
*/
public void doIntercept(HttpServletRequest request,
HttpServletResponse response, IWebInterceptorChain interceptorChain)
throws IOException, ServletException;
}
IWebInterceptor类操作说明:
方法签名 | 功能说明 |
---|---|
方法签名 | 功能说明 |
doIntercept(HttpServletRequest request, HttpServletResponse response, IWebInterceptorChain interceptorChain) | 拦截请求的具体操作;注意实现该方法的时候,要确保当前的拦截器处理完成后,能够传递到拦截器链上的下一个拦截器;需要实现下面的一句代码: interceptorChain.doIntercept(request, response); |
# 应用示例
# 场景说明
在处理Web请求的开发中,经常碰到请求编码的问题,通常的做法是实现一个filter,然后在web.xml中配置该filter;该filter负责统一处理所有请求的编码;现在我们把这一功能用EOS6提供的Web请求过滤扩展点的功能来实现。
# 操作步骤
- 实现IWebInterceptor接口,完成RequestEncodingWebInterceptor.java的开发。 RequestEncodingWebInterceptor中完成请求编码的设置,将所有请求的编码设置为了"UTF-8"编码;最后将请求传递给链上的其他过滤器中。 实现类的代码如下:
public class RequestEncodingWebInterceptor implements IWebInterceptor {
//统一设置请求的编码格式为UTF-8
public void doIntercept(HttpServletRequest request,
HttpServletResponse response, IWebInterceptorChain interceptorChain)
throws IOException, ServletException {
try {
request.setCharacterEncoding("UTF-8");
} finally {
//最后将请求传递到其它过滤器中
interceptorChain.doIntercept(request, response);
}
}
}
- 在配置文件handler- web.xml中配置实体拦截器。 下面是配置文件的信息:
<handles>
<handler id="WSInterceptor" sortIdx="0" pattern="/*"
class="com.primeton.access. RequestEncodingWebInterceptor "/>
</handles>
因为是处理请求编码的一个拦截器,我们希望将该拦截器放在请求最入口的地方执行,因此我们配置sortIdx为"0",表示这个最优先执行。
# 构件包加载拦截器(handler-contribution.xml)
与构件包加载拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler- contribution.xml | ||
IContributionListener | com.eos.runtime.resource.IContributionListener | 用户监听接口必须实现接口IContributionListener,监听的事件类型有构件包加载事件、卸载事件和构件包加载完成事件 |
IContributionEvent | com.eos.runtime.resource.IContributionEvent | 事件发生时,提供的事件源对象为IContributionEvent,其中包含了构件包的元数据(对应的数据文件为$构件包目录/META-INF/MANIFEST.MF)和构件包的配置信息(对应的数据文件为$构件包目录/META-INF/contribution.eosinf) |
ContributionMetaData | com.eos.runtime.resource.ContributionMetaData | 构件包对应的元数据对象为ContributionMetaData,构件包元数据文件为Manifest.MF格式,遵从OSGI的Bundle规范;(对应的数据文件为$构件包目录/META-INF/MANIFEST.MF) |
# 功能描述
在构件包发生加载、卸载事件时回调用户的接口,监听构件包的变化,此监听事件是针对所对应的构件包,可以为不同构件包配置不同的监听接口。有如下的监听时机:
- 在构件包加载(load)时;
- 在构件包加载完成(loadFinished)时;
- 在构件包卸载(unLoad)时。
EOS6中默认为构件包提供了一个加载日志功能的扩展点(com.primeton.ext.common.logging.startup.ContributionLoggingStartupRuntimeListener),在每个构件包加载的时候,为构件包注册了构件包日志组件服务,用户可以在构件包中利用此处提供的日志服务记录日志。
# 配置文件与关键类
配置文件:handler- contribution.xml 关键类:IContributionListener、IContributionEvent、ContributionMetaData
# 配置文件格式说明
文件路径:
- eosserver\working\应用名\config\handler- contribution.xml
- 组件包目录/META-INF/handler-contribution.xml
说明
- 位置:eosserver\working\应用名\config\handler- contribution.xml中的扩展点会对所有的构件包起作用;
- 位置:组件包目录/META-INF/handler-contribution.xml中的扩展点仅仅对本构件包起作用。
handler- contribution.xml文件格式如下:
<handlers>
<!--
构件运行环境(Contribution级)启动监听器,监听器的加载执行顺序按照配置的先后顺序
该文件可以有多个,存放位置支持两种:
1、组件包目录/META-INF/handler-contribution.xml
2、eosserver\working\应用名\config\handler- contribution.xml
-->
<handler handle-class="com.primeton.ext.common.logging.startup.
ContributionLoggingStartupRuntimeListener"/>
</handlers>
格式说明:
handlers节点:
下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。
说明
关于执行顺序: 在同一个文件内部:按照handler的定义顺序执行; 存在应用级别配置文件和构件包级别的配置文件时候,首先执行应用级别的handler,然后执行构件包级别的handler。即:
- 先执行:eosserver\working\应用名\config\handler- contribution.xml中的handler;
- 后执行:组件包目录/META-INF/handler-contribution.xml中的handler
handler节点: handle-class属性:构件包加载、卸载扩展点的实现类,需要指定类的全名。该类必须实现com.eos.runtime.resource.IContributionListener接口。
# 关键类
IContributionListener类:
用户监听接口必须实现接口IContributionListener,监听的事件类型有构件包加载事件、卸载事件和构件包加载完成事件。
类定义如下:
public interface IContributionListener extends EventListener{
/**
* Contribution加载时执行方法.
*/
public void load (IContributionEvent event);
/**
* Contribution加载完成时执行的任务
*/
public void loadFinished(IContributionEvent event);
/**
* Contribution卸载时执行方法.
*/
public void unLoad(IContributionEvent event);
}
IContributionListener类操作说明:
方法签名 | 功能说明 |
---|---|
load (IContributionEvent event) | Contribution加载时执行方法 |
loadFinished(IContributionEvent event) | Contribution加载完成时执行的任务 |
unLoad(IContributionEvent event) | Contribution卸载时执行方法 |
IContributionEvent类:
事件发生时,提供的事件源对象为IContributionEvent,其中包含了构件包的元数据和构件包的配置信息。
IContributionEvent类操作说明:
方法签名 | 功能说明 |
---|---|
ContributionMetaData getContributionMetaData() | 取得Contribution 元数据 |
Configuration getContributionConfiguration() | 取得Contribution 配置,contribution.eosinf文件内容 |
ContributionMetaData类:
构件包元数据类,数据从构件包元数据文件Manifest.MF中获取,遵从OSGI的Bundle规范,有如下属性:
#Manifest 默认版本
Manifest-Version:1.0
# Bundle-Name 构件包显示名称
Bundle-Name: Primeton Test Composite
#构件包的唯一标识,也就是 Bundle 的名称
Bundle-SymbolicName: com.eos.data.simple
# Bundle-Version构件包主版本号
Bundle-Version: 6.0
#构件包提供者
Bundle-Vendor: %Primeton
#依赖的其他构件包,可以是多个,以逗号分割
Require-Bundle:
#允许构件包中存在多个 jar,也可以使用相对路径作为资源加载的位置
Bundle-ClassPath: .
#本构件包所属的模块,
eos-module: module1/sub_module1
#构件包默认的名称空间
eos-basePath: com.eos.bigbank.module1.sub_module1
#构件包中包含所有 web 资源,相对于 web 应用根的相对目录
eos-webCtxPath: bigbank
ContributionMetaData类操作说明:
方法签名 | 功能说明 |
---|---|
String getLabel() | 获取构件包的显示名 |
String getName() | 获取构件包标识 |
String getVersion() | 获取构件包版本 |
String getVendor() | 获取构件包提供商 |
String[] getRequired() | 获取依赖的构件包标识列表 |
String[] getClassPathes() | 获取构件包的类路径 |
String getContainingModule() | 获取构件包所属的Module |
String getBasePath() | 获取构件包的base path |
String getWebCtxPath() | 获取构件包对应的Web Context path |
String getContributionLocation() | 获取构件包的location(绝对路径) |
File getContributionDirectory() | 获取构件包的location(绝对路径) |
# 应用示例
# 场景说明
用户期望开发一个管理组件包状态的框架,该框架包含如下功能:
- 系统装载了那些组件包;
- 那些组件包没有装载成功;
- 卸载过那些组件包。
该框架可以通过构件包加载、卸载扩展点的方式来实现:在构件包加载事件中向框架中加入装载的构件包;在构件包加载成功的事件中向框架通知构件包加载成功;在构件包卸载的事件中向框架通知该构件包已经被卸载;框架获得这些元数据信息后,框架就可以完成各种构件包状态展现的功能。
# 操作步骤
实现IContributionListener接口,完成FrameWorkContributionListener.java的开发。
FrameWorkContributionListener中负责完成向框架注入构件包加载、卸载、加载成功的元数据信息。
实现类的代码如下:
public class FrameWorkContributionListener implements IContributionListener{
//构件包加载的时候,向统计框架注入当前构件包信息
public void load(IContributionEvent event) {
if (event.getContributionMetaData() != null){
String contirbutionName = event.getContributionMetaData().getName();
testInfo=contirbutionName;
FrameWorkStack.addContribution("Contribution:"+contirbutionName);
}
}
//构件包卸载的时候,向统计框架注入当前构件包信息
public void unLoad(IContributionEvent event) {
if (event.getContributionMetaData() != null){
String contirbutionName = event.getContributionMetaData().getName();
FrameWorkStack .addRemovedContribution("Contribution:"
+contirbutionName);
}
}
//构件包加载成功的时候,向统计框架注入当前构件包信息
public void loadFinished(IContributionEvent event) {
if (event.getContributionMetaData() != null){
String contirbutionName = event.getContributionMetaData().getName();
testInfo=contirbutionName;
FrameWorkStack.addSuccessedContribution("Contribution:"
+contirbutionName);
}
}
}
FrameWorkStack负责完成构件包各种状态的统计功能,并提供一种展现方式向用户展现。
在配置文件handler- contribution.xml中配置实体拦截器。
由于需要拦截所有的构件包的加载,因此配置文件应该放置在应用级别的配置文件中,即位置为:eosserver\working\应用名\config\handler- contribution.xml的配置配置文件。
下面是配置文件的信息:
<handles>
<handler handle-class="com.primeton.ext.contribution.framework.
FrameWorkContributionListener "/>
</handles>
这样所有的组件包被加载、卸载的时候都能触发FrameWorkContributionListener。
# Processor拦截器(handler-processor.xml)
与Processor拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler- processor.xml | eosserver\working\应用名\config\handler- processor.xml | 请求的处理器配置文件,功能类似于在web.xml中配置不同的servlet和servlet-mapping的功能;可以为不同的请求配置不同的processor进行处理请求。 |
IProcessor | com.eos.access.http.IProcessor | 请求处理接口类,开发者需要实现该接口。 |
# 功能描述
通常为了对不同的请求进行处理,需要在web.xml中配置多个servlet来实现;当应用中提供的servlet越来越多的时候,web.xml大的难以维护;在EOS6中提供了请求处理器的扩展配置文件,不需要在web.xml文件中进行配置,只需要在handler-processor.xml中进行配置即可;在web.xml中配置的InterceptorFilter会自动将请求根据后缀名转发给handler-processor.xml中配置的processor。
web.xml配置的filter(InterceptorFilter)描述:
<filter>
<filter-name>InterceptorFilter</filter-name>
<filter-class>com.eos.access.http.InterceptorFilter</filter-class>
</filter>
InterceptorFilter会拦截所有的请求,然后分发给不同的processor进行处理。
# 配置文件与关键类
配置文件:handler- processor.xml 关键类:IProcessor
# 配置文件格式说明
文件路径:eosserver\working\应用名\config\handler- processor.xml handler- processor.xml文件格式如下:
<handlers>
<!--
processor配置扩展点
id:编号(不能重复);
suffix:processor匹配的后缀;
sortIdx:排序编号,数字小的先执行;
class:processor实现类;
注意,即使在suffix中配置了多个后缀,但是对每一种后缀都会有不同的processor实例来对相应的请求进行处理。
-->
<handler id="flowProcessor" suffix=".flow,.flowx" sortIdx="0"
class="com.primeton.ext.engine.core.processor.HttpPageFlowProcessor" /> </handlers>
格式说明:
handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照sortIdx 的顺序执行handler,数字越小越先执行。
handler节点:
可以有多个handler节点,用来配置一个完成的请求处理器。
- id属性: 表示handler的编号,在配置文件中,不同的handler之间id编号不能重复;
- suffix属性: processor匹配的后缀名,支持多个,多个之间以","分割;
- sortIdx属性: 排序编号,数字小的先执行;
- class属性: 具体的实现类,必须实现com.eos.access.http.IProcessor。
# 关键类
IProcessor类: 用户实现接口IProcessor,需要实现关键方法process(HttpServletRequest request, HttpServletResponse response),该方法用来处理特定后缀的请求。 类定义如下:
public interface IProcessor {
/**
* 设置请求的后缀名
* 不同的后缀名的请求,会交给不同的processor进行处理
*/
void setRequestSuffix(String requestSuffix);
/**
* 获取能处理的请求后缀名.<br>
* @return 能处理的请求后缀名.
*/
String getRequestSuffix();
/**
* 处理页面请求
* 根据不同的后缀名,交给不同的processor进行处理
*/
void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;
void processException(HttpServletRequest request,
HttpServletResponse response, ExceptionObject exObj) throws IOException,
ServletException;
}
IProcessor类操作说明:
方法签名 | 功能说明 |
---|---|
setRequestSuffix(String requestSuffix) | 设置请求的后缀名。 |
String getRequestSuffix() | 获取能处理的请求后缀名。 |
process(HttpServletRequest request, HttpServletResponse response) | 处理页面请求。 根据不同的后缀名,交给不同的processor进行处理。 |
processException(HttpServletRequest request, HttpServletResponse response, ExceptionObject exObj) | 处理异常情况页面请求。 根据异常对象ExceptionObject来对请求做出响应。 |
# 应用示例
# 场景说明
我们以EOS6中的ActionProcessor为例子来介绍该扩展点的使用。EOS6中提供了页面流的概念,通常在页面中通过"_eosFlowAction"隐含域来实现请求那个action的功能。
页面流引擎提供了一种简便的方式调用页面流,可以通过如下的方式调用:页面流名称+action名称+".action"的方式调用,这样可以在请求的url中直接写aciton的名字,而不必要在form表单中再次填写"_eosFlowAction"字段。
为了实现上面的功能,可以通过实现一个单独的processor来完成对".action"的请求,然后在handler-processor.xml中进行配置,用ActionProcessor来完成所有的".action"的请求。
# 操作步骤
- 实现IProcessor接口,完成ActionProcessor.java的开发。 ActionProcessor中处理后缀名为".action"的请求,以达到上面的场景需求。 实现类的代码如下:
public class ActionProcessor implements IProcessor{
private String requestSuffix;
void setRequestSuffix(String requestSuffix){
this.requestSuffix = requestSuffix;
}
String getRequestSuffix(){
return requestSuffix;
}
void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException{
//action 从请求的uri中获取
String eosFlowAction = getRequestedActionName(request);
......
//上面省略了对请求处理的代码实现
}
void processException(HttpServletRequest request,
HttpServletResponse response, ExceptionObject exObj) throws IOException,
ServletException{
String errorPage = exObj.__getForwardPage();
if (errorPage != null && errorPage.length() > 0) {
if (exObj.isNeedForward()) {
RequestDispatcher rd = request.getRequestDispatcher(errorPage);
rd.forward(request, response);
} else {
response.sendRedirect(errorPage);
}
} else {
throw new ServletException(exObj.getThrowable());
}
}
}
- 在配置文件handler- processor.xml中配置实体拦截器。 下面是配置文件的信息:
<handles>
<handler id="actionProcessor" suffix=".action" sortIdx="0"
class="com.primeton.ext.engine.core.processor.ActionProcessor" /> </handles>
这样所有对".action"的请求都将被转发到ActionProcessor上面进行处理,无需修改web.xml文件,就可以做到对不同请求的拦截处理。
# 启动拦截器(handler-startup.xml)
与启动拦截器相关的配置文件与接口类:
配置文件/关键类 | 路径/包名 | 说明 |
---|---|---|
handler- startup.xml | eosserver\working\应用名\config\handler- startup.xml | 应用启动时候,需要执行的listener;达到执行回调的目的 |
IRuntimeListener | com.eos.runtime.core.IRuntimeListener | 应用启动Listener,用户需要实现该接口 |
RuntimeEvent | com.eos.runtime.core.RuntimeEvent | 应用启动的触发事件 |
ApplicationContext | com.eos.runtime.core.ApplicationContext | 应用上下文信息,可以获取和应用相关的配置信息 |
# 功能描述
在应用启动、停止,构件运行环境提供了一种回调机制;当应用启动、停止事件发生时,可以回调用户定义的操作,完成其特定的功能。通常可以完成功能模块的初始化、为应用开启一种新的服务等。
EOS在handler- startup.xml文件中配置了一系列应用启动监听器、这些默认监听器用户尽量不要修改,否则可能会引起某些功能性异常,但用户可以配置自己的监听器,以便在应用启动、停止的时候执行用户自定义的动作。
# 配置文件与关键类
配置文件:handler- startup.xml 关键类:IRuntimeListener、RuntimeEvent、ApplicationContext
# 配置文件格式说明
文件路径:eosserver\working\应用名\config\handler- startup.xml handler- startup.xml文件格式如下:
<handlers>
<!--启动DAS_ENTITY-->
<handler handle-class="com.primeton.ext.das.common.
DASCommonStartupListener"/>
</handlers>
格式说明:
- handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。
- handler节点: 可以有多个handler节点,不同的handler执行顺序按照配置文件中定义的顺序执行。 handle-class属性: 具体的实现类,必须实现com.eos.runtime.core.IRuntimeListener。
# 关键类
IRuntimeListener类:
用户实现接口IRuntimeListener,需要分别实现start()和stop()方法,分别在应用启动和应用停止的时候回调用户的操作。
类定义如下:
public interface IRuntimeListener {
/**
* 启动应用
* @param envent
*/
public void start(RuntimeEvent envent);
/**
* 结束应用
* @param envent
*/
public void stop(RuntimeEvent envent);
}
IRuntimeListener类操作说明:
方法签名 | 功能说明 |
---|---|
start(RuntimeEvent envent) | 应用启动的时候,会触发该操作 |
stop(RuntimeEvent envent) | 应用停止的时候,会触发该操作 |
RuntimeEvent类:
在应用启动、停止的时候,会发出该事件,通过RuntimeEvent可以获取:
Unknown macro: {span}
- 系统配置文件对象;
- 用户配置文件对象;
- 用户自定义配置文件对象;
- 应用上下文对象。
RuntimeEvent类操作说明:
方法签名 | 功能说明 |
---|---|
ApplicationContext getApplicationContext() | 应用上下文对象ApplicationContext |
Configuration getSystemConfiguration() | 系统配置文件对象Configuration(对应配置文件$EOS_HOME/working/$AppName/config/sys-config.xml) |
Configuration getUserConfiguration() | 用户配置文件对象Configuration(对应配置文件$EOS_HOME/working/$AppName/config/user-config.xml) |
Configuration getUserLocalConfiguration() | 用户自定义配置文件对象Configuration(对应配置文件$EOS_HOME/working/$AppName/config/user-local-config.xml) |
ApplicationContext类:
应用上下文类,可以获取以下的应用环境信息:
ApplicationContext类操作说明:
方法签名 | 功能说明 |
---|---|
方法签名 | 功能说明 |
String getEOS_HOME() | 获取返回EOS_HOME路径 |
String getAppName() | 获取应用名 |
String getApplicationWorkPath() | 获取应用的工作路径 eg:eosserver/working/eos-default |
String getApplicationConfigPath() | 获取应用配置文件路径 eg:eosserver/working/eos-default/config |
String getApplicationSysConfigurationFile() | 取得应用级别系统配置文件(sys-config.xml)的全路径 |
String getApplicationUserConfigurationFile() | 取得应用级别用户配置文件(user-config.xml)的全路径 |
String getApplicationUserLocalConfigurationFile() | 取得应用级别本地用户自定义配置文件(user-local-config.xml)的全路径 |
String getApplicationSystemWorkingPath() | 取得系统构件包的工作路径 |
String getApplicationUserWorkingPath() | 取得用户构件包的工作路径 |
String getEarRealPath() | 取得应用EAR的实际路径 |
String getWarRealPath() | 取得应用WAR的类路径 |
String getWebContextPath() | 取得应用对应的WEB Context名称 |
# 应用示例
# 场景说明
用户拿到EOS之后,自行开发了一个平台模块(统计监控)的功能,希望在EOS应用启动的时候将该平台模块(统计监控)启动起来,以方便对外提供服务使用。
为了实现上述的场景,用户只需要简单的实现IRuntimeListener接口,然后在hanlder-startup.xml配置上述Listener即可。
# 操作步骤
实现IRuntimeListener接口,完成StatisticRuntimeListener.java的开发。
StatisticRuntimeListener中统计监控模块的启动和停止功能。
实现类的代码如下:
public class StatisticRuntimeListener implements IRuntimeListener{
/**
* 打开统计功能
*/
public void start(RuntimeEvent envent) {
//打开统计功能
Statistic.openStatistic();
}
/**
* 关闭统计功能
*/
public void stop(RuntimeEvent envent) {
//关闭统计功能
Statistic.closeStatistic();
}
}
在配置文件handler- startup.xml中配置实体拦截器。
下面是配置文件的信息:
<handles>
<!—统计功能模块-->
<handler handle-class="com.primeton.ext.runtime.resource.
startup.StatisticRuntimeListener"/>
</handles>
这样在应用启动的时候,就可以将统计模块自动的加载起来;可以对外提供统计服务功能。
# 资源访问检查拦截器(IAccessedResourceCheckedHandler接口)
与事务同步扩展点相关的接口类: 关键类说明:
关键类 | 包名 | 说明 |
---|---|---|
IAccessedResourceCheckedHandler | com.eos.access.authorization.IAccessedResourceCheckedHandler | 资源访问检查接口 |
IAccessedResourceFactory | com.eos.access.authorization.IAccessedResourceFactory | 可访问资源创建工厂 |
IAccessedResource | com.eos.access.authorization.IAccessedResource | 可访问资源对象 |
# 功能描述
资源访问授权检查接口,可以利用该接口完成具体的授权访问策略。用来检查用户是否拥有对某些资源进行访问的权限。这里接口的实现者需要根据自己业务上的规则,确定用户可以访问的资源;如果用户可以访问资源,返回通过;否则返回不通过。
# 关键类
关键类:IAccessedResourceCheckedHandler、IAccessedResourceFactory
- IAccessedResourceCheckedHandler类: 类定义如下:
public interface IAccessedResourceCheckedHandler extends Serializable {
/**
* 检查用户是否可以访问资源.<br>
* @param accessedResource 被访问的资源.
* @param userObject 用户对象.
* @return 检查结果.
*/
CheckedResult check(IAccessedResource accessedResource,
IUserObject userObject);
}
IAccessedResourceCheckedHandler类操作说明:
方法签名 | 功能说明 |
---|---|
check(IAccessedResource accessedResource, IUserObject userObject) | 校验用户使用可以访问资源 |
- IAccessedResource 可访问资源类,类包含一个资源的唯一标示符URI和一个资源类型。类定义如下:
public interface IAccessedResource extends Serializable {
/**
* 获取资源对应的URI.<br>
* 如: /user/login.jsp;com.eos.userLogin.flow
* @return 资源对应的URI.
*/
String getResourceURI();
/**
* 获取资源类型.<br>
* 见{@link AccessedResourceType#BIZ_RESOURCE}
* @return 资源类型.
*/
int getResourceType();
}
- IAccessedResourceFactory 资源访问工厂类,用来创建可以访问的资源对象IAccessedResource(包含resourceURI和resourceType两个属性)。EOS系统缺省提供了一个DefaultAccessedResourceFactory工厂类,可以创建jsp页面、页面流、逻辑流、服务等资源信息。用户可以扩展这个接口,提供新的访问资源。资源类定义如下:
public interface IAccessedResourceFactory {
/**
* 创建资源对象.<br>
* @param context 资源访问的上下文.
* @return 资源对象.
*/
IAccessedResource create(IAccessedResourceContext context);
}
下面是DefaultAccessedResourceFactory类的例子,用户如果想扩展,可以参考这个例子来写。
public class DefaultAccessedResourceFactory implements
IAccessedResourceFactory {
private static IAccessedResourceFactory factory = new DefaultAccessedResourceFactory();
public static IAccessedResourceFactory getInstance() {
return factory;
}
public IAccessedResource create(IAccessedResourceContext context) {
//先做用户定义的
if (AccessedResourceCustomFactoryProvider.getFactory() != null) {
IAccessedResource resource = AccessedResourceCustomFactoryProvider
.getFactory().create(context);
if (resource != null)
return resource;
}
String resource = context.getResource();
switch (context.getResourceType()) {
case AccessedResourceType.PAGE_RESOURCE:
AccessedHttpResource pageResource = new AccessedPageResource(resource);
pageResource.setRequest(context.getRequest());
pageResource.setResponse(context.getResponse());
return pageResource;
case AccessedResourceType.PAGE_FLOW_RESOURCE:
AccessedPageFlowResource pageFlowResource = new AccessedPageFlowResource(resource);
pageFlowResource.setRequest(context.getRequest());
pageFlowResource.setResponse(context.getResponse());
String eosFlowAction=(String)context.getRequest().getAttribute(AbstractPageFlowProcessor.EOS_PAGEFLOW_ACTION);
if(eosFlowAction == null){
eosFlowAction=(String)context.getRequest().getParameter(AbstractPageFlowProcessor.EOS_PAGEFLOW_ACTION);
}
pageFlowResource.setActionName(eosFlowAction);
return pageFlowResource;
case AccessedResourceType.BIZ_RESOURCE:
AccessedBizResource bizResource = new AccessedBizResource(resource);
return bizResource;
case AccessedResourceType.SERVICE_RESOURCE:
AccessedServiceResource serviceResource = new AccessedServiceResource(resource);
return serviceResource;
default:
throw new IllegalArgumentException(
"the type cannot create IAccessedResource");
}
}
}
# 应用示例
# 场景说明
用户希望完成对资源的访问控制,不同的用户对不同的资源有不同的权限。可以实现IAccessedResourceCheckedHandler接口,定义不同用户对资源的访问规则。
示例中只有用户名为"root"的超级用户有访问逻辑流资源的权限;其它用户都没有访问权限。
# 示例实现
- 实现IAccessedResourceCheckedHandler接口,完成MyAccessedResourceCheckedHandler的开发。 内部的判断逻辑,是只有用户名为"root"的超级用户拥有访问逻辑流的权限; 实现类的代码如下:
public class MyAccessedResourceCheckedHandler implements
IAccessedResourceCheckedHandler{
public CheckedResult check(IAccessedResource accessedResource,
IUserObject userObject){
boolean isRoot = "root".equals(userObject.getUserId());
//是否是逻辑流资源
boolean isBizResource = (AccessedResourceType.BIZ_RESOURCE ==
accessedResource.getResourceType());
if(isBizResource){
if(isRoot){
return CheckedResult.PASS;
}else{
return CheckedResult.REJECT;
}
}
return CheckedResult.PASS;
}
}
- 在EOS管理控制台上配置资源监察拦截器。 登录Governor,选择"配置—资源方法权限"菜单,进入配置页面如下,将用户自定义的资源检查拦截器和资源创建工厂类名写入配置项,按"确定"更新。 以上配置对应配置文件user-config.xml下面的配置内容:
<!-- 资源访问的检查 -->
<module name="Accessed-Resource-Checked">
<group name="Provider">
<!-- 用户自定义资源检查的handler -->
<configValue key="CheckedHandler">
com.primeton.sample. MyAccessedResourceCheckedHandler </configValue>
<!-- 用户自定义资源的创建工厂 -->
<configValue key="ResourceFactory">
com.primeton.ext.access.authorization.DefaultAccessedResourceFactory
</configValue>
</group>
</module>
# 系统服务监听(LifecycleSupport接口)
与系统服务监听相关的接口类: 配置文件、关键类说明:
关键类 | 路径/包名 | 说明 |
---|---|---|
config.xml | 安装目录/eosserver/config/config.xml | 配置生命周期接口实现类 |
ILifecycle | com.eos.system.ILifecycle | 生命周期接口类 |
ILifecycleListener | com.eos.system.ILifecycleListener | 生命周期事件监听器,监听生命周期事件 |
LifecycleEvent | com.eos.system.LifecycleEvent | 定义了生命周期的事件 |
LifecycleSupport | com.eos.system.LifecycleSupport | 生命周期接口支持类,实现了部分ILifecycle和ILifecycleListener接口,并可以触发所有监听器处理生命周期事件; 用户可以直接使用该抽象类来完成上面的接口完成的功能,大大简化了用户使用的复杂度。 |
# 功能描述
系统服务是EOS服务器最底层的服务,主要负责整个EOSserver的生命周期管理、EOS域的管理、EOS应用的管理和部署、主管服务器和被管服务之间的相互通讯、应用的同步等管理操作。
系统服务提供了一个服务的生命周期的管理框架,允许用户在EOS服务器启动过程中,运行用户自定义的服务。也就是说,用户通过扩展开发可以在EOS Server启动的过程中加入自己希望启动的底层服务。
# 关键类
关键类:ILifecycle、ILifecycleListener、LifecycleEvent、LifecycleSupport
- ILifecycle类: 生命周期的接口类,用户需要重点实现其中的start()和 stop()两个方法,分别表示服务的启动、服务的停止操作。 类定义如下:
public interface ILifecycle {
public static final String START_EVENT="start";
public static final String STOP_EVENT="stop";
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void addLifecycleListener(ILifecycleListener listener);
public List<ILifecycleListener> findLifecycleListeners();
public void removeLifecycleListener(ILifecycleListener listener);
}
ILifecycle类操作说明:
方法签名 | 功能说明 |
---|---|
start() | 服务启动入口 |
stop() | 服务停止入口 |
addLifecycleListener(ILifecycleListener listener) | 注册生命周期监听器 |
List<ILifecycleListener> findLifecycleListeners() | 查找所有注册过的生命周期监听器 |
removeLifecycleListener(ILifecycleListener listener) | 删除生命周期监听器 |
- ILifecycleListener类: 生命周期事件监听器类,用于监听生命周期事件。 ILifecycleListener类操作说明:
方法签名 | 功能说明 |
---|---|
void handleEvent(LifecycleEvent event) | 处理生命周期事件 |
- LifecycleEvent类: 生命周期事件类,主要包括事件的类型、事件的发生源、上下文数据等。 LifecycleEvent类操作说明:
方法签名 | 功能说明 |
---|---|
Object getData() | 上下文数据,一般传入ServerContext |
ILifecycle getLifecycle() | 事件的发生源(是触发时间的ILifecycle实例) |
String getType() | 获取事件的类型,通常有两种,由ILifecycle的常量来定义。 START_EVENT:启动事件 STOP_EVENT:停止事件 |
- LifecycleSupport类: 生命周期接口支持类,实现了部分ILifecycle和ILifecycleListener接口,并可以触发所有监听器处理生命周期事件; 用户可以直接使用该抽象类来完成上面的接口完成的功能,大大简化了用户使用的复杂度(com.eos.system.LifecycleSupport抽象类,这个类实现了ILifecycle接口和ILifecycleListener接口); 用户直接使用这个抽象类的时候,只需要实现start()和stop()两个方法。
# 应用示例
# 场景说明
本例中在EOS系统服务启动的过程中,启动一个时间服务器,当客户端每次访问的时候,可以返回当前的服务器端的时间。
# 示例实现
- 继承LifecycleSupport抽象类,完成TimeService的开发。 TimeServer中,主要实现了start()和stop()方法。提供的时间服务,通过创建一个ServerSocket连接,将当前服务器的时间返回给客户端。 实现类的代码如下:
public class TimeService extends LifecycleSupport {
private TimeServiceThread timeService;
static class TimeServiceThread extends Thread {
private ServerSocket server;
public ServerSocket getServerSocket() {
return server;
}
public void run() {
int port = ServerContext.getInstance().getAdminPort()+1;
try {
server = new ServerSocket(port);
System.out.println("Time Service is opened on port " + port);
} catch (IOException ex) {
ex.printStackTrace();
}
Socket connection = null;
while (true) {
try {
if (this.isInterrupted()) { // 中断线程
server.close();
System.out.println("Time Service is stopped.");
break;
}
connection = server.accept();
Writer out = new OutputStreamWriter(
connection.getOutputStream());
Date now = new Date();
out.write(now + "\r\n");
out.flush();
connection.close();
} catch (IOException ex) {
} finally {
try {
if (connection != null) connection.close();
} catch (IOException ex) {
}
}
}
}
}
public void start() throws LifecycleException {
this.timeService = new TimeServiceThread();
this.timeService.start();
}
public void stop() throws LifecycleException {
this.timeService.interrupt();
}
}
- 在安装目录/eosserver/config/config.xml文件中配置时间服务器。 参见下面的代码示例:
<listeners>
<listener name="TimeService" className="test.TimeService"/>
</listeners>
为了完整的演示效果,这里提供一个客户端的代码;通过执行客户端的代码,可以获取服务器端的时间。
注意
为了正确执行,需要正确的配置Socket的ip和端口号。
参见下面的客户端代码示例:
public static void main(String[] args) {
try {
Socket soc = new Socket("localhost", 6287);
BufferedReader br = null;
InputStreamReader isr;
isr = new InputStreamReader(soc.getInputStream ());
br = new BufferedReader (isr);
String result = br.readLine();
System.out.println(result);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
执行上面的main函数后,可以从控制台看到服务器端的时间: Thu Sep 17 16:00:33 CST 2009