ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Solon 的过滤器 Filter 和两种拦截器 Handler、 Interceptor

2021-05-17 11:01:34  阅读:191  来源: 互联网

标签:拦截器 Solon void class Handler 拦截 public


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

附:项目地址

附:入门示例

标签:拦截器,Solon,void,class,Handler,拦截,public
来源: https://www.cnblogs.com/noear/p/14776078.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有