# 拦截器
ESB提供了拦截器接口,用户需要根据自己对拦截器的要求实现标准拦截器(HTTP协议和Soap协议)或者自定义协议拦截器(TCP协议、FTP协议、UDP协议、Email、EJB和CUST中包含的IBMMQ和TUXEDO)。 本文以实现ws的代理服务上的数据请求拦截器为例,说明如何开发符合客户需求的拦截器。
本节分为以下几个部分:
- 标准拦截器实现
- 自定义协议拦截器实现
- IP地址拦截器示例
# 标准拦截器实现
拦截器接口为IInterceptor4Service<MSG, CTX>,用户开发拦截器必须实现这个接口,在这个接口的beforeHandle(MSG message, CTX context),afterHandle(MSG message, CTX context) 加入对拦截器的要求,例如:该拦截器需要落日志,对文件进行操作,对数据库进行操作等等。
拦截器接口IInterceptor4Service说明:
- open方法打开拦截器
- close方法关闭拦截器
- call方法调用业务逻辑
- beforeHandle方法是在该服务的消息进行转换前调用
- afterHandle方法是在该服务的消息进行转换后调用
注意:afterHandle和beforeHandle返回值决定了消息能否在ESB中继续发送,只有当返回的只为"0"时,消息才能继续发送,为其他值时都会驳回消息。
步骤1、Java代码实例如下:
package com.primeton.esb.interceptor.test;
import com.primeton.esb.model.IInterceptor4Service;
import com.primeton.esb.soap.inbound.model.IWebServiceInbound;
import org.springframework.messaging.Message;
public class SoapInboundRequest implements IInterceptor4Service<Message<?>, IWebServiceInbound> {
public int afterHandle(Message<?> arg0, IWebServiceInbound arg1) {
System.out.println("inbound request afterHandle");
return 0;
}
public int beforeHandle(Message<?> arg0, IWebServiceInbound arg1) {
System.out.println("inbound request beforeHandle");
return 0;
}
public int call(Message<?> arg0, IWebServiceInbound arg1) throws Exception {
return 0;
}
public void close() {
// TODO Auto-generated method stub
}
public boolean isOpen() {
// TODO Auto-generated method stub
return false;
}
public void open() {
// TODO Auto-generated method stub
}
}
为简单起见,本实例只在beforeHandle和afterHandle中打印出来了日志,而实际情况中需要对业务逻辑的实现。
步骤2、将开发出来的实现类导出成jar包放到esbserver环境中,路径为:esbserver安装目录\plugins。
步骤3、打开esb studio,开发一个ws-ws穿透(参考《ESB6.5用户手册》)。
步骤4、将开发好的ws-ws穿透部署到esbserver下(参考《ESB6.5用户手册》)。
步骤5、修改拦截器的加载文件,文件目录为:esbserver安装目录\EOS_srv\config\ esb-interceptor.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<application xmlns="http://www.primeton.com/xmlns/eos/1.0">
<module name="ProxyServiceInterceptor">
<group name="Soap">
<configValue key="requestInterceptor">com.primeton.esb.interceptor.test.SoapInboundRequest</configValue>
</group>
</module>
</application>
esb-interceptor.xml参数说明:
参数名称 | 可选值 | 说明 |
---|---|---|
module | TransportInterceptor | 在Transport上加拦截器 |
ProxyServiceInterceptor | 在代理服务上加拦截器 | |
BusinessServiceInterceptor | 在业务服务上加拦截器 | |
EndpointIntercetor | 在Endpoint上加拦截器 | |
group | Soap | 对Soap协议进行拦截 |
Http | 对Http协议进行拦截 | |
configValue | requestInterceptor | 请求channel的拦截器 |
replyInterceptor | 响应channel的拦截器 | |
errorInterceptor | 异常channel的拦截器 |
说明:
(1)ESB默认提供了6个拦截器,分别为soap协议的代理服务的requestInterceptor、replyInterceptor、errorInterceptor,业务服务的requestInterceptor、replyInterceptor、errorInterceptor。这几个拦截器是用来对日志进行落地。
(2)如果在一层需要配置两个或多个拦截器,需要用","隔开。
步骤6、启动esbserver:
步骤7、使用soap-ui发送soap请求
步骤8、查看esbserver的控制台
# 自定义协议拦截器实现
以上标准拦截器的实现步骤适用于自定义协议拦截器的实现,只是在自定义拦截器实现类的定义过程中要求更严苛。 由于自定义协议拦截器可对包括TCP协议、FTP协议、UDP协议、Email、EJB以及CUST协议中包含的IBMMQ和TUXEDO的协议进行处理, 所以自定义协议拦截器的实现类要以TCP、FTP、UDP、Email、EJB、IBMMQ和TUXEDO开头,下面以esbserver安装目录\EOS_srv\config\ esb-interceptor.xml的配置为例, 具体说明自定义协议拦截器配置及加载过程。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<application xmlns="http://www.primeton.com/xmlns/eos/1.0">
<module name="TransportInterceptor">
<group name="Http">
<configValue key="requestInterceptor">
com.primeton.esb.interceptor.kvlist.ClientIdClientIPInterceptor,com.primeton.esb.interceptor.kvlist.ClientIdOperationInterceptor
</configValue>
</group>
<group name="CUST">
<configValue key="requestInterceptor">
com.primeton.esb.interceptor.kvlist.TCPInterceptor,com.primeton.esb.interceptor.kvlist.TESTInterceptor,com.primeton.esb.interceptor.kvlist.TCPOperationInterceptor
</configValue>
</group>
</module>
<module name="ProxyServiceInterceptor">
<group name="Soap">
<configValue key="requestInterceptor">com.primeton.esb.interceptor.logger.SoapReqInBoundInterceptor</configValue>
<configValue key="replyInterceptor">com.primeton.esb.interceptor.logger.SoapRespInBoundInterceptor</configValue>
<configValue key="errorInterceptor">com.primeton.esb.interceptor.logger.SoapErrorInBoundInterceptor</configValue>
</group>
</module>
<module name="BusinessServiceInterceptor">
<group name="Soap">
<configValue key="requestInterceptor">com.primeton.esb.interceptor.logger.SoapReqOutBoundInterceptor</configValue>
<configValue key="replyInterceptor">com.primeton.esb.interceptor.logger.SoapRespOutBoundInterceptor</configValue>
<configValue key="errorInterceptor">com.primeton.esb.interceptor.logger.SoapErrorOutBoundInterceptor</configValue>
</group>
<group name="CUST">
<configValue key="requestInterceptor">
com.primeton.esb.interceptor.logger.TCPReqOutBoundInterceptor,com.primeton.esb.interceptor.logger.TESTOutInterceptor
</configValue>
<configValue key="replyInterceptor">com.primeton.esb.interceptor.logger.TCPRespOutBoundInterceptor</configValue>
<configValue key="errorInterceptor">com.primeton.esb.interceptor.logger.TCPErrorOutBoundInterceptor</configValue>
</group>
</module>
</application>
解析:
示例拦截器配置文件中共添加了Http标准类型拦截器(Transport)、Soap标准类型拦截器(代理服务、业务服务)和自定义协议(CUST)TCP类型拦截器(Transport、业务服务); 针对自定义协议TCP类型拦截器在Transport端的拦截,我们在配置了三个拦截器类, 分别是TCPInterceptor、TESTInterceptor和TCPOperationInterceptor,由于ESB server加载TCP协议模型文件时会根据具体的协议类型"TCP"加载以TCP开始的拦截器, 所以配置文件中的TESTInterceptor拦截器不会被加载到TCP协议的应用中。
在配置文件中"TCP业务服务"的拦截器装配机制与上面描述相同。
# IP地址拦截器示例
步骤1、开发一个HTTP Transport上的IP地址拦截器IPInterceptor,源码如下:
package com.primeton.esb.interceptor.kvlist;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import com.eos.common.connection.DataSourceHelper;
import com.primeton.esb.common.TipIdentifierBuilder;
import com.primeton.esb.http.HttpConstants;
import com.primeton.esb.message.ITipMessagePayload;
import com.primeton.esb.model.Constants;
import com.primeton.esb.model.IInterceptor4Service;
import com.primeton.esb.model.transport.ITransport;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
/**
* Transport拦截器,根据客户端IP拦截请求
* @author Administrator
*
* @param <T>
*/
public class IPInterceptor<T> implements IInterceptor4Service<Message<?>, ITransport<T>> {
private static final String ENVELOPE_NAMESPACE_URI_SOAP11 = "http://schemas.xmlsoap.org/soap/envelope/";
public IPInterceptor() {
}
public int beforeHandle(Message<?> message, ITransport<T> transport) {
System.out.println("Transport request beforeHandle");
int code = CONTINUE;//CONTINUE的值为0
//使用ESB自带方法连接Server中配置的数据库,读取IP地址记录
DataSource datasource = DataSourceHelper.getDataSource("default");
Connection connection;
List<String> iplist = new ArrayList<String>();
try {
connection = datasource.getConnection();
Statement stmt = connection.createStatement();
String sql = "select * from ip_table";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
iplist.add(rs.getString(1));
System.out.println("ip地址:" + rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
}
ITipMessagePayload payload = (ITipMessagePayload) message.getPayload();
// 解析请求的消息获得Protocolheaders里面是客户端发送过来的ClientId & OperationCode & clientIp
Map<?, ?> headers = (Map<?, ?>) payload.getProtocolHeaders();
String clientId = (String) headers.get("ClientId");
String operationCode = (String) headers.get("OperationCode");
String clientIp = (String) headers.get("X-Forwarded-For");
if (clientIp == null || clientIp.length() == 0) {
clientIp = (String) headers.get(HttpConstants.REMOTE_ADDR);
clientIp = clientIp.split(":")[0];
}
System.out.println("请求方地址:" + clientIp);
//判断客户端的ip是不是IP地址记录表中,不在的话驳回请求
if (iplist.contains(clientIp)) {
code = CONTINUE;
} else {
code = BLOCK;//BLOCK值为-1
String faultstring = "请求方地址:" + clientIp + "不在IP地址列表中,不允许访问服务";
sendRejectedMessage(message, transport, Integer.toString(code), faultstring, clientId, operationCode);
}
return code;
}
public int afterHandle(Message<?> message, ITransport<T> context) {
System.out.println("Transport request afterHandle");
return CONTINUE;
}
/**
* ESB返回 的消息
*/
protected void sendRejectedMessage(Message<?> message, ITransport<T> transport, String faultcode,
String faultstring, String ClientId, String OperationCode) {
String rejectMsg = buildSOAPMessageWithFault11(faultcode, faultstring, ClientId, OperationCode);
Message<?> mgs = buildErrorMessage(message, rejectMsg);
transport.getReplyChannel().send(mgs);
}
/**
* 构造异常情况ESB返回 的消息
*/
private Message<?> buildErrorMessage(Message<?> requestMessage, String rejectMsg) {
MessageBuilder<?> builder = MessageBuilder
.withPayload(new FaultMessagePayload(requestMessage, rejectMsg));
builder.setHeader(Constants.CONTINUATION_ID, requestMessage
.getHeaders().get(Constants.CONTINUATION_ID));
builder.setHeader(MessageHeaders.ID,
TipIdentifierBuilder.getMessageId());
MessageHeaders headers = requestMessage.getHeaders();
for (Map.Entry<String, Object> entry : headers.entrySet()) {
String headerKey = entry.getKey();
if (!headerKey.equals(Constants.ERROR_CHANNEL)
&& !headerKey.equals(Constants.REPLY_CHANNEL)) {
builder.setHeader(headerKey, entry.getValue());
}
}
builder.setHeader(Constants.REQUEST_CHANNEL, requestMessage
.getHeaders().get(Constants.ERROR_CHANNEL));
return builder.build();
}
/**
* 构造异常返回 的soap报文
*/
public static String buildSOAPMessageWithFault11(String faultCode, String faultString,
String ClientId, String OperationCode) {
StringBuffer sb = new StringBuffer();
sb.append("<soapenv:Envelope xmlns:soapenv=\"").append(ENVELOPE_NAMESPACE_URI_SOAP11).append("\">");
sb.append("<soapenv:Header>");
sb.append("<ClientId>").append(ClientId).append("</ClientId>");
sb.append("<OperationCode>").append(OperationCode).append("</OperationCode>");
sb.append("</soapenv:Header>");
sb.append("<soapenv:Body>");
sb.append("<soapenv:Fault>");
sb.append("<faultcode>").append(faultCode).append("</faultcode>");
sb.append("<faultMessage>").append(faultString).append("</faultMessage>");
sb.append("</soapenv:Fault>");
sb.append("</soapenv:Body>");
sb.append("</soapenv:Envelope>");
return sb.toString();
}
public boolean onChange(byte[] b) {
// TODO Auto-generated method stub
return false;
}
public boolean isOpen() {
// TODO Auto-generated method stub
return false;
}
public void open() {
// TODO Auto-generated method stub
}
public void close() {
// TODO Auto-generated method stub
}
}
步骤2、将开发出来的实现类导出成jar包放到esbserver环境中,路径为:esbserver安装目录\plugins。
步骤3、打开esb studio,开发一个HTTP穿透。
步骤4、将开发好的HTTP穿透部署到esbserver下。
步骤5、修改拦截器的加载文件,文件目录为:esbserver安装目录\EOS_srv\config\ esb-interceptor.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<application xmlns="http://www.primeton.com/xmlns/eos/1.0">
<module name="TransportInterceptor">
<group name="Http">
<configValue key="requestInterceptor">
com.primeton.esb.interceptor.kvlist.IPInterceptor,
com.primeton.esb.interceptor.kvlist.ClientIdClientIPInterceptor,
com.primeton.esb.interceptor.kvlist.ClientIdOperationInterceptor
</configValue>
</group>
</module>
<module name="ProxyServiceInterceptor">
<group name="Soap">
<configValue key="requestInterceptor">com.primeton.esb.interceptor.logger.SoapReqInBoundInterceptor
</configValue>
<configValue key="replyInterceptor">com.primeton.esb.interceptor.logger.SoapRespInBoundInterceptor
</configValue>
<configValue key="errorInterceptor">com.primeton.esb.interceptor.logger.SoapErrorInBoundInterceptor
</configValue>
</group>
</module>
<module name="BusinessServiceInterceptor">
<group name="Soap">
<configValue key="requestInterceptor">com.primeton.esb.interceptor.logger.SoapReqOutBoundInterceptor
</configValue>
<configValue key="replyInterceptor">com.primeton.esb.interceptor.logger.SoapRespOutBoundInterceptor
</configValue>
<configValue key="errorInterceptor">com.primeton.esb.interceptor.logger.SoapErrorOutBoundInterceptor
</configValue>
</group>
</module>
</application>
步骤6、使用soapUI调用,测试拦截器
- 当请求方IP地址没有在数据库中时,结果如下:
- 当请求方IP地址在数据库中时,结果如下:
标准拦截器示例代码如下: 标准拦截器demo.zip