zoukankan      html  css  js  c++  java
  • Solon 的过滤器 Filter 和两种拦截器 Handler、 Interceptor

    在web开发中,过滤器、拦截器是经常用到的功能。它可以帮我们限制流量、验证是否登陆、记录日志以及统计执行效率等等。

    今天主要交流一下 Solon 框架中的过滤器和拦截器。

    Solon 是什么框架?

    Solon 是一个插件式的 Java 微型开发框架。强调,克制 + 简洁 + 开放的原则;力求,更小、更快、更自由的体验。支持:RPC、REST API、 MVC、Micro service、WebSocket、Socket 等多种开发模式。

    一、Solon 的过滤器

    Solon 是一个 Servelt 无关的开发框架,所以有自己专属的 Filter,但与 Servelt 的 Filter 功能相差不大。另外,Solon 是一个多信号源的开发框架,所以 Filter 对 Http、Socket、WebSocket 的请求信号统统有效。

    //接口代码
    @FunctionalInterface
    public interface Filter {
        void doFilter(Context ctx, FilterChain chain) throws Throwable;
    }
    

    Solon Filter 是最根级的、最粗颗料度的过滤手段。它不能选择路径过滤,只能对所有的请求进行过滤。如果需要仅对某路径处理,需要代码内控制,这是与 Servelt Filter 的一大区别。

    一个限流的示例:
    public class DemoApp{
        public static void main(String[] args){
            SolonApp app = Solon.start(DemoApp.class, args);
            
           app.filter((ctx, chain)->{
                try(AutoCloseable entry = Limiter.entry()){
                    chain.doFilter(ctx);
                }catch (Exception e){
                    ctx.output("服务器有点忙,请稍后再试");
                }
            });
        }
    }
    
    也可以用组件的形式申明:
    @Component
    public class BreakerFilter implements Filter {
        @Override
        public void doFilter(Context ctx, FilterChain chain) throws Throwable {
            try(AutoCloseable entry = Limiter.entry()){
                chain.doFilter(ctx);
            }catch (Exception e){
                ctx.output("服务器有点忙,请稍后再试");
            }
        }
    }
    

    Solon Filter 绝大部份的工作,都可以由 Solon 拦截器 Handler 完成。

    二、Solon 的拦截器

    Solon 中拦截器分为两种。一是 Handler,争对请求地址与上下文对象的拦截;一是 Interceptor,对 Bean 的 Method 进行拦截。

    1、Handler(Context 拦截器)

    Solon 对web请求处理的本质,即是对 Context 的一路拦截处理并最终输出。这一路的拦截处理可称之为拦截链,拦截链上每个处理节点,即为 Context 拦截器,每个拦截器即为 Handler 。

    //接口代码
    @FunctionalInterface
    public interface Handler {
        void handle(Context context) throws Throwable;
    }
    

    Handler 在顺位上可分为:前置拦截器(可以多个)、中置拦截器(最多一个)、后置拦截器(可以多个),提供了三段拦截能力。在使用上又有三种模式可选,具体如下代码:

    使用模式一:纯手写模式(这种模式,可以偷偷为控制器加点东西)
    public class DemoApp{
        public static void main(String[] args){
            SolonApp app = Solon.start(DemoApp.class, args);
            
            //中置拦截处理
            app.get("/hello",c->c.output("Hello world!"));
            
            
            
            //前置拦截处理(验证Token)
            app.before("/hello",c->{
                if(c.header("Token") == null){
                    //如果没有Token则中止后续处理
                    c.setHandled(true);
                }
            });
    
            //前置拦截处理(记录Log)-- 拦截链,可以形成一种"装配"的感觉
            app.before("/hello",c->{
                System.out.println("记录日志");
            });
    
            //后前置拦截处理
            app.after("/hello",c->{
                System.out.println("记录时间消耗");
            });
        }
    }
    
    使用模式二:控制器编写模式(这种模式比较有透明度,自己给自己加点料)
    @Controller
    public class DemoController {
    
        //前置拦截处理(验证Token)
        @Mapping(value = "hello", before = true)
        public void helloBef1(Context c) {
            if (c.header("Token") == null) {
                //如果没有Token则中止后续处理
                c.setHandled(true);
            }
        }
    
        //前置拦截处理(记录Log)
        @Mapping(value = "hello", before = true)
        public void helloBef2(Context c) {
            System.out.println("记录日志");
        }
    
        //中置拦截处理
        @Get
        @Mapping("hello")
        public String hello() {
            return "Hello world!";
        }
    
        //后前置拦截处理
        @Mapping(value = "hello", after = true)
        public void helloAft1(Context c) {
            System.out.println("记录时间消耗");
        }
    }
    
    使用模式三:注解模式(通过:@Before、@After 注解附加;这种模式比较有装配感)
    //
    //1. 三个拦截处理
    //
    public class HelloBef1Handler implements Handler {
        @Override
        public void handle(Context c) throws Throwable {
            if (c.header("Token") == null) {
                //如果没有Token则中止后续处理
                c.setHandled(true);
            }
        }
    }
    
    public class HelloBef1Handler implements Handler {
        @Override
        public void handle(Context c) throws Throwable {
            if (c.header("Token") == null) {
                //如果没有Token则中止后续处理
                c.setHandled(true);
            }
        }
    }
    
    public class HelloBef2Handler implements Handler {
        @Override
        public void handle(Context c) throws Throwable {
            System.out.println("记录日志");
        }
    }
    
    //
    // 2.通过注解,附加在Action上
    //
    @Controller
    public class DemoController {
        //此注入,也可附加在控制器类上
        @After({HelloAft1Handler.class})
        @Before({HelloBef1Handler.class, HelloBef2Handler.class})
        @Get
        @Mapping("hello")
        public String hello() {
            return "Hello world!";
        }
    }
    
    

    2、Interceptor(Method 拦截器)

    Interceptor 拦截的目标是方法,所以被代理的 Bean Method。

    //接口代码
    @FunctionalInterface
    public interface Interceptor {
        Object doIntercept(Invocation inv) throws Throwable;
    }
    

    Interceptor 同样有三种使用模式。

    使用模式一:手写模式
    //定义一个拦截器
    public class TranInterceptor implements Interceptor {
        @Override
        public Object doIntercept(Invocation inv) throws Throwable{
            ValHolder val0 = new ValHolder();
    
            Tran anno = inv.method().getAnnotation(Tran.class);
            TranExecutorImp.global.execute(anno, () -> {
                val0.value = inv.invoke();
            });
    
            return val0.value;
        }
    }
    
    //定义一个注解
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Tran {
    }
    
    //注册一个环境处理到Aop容器
    Aop.context().beanAroundAdd(Tran.class, new TranInterceptor(), 120);
    
    //使用
    @Service
    public class UserService{
        //通过@Tran,实现拦截并添加事务支持
        @Tran
        public void addUser(User user){
            userMapper.insert(user);
        }
    }
    
    使用模式二:通过注解桥接模式(通过:@Around 注解桥接一个拦截器)
    //定义一个拦截器
    public class TranInterceptor implements Interceptor {
        @Override
        public Object doIntercept(Invocation inv) throws Throwable{
            ValHolder val0 = new ValHolder();
    
            Tran anno = inv.method().getAnnotation(Tran.class);
            TranExecutorImp.global.execute(anno, () -> {
                val0.value = inv.invoke();
            });
    
            return val0.value;
        }
    }
    
    //定义一个注解(通过@Aroud 关联一个拦截器)
    @Around(value = TranInterceptor.class, index = 120))
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Tran {
    }
    
    //使用
    @Service
    public class UserService{
        //通过@Tran,实现拦截并添加事务支持
        @Tran
        public void addUser(User user){
            userMapper.insert(user);
        }
    }
    
    使用模式三:直接注解模式(通过:@Around 注解直接申明拦截器)
    //定义一个拦截器
    public class TranInterceptor implements Interceptor {
        @Override
        public Object doIntercept(Invocation inv) throws Throwable{
            ValHolder val0 = new ValHolder();
    
            Tran anno = inv.method().getAnnotation(Tran.class);
            TranExecutorImp.global.execute(anno, () -> {
                val0.value = inv.invoke();
            });
    
            return val0.value;
        }
    }
    
    //使用
    @Service
    public class UserService{
        @Around(value = TranInterceptor.class, index = 120))
        public void addUser(User user){
            userMapper.insert(user);
        }
    }
    

    附:项目地址

    附:入门示例

  • 相关阅读:
    Ubuntu adb devices :???????????? no permissions (verify udev rules) 解决方法
    ubuntu 关闭显示器的命令
    ubuntu android studio kvm
    ubuntu 14.04版本更改文件夹背景色为草绿色
    ubuntu 创建桌面快捷方式
    Ubuntu 如何更改用户密码
    ubuntu 14.04 返回到经典桌面方法
    ubuntu 信使(iptux) 创建桌面快捷方式
    Eclipse failed to get the required ADT version number from the sdk
    Eclipse '<>' operator is not allowed for source level below 1.7
  • 原文地址:https://www.cnblogs.com/noear/p/14776078.html
Copyright © 2011-2022 走看看