ESB文档库 ESB文档库
00 概述
01 产品安装指南
02 快速入门指南
03 ESB Studio使用指南
04 企业服务总线使用指南
05 高级配置指南
06 接口服务说明
07 升级&数据迁移指南
08 FAQ
  • 拦截器
  • 标准拦截器实现
  • 自定义协议拦截器实现
  • IP地址拦截器示例

# 拦截器

ESB提供了拦截器接口,用户需要根据自己对拦截器的要求实现标准拦截器(HTTP协议和Soap协议)或者自定义协议拦截器(TCP协议、FTP协议、UDP协议、Email、EJB和CUST中包含的IBMMQ和TUXEDO)。 本文以实现ws的代理服务上的数据请求拦截器为例,说明如何开发符合客户需求的拦截器。

本节分为以下几个部分:

  1. 标准拦截器实现
  2. 自定义协议拦截器实现
  3. 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

← 3.6.4 消息确认 3.6.6 自带拦截器说明 →