定义控制层拦截器@Before时,如何传入参数

如下的拦截器:TestInterceptor

public class TestInterceptor implements Interceptor {

    private TestServiceInterface testService;
    
    //带参构造方法,传入相应的服务对象
    public TestInterceptor(TestServiceInterface service){
        this.testService = service;
    }
    
    public void intercept(Invocation inv) {
        //执行逻辑处理
        service.dosomething("...");
        
        //调用目标方法
        inv.invoke();
    }

}


这个拦截器很简单,就是增加了一个接口类型的带参实例方法,目的是通过传入的服务对象在拦截器内部进行可定制的逻辑处理,这样的话,不同项目中,相同功能的拦截器可以剥离出来,只需要在实例化时注入服务对象就可以了

我已经在项目中这么用了,只是以前都是定义成全局控制器:

public void configInterceptor(Interceptors me) {
    me.add(new TestInterceptor(new UserService()));
}


现在需要定义成Class级控制器,利用@Before时,发现无法给拦截器传入参数。

分析JFinal初始化拦截器的源码:InterceptorManager.class 154行

public Interceptor[] createInterceptor(Class<? extends Interceptor>[] interceptorClasses) {
    if (interceptorClasses == null || interceptorClasses.length == 0) {
        return NULL_INTERS;
    }
    
    Interceptor[] result = new Interceptor[interceptorClasses.length];
    try {
        for (int i=0; i<result.length; i++) {
            result[i] = singletonMap.get(interceptorClasses[i]);
            if (result[i] == null) {
                result[i] = (Interceptor)interceptorClasses[i].newInstance();
                singletonMap.put(interceptorClasses[i], result[i]);
            }
        }
        return result;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

发现没办法对带参的拦截器进行反射

也没办法重写这个InterceptorManager

遇到障碍了,还请 @JFinal 指点

评论区

netwild

2017-04-13 10:38

实在不行就只能定义一个服务工厂类,用于接收拦截器中需要用到的各种服务对象,等待更好的办法。

JFinal

2017-04-13 11:21

办法有很多,这里只说三种:
1:创建该拦截器的一个继承类,在构造方法中直接 new UserService() 给它用

2:自定义一个注解,让这个注解可以接收一个 class 形参数,例如创建一个名为ConfigService的注解:
@ConfigService(UserService.class)
然后在你的那个 TestInterceptor 中通过下面的方法创建:
Class serviceClass = inv.getMethod.getAnnotation(ConfigService.class).value();
然后再创建这个业务类对象:
serviceClass.newInstance();
打完收枪

3:还可通过 url 或者 setAttr 或者 threadlocal 来传个参到拦截器,拦截器再做出判断

netwild

2017-04-13 13:16

@JFinal 还是第一种比较好,把拦截器做成抽象类,为子类开放一个服务对象的set方法。
这样子类拦截器即可以做全局,也能Before。
思路有时候就是转不过弯,感谢詹老大的提醒!
现在对jfinal越来越上瘾,最舒服的就是jfinal为二开提供了广阔的空间,各种重载和接口,这种自由的感觉不是一般的爽!更是从jfinal的源码里学到了框架层面的开发技巧,再次感谢詹总!

热门反馈

扫码入社