在osmp里,osmp-http对外发布了统一的访问接口,接受请求解析后从osmp-service容器里获取服务,调用并将结果返回,在这个过程中,我们通过编写自定义的拦截器对请求进行拦截,主要应用以下场景 (安全、权限、数据过滤、数据格式化、记录入参、出参日志、调用统计分析、全链路日志等AOP形为)。
下面我们介绍怎样在osmp框架下编写我们的第一个拦截器对非法IP的请求进行拦截。
1、参照前面讲的第一个服务的开发,搭建组件开发环境,把没有的类和包删除。
2、新增拦截器实现类OsmpDemoInterceptor.java
/*
* Project: 基础组件
* FileName: SicentTestServiceImpl.java
* Company: Chengdu Sicent Technology Co.,Ltd
* version: V1.0
*/
package com.osmp.demo.interceptor;
import org.springframework.stereotype.Component;
import com.osmp.intf.define.config.FrameConst;
import com.osmp.intf.define.interceptor.ServiceInterceptor;
import com.osmp.intf.define.interceptor.ServiceInvocation;
import com.osmp.intf.define.model.ServiceContext;
/**
* Description:日志拦截用于统计日志访问提供支撑数据
*
* @author: wangkaiping
* @date: 2014年9月26日 下午3:03:55
*/
@Component
public class OsmpDemoInterceptor implements ServiceInterceptor {
@Override
public Object invock(ServiceInvocation invocation) {
ServiceContext context = invocation.getContext();
String ip = context.getClientInfo().get(FrameConst.CLIENT_IP);
String serviceName = context.getServiceName();
System.out.println("serviceName : " + serviceName);
System.out.println("IP拦截 : " + ip);
if ("192.168.1.1".equals(ip)) {
return "IP非法!";
} else {
return invocation.process();
}
}
}
实现osmp-intf-define 定义的拦截器接口 ServiceInterceptor.java, 这里我们从ServiceInvocation里获取ServiceContext 上下文,并得到客户端信息。
从客户端信息里获取客户端IP 判断 客户端IP是否为 "192.168.1.1" 如果是的话我们返回IP非法,如果不是则执行请求并返回!
拦截器接口定义 ServiceInterceptor.java
/*
* Project: OSMP
* FileName: ServiceInterceptor.java
* version: V1.0
*/
package com.osmp.intf.define.interceptor;
/**
* Description:拦截器
* 所有基于osmp的拦截器都需要实现该接口,拦截器按作用域分为全局拦截器,BUNDLE拦截器,SERVICE拦截器三种类型。
* 全局拦截器(ALL): 作用于osmp的所有BUNDLE和服务。
* BUNDLE拦截器(BUNDLE): 作用于osmp指定BUNDLE下的所有服务。
* SERVICE拦截器(SERVICE): 作用于osmp指定的SERVICE服务。
*
* 拦截器适用于 接口安全、权限校验、全局日志、调用链日志Track、特定服务AOP拦截等业务场景
*
* 服务发布时,需要在service-properties 里指定拦截器的类型(type)和匹配的拦截策略(pattern)
*
* <osgi:service interface="com.osmp.intf.define.interceptor.ServiceInterceptor" ref="osmp.demo.interceptor">
<osgi:service-properties>
<entry key="name" value="Interceptor_demo" />
<entry key="mark" value="拦截器demo"/>
<entry key="type" value="SERVICE"/> //type:ALL、BUNDLE、SERVICE
<entry key="pattern" value="这里是发布的服务名称"/> //支持正则匹配、 AAAService* 、 *AAA* 、
</osgi:service-properties>
</osgi:service>
*
* 拦截器与bundle、服务两种绑定方式:
* 1、拦截器被安装时osmp-service组件进行bundle监听时,通过bundle获取interface service 后解析type和 pattern并注入到ServiceContainer中。
* 2、通过osmp-web在线可以绑定和解绑拦截器与bundle、服务。
*
* @author: wangkaiping
* @date: 2016年8月9日 上午9:26:32上午10:51:30
*/
public interface ServiceInterceptor {
Object invock(ServiceInvocation invocation);
}
ServiceInvocation定义了 ServiceContext getContext(); Object process(); 两个接口,
getContext()接口获取服务上下文,上下文包含了 请求客户端基本信息、请求参数、服务名称、及请求的url字符串等信息
process()请求执行接口,默认实现为,先从拦截器链里获取此服务对应的拦截器,如果拦截器链为空则直接执行BaseDataService的execture() 调用服务,如果不为空则执行调用拦截器链执行。
默认为 Invocation 实现 DefaultServiceInvocation.java
/*
* Project: OSMP
* FileName: DefaultServiceInvocation.java
* version: V1.0
*/
package com.osmp.http.tool;
import java.util.List;
import com.osmp.intf.define.interceptor.ServiceInterceptor;
import com.osmp.intf.define.interceptor.ServiceInvocation;
import com.osmp.intf.define.model.ServiceContext;
import com.osmp.intf.define.service.BaseDataService;
/**
* 服务拦截器调用
* @author heyu
*
*/
public class DefaultServiceInvocation implements ServiceInvocation {
private int currentInterceptorIndex = 0;
private List<ServiceInterceptor> interceptorChain;
private BaseDataService dataService;
private ServiceContext context;
private boolean isError = true;
@Override
public Object process() {
if(interceptorChain == null || interceptorChain.isEmpty()){
isError = false;
return dataService.execute(context.getParameter());
}
if(currentInterceptorIndex == interceptorChain.size()){
isError =false;
return dataService.execute(context.getParameter());
}
++currentInterceptorIndex;
return interceptorChain.get(currentInterceptorIndex-1).invock(this);
}
public DefaultServiceInvocation(List<ServiceInterceptor> interceptorChain,
BaseDataService dataService, ServiceContext context) {
super();
this.interceptorChain = interceptorChain;
this.dataService = dataService;
this.context = context;
}
@Override
public ServiceContext getContext() {
return context;
}
public boolean isError() {
return isError;
}
}
3、编写spirng配置文件 /src/main/resources/META-INF/spring/spirng-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd">
<context:component-scan base-package="com.osmp.demo.interceptor"></context:component-scan>
<bean id="osmp.demo.interceptor" class="com.osmp.demo.interceptor.OsmpDemoInterceptor" />
<osgi:service interface="com.osmp.intf.define.interceptor.ServiceInterceptor" ref="osmp.demo.interceptor">
<osgi:service-properties>
<entry key="name" value="Interceptor_demo" />
<entry key="mark" value="拦截器demo"/>
<entry key="type" value="ALL"/>
<entry key="pattern" value=""/>
</osgi:service-properties>
</osgi:service>
</beans>
- 将拦截器实现发布为服务
- 服务属性包括 name、mark、type、pattern
- name:拦截器名称
- mark:拦截器注释
- type:拦截器类型(ALL:全局拦截 BUNDLE:bundle拦截器 SERVICE:服务拦截器)可以省略,默认为ALL 全局拦截
- pattern:拦截匹配 (只有type 不为 ALL生效,可以省略 eg: 正则匹配、 AAAService* 、 *AAA* )
4、pom.xml 配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.osmp.baseweb</groupId> <artifactId>osmp-parent</artifactId> <version>1.0.0</version> </parent> <artifactId>osmp-interceptor-demo</artifactId> <packaging>bundle</packaging> <name>osmp-interceptor-demo</name> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> <configuration> <instructions> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Export-Package></Export-Package> <Import-Package> *;resolution:=optional </Import-Package> </instructions> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.osmp.baseweb</groupId> <artifactId>osmp-intf-define</artifactId> <version>${osmp.version}</version> </dependency> </dependencies> </project>
5、打包部署 mvn install ,将打好的bundle包(osmp-interceptor-demo-1.0.0.jar)部署到servicemix里
6、将拦截器绑定,自动绑定、手动绑定两种方式:
- 自动绑定:在将拦截器部署到servicemix的时候 osmp-service会监听拦截器接口服务,解析 typ、pattern进行自动绑定
- 手动绑定:我们将拦截器部署后,如果没有添加type、pattern拦截器属性时,可以通过调用osmp-config提供的接口手动绑定。
7、访问请求
拦截器已经 生效,我们再停掉拦截器
再次访问
正常返回请求
至此基于osmp的拦截器开发已经完成。