目录
5、service剔除provider统一配置的Filter
一、简介
我们再开发web应用的时候,通常会需要继承javax.servlet.Filter的接口类来实现统一拦截请求进行处理的功能,如鉴权、日志、Xss攻击拦截等。那么在微服务dubbo框架处理RPC请求的时候,我们是否也有这样的需求,需要对远程服务调用的每一个接口实现自定义的Filter呢?
dubbo提供了调用拦截扩展的方式,通过继承org.apache.dubbo.rpc.Filter的接口类,服务提供方和服务消费方调用过程都可以进行拦截。
本文是基于上篇文章进行的配置实现(SpringCloudAlibaba学习系列(2)dubbo集成),所以这里就不继续重复去搭建项目,只做重点代码配置验证。
二、实战
1、创建filter类
package com.sam.cloud.provider.filter;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FirstRpcFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(FirstRpcFilter.class);
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
LOG.info("我是执行的First的filter:FirstRpcFilter");
return invoker.invoke(invocation);
}
}
这里就是通过集成org.apache.dubbo.rpc.Filter类实现;为了方便后续的验证,这里还创了两个filter:SecondRpcFilter和ThirdRpcFilter
package com.sam.cloud.provider.filter;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SecondRpcFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(SecondRpcFilter.class);
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
LOG.info("我是执行的second的filter:SecondRpcFilter");
return invoker.invoke(invocation);
}
}
package com.sam.cloud.provider.filter;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ThirdRpcFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(ThirdRpcFilter.class);
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
LOG.info("我是执行的third的filter:ThirdRpcFilter");
return invoker.invoke(invocation);
}
}
2、配置Filter文件
在resources目录下创建文件夹/META-INF/dubbo,然后创建纯文本文件:com.alibaba.dubbo.rpc.Filter,内容为:
firstRpcFilter=com.sam.cloud.provider.filter.FirstRpcFilter
secondRpcFilter=com.sam.cloud.provider.filter.SecondRpcFilter
thirdRpcFilter=com.sam.cloud.provider.filter.ThirdRpcFilter
3、配置dubbo
a、作为全局的provider配置使用Filter,有两种方式,基于properties和基于注解
- 基于properties:在bootstarp.properties中添加配置,排序就是执行顺序
dubbo.provider.filter=firstRpcFilter,secondRpcFilter,thirdRpcFilter
- 基于注解:@Activate(group = {CommonConstants.PROVIDER}, order = 1),如果是消费者使用group的值为CommonConstants.CONSUMER,如果是提供者和消费者都用到,就两个都加上,order代表当存在多个自定义filter时执行的顺序。这里只需要在FirstFilter的类上加上注解就可以开启使用。
package com.sam.cloud.provider.filter;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Activate(group = {CommonConstants.PROVIDER}, order = 1)
public class FirstRpcFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(FirstRpcFilter.class);
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
LOG.info("我是执行的First的filter:FirstRpcFilter");
return invoker.invoke(invocation);
}
}
剩余两个类SecondRpcFilter和ThirdRpcFilter也加上同样的注解
4、查看效果
启动提供者magic-provider,然后启动magic-consumer,然后请求接口,查看日志打印为:
INFO#2021-09-12 16:09:58.958#[]#我是执行的First的filter:FirstRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的second的filter:SecondRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的third的filter:ThirdRpcFilter
5、配置service的Filter
上面说的是全局的provider或者consumer配置,但在实际开发中,我们可能会出现需要这个filter只作用在某个service的类中,我们需要怎么样去弄呢?
只需要在注解@DubboService中配置filter就可以,首先先按照第1步和第2步创建了一个Auth的鉴权filter:AuthRpcFilter,不需要设置激活注解@Activate,接着在service实现类的注解设置filter = {"authRpcFilter"},代码如下:
AuthRpcFilter:(这里有个点要注意,如果要使用spring管理的bean,不能用@Resource来注入,需要实现参数的set方法,dubbo会自动进行注入,像下面的代码AuthHandler类的注入那样)
package com.sam.cloud.provider.filter;
import com.sam.cloud.provider.filter.handler.AuthHandler;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AuthRpcFilter implements Filter {
private final Logger LOG = LoggerFactory.getLogger(AuthRpcFilter.class);
//dubbo自己会对这些bean进行注入,不需要再标注@Resource让Spring注入
private AuthHandler authHandler;
public void setAuthHandler(AuthHandler authHandler) {
this.authHandler = authHandler;
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
LOG.info("我是执行的鉴权filter:AuthRpcFilter");
return invoker.invoke(invocation);
}
}
MagicProviderFacadeImpl:
package com.sam.cloud.provider.facade;
import com.sam.cloud.provider.api.domain.UserDTO;
import com.sam.cloud.provider.api.facade.MagicProviderFacade;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService(version = "1.0.0", group = "magic", interfaceClass = MagicProviderFacade.class,
filter = {"authRpcFilter"})
public class MagicProviderFacadeImpl implements MagicProviderFacade {
@Override
public UserDTO queryUser(String name) {
UserDTO user = new UserDTO();
user.setUserId(1);
user.setName("sam");
user.setAge(1L);
return user;
}
}
启动验证输出日志如下:
INFO#2021-09-12 16:09:58.958#[]#我是执行的First的filter:FirstRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的second的filter:SecondRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的third的filter:ThirdRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的鉴权filter:AuthRpcFilter
5、service剔除provider统一配置的Filter
在做业务的时候,可能会出现某个service实现不需要执行某个provider提供的统一filter,这时候可以采用特殊符号“-”进行标识剔除,如下代码:
package com.sam.cloud.provider.facade;
import com.sam.cloud.provider.api.domain.UserDTO;
import com.sam.cloud.provider.api.facade.MagicProviderFacade;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService(version = "1.0.0", group = "magic", interfaceClass = MagicProviderFacade.class,
filter = {"-secondRpcFilter", "authRpcFilter"})
public class MagicProviderFacadeImpl implements MagicProviderFacade {
@Override
public UserDTO queryUser(String name) {
UserDTO user = new UserDTO();
user.setUserId(1);
user.setName("sam");
user.setAge(1L);
return user;
}
}
filter = {"-secondRpcFilter", "authRpcFilter"}就代表这个service会按照顺序执行firstRpcFilter,thirdRpcFilter,authRpcFilter,而忽略secondRpcFilter。
执行日志如下:
INFO#2021-09-12 16:09:58.958#[]#我是执行的First的filter:FirstRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的third的filter:ThirdRpcFilter
INFO#2021-09-12 16:09:58.958#[]#我是执行的鉴权filter:AuthRpcFilter
三、other
参考官网文档:(调用拦截扩展 | Apache Dubbo)
1、用户自定义的 filter 都是默认在dubbot内置 filter 之后执行;目前dubbo内置的filter有如下:
org.apache.dubbo.rpc.filter.EchoFilter
org.apache.dubbo.rpc.filter.GenericFilter
org.apache.dubbo.rpc.filter.GenericImplFilter
org.apache.dubbo.rpc.filter.TokenFilter
org.apache.dubbo.rpc.filter.AccessLogFilter
org.apache.dubbo.rpc.filter.CountFilter
org.apache.dubbo.rpc.filter.ActiveLimitFilter
org.apache.dubbo.rpc.filter.ClassLoaderFilter
org.apache.dubbo.rpc.filter.ContextFilter
org.apache.dubbo.rpc.filter.ConsumerContextFilter
org.apache.dubbo.rpc.filter.ExceptionFilter
org.apache.dubbo.rpc.filter.ExecuteLimitFilter
org.apache.dubbo.rpc.filter.DeprecatedFilter
2、特殊值 default
,表示缺省扩展点插入的位置。比如:filter="xxx,default,yyy"
,表示 xxx
在缺省 filter 之前执行,yyy
在缺省 filter 之后执行
3、特殊符号 -
,表示剔除。比如:filter="-foo1"
,剔除添加缺省扩展点 foo1
。比如:filter="-default"
,剔除添加所有缺省扩展点。
4、provider 和 service 同时配置的 filter 时,累加所有 filter,而不是覆盖。比如:<dubbo:provider filter="xxx,yyy"/>
和 <dubbo:service filter="aaa,bbb" />
,则 xxx
,yyy
,aaa
,bbb
均会生效。如果要覆盖,需配置:<dubbo:service filter="-xxx,-yyy,aaa,bbb" />