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);
    }
}

附:新项目详细地址

  • Gitee:https://gitee.com/noear/solon
  • GitHub:https://github.com/noear/solon

附:新手入门实例

  • Solon 基础教程实例:https://gitee.com/noear/solon_demo
  • Solon Rpc 基础教程实例:https://gitee.com/noear/solon_rpc_demo
  • Solon Cloud 基础教程实例:https://gitee.com/noear/solon_cloud_demo
  • Solon 升阶实例教程实例:https://gitee.com/noear/solon_advance_demo

评论(0条)

刀客源码 游客评论