公司用play2.26架构微服务,底层实现权限登陆控制各接口验参功能
其中拦截器是用继承下面这个类来实现的
public abstract class Action<T> extends Results
{
public T configuration;
public Action<?> delegate;
public abstract F.Promise<SimpleResult> call(Http.Context paramContext)
throws Throwable;
public static abstract class Simple extends Action<Void>
{
}
}
@With(CheckAction.class)
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
String token() default "token";
/**
* 需要检查的接口参数名
* @return
*/
String[] args() default {};
/**
* 该接口是否需要进行权限检查
* @return
*/
boolean authCheck() default false;
boolean transactional() default false;
}
public class CheckAction extends Action<Check> {
private static ThreadLocal<UserToken> tl = new ThreadLocal<UserToken>();
private static ThreadLocal<String> tl2 = new ThreadLocal<String>();
@Override
public Promise<SimpleResult> call(Context ctx) throws Throwable {
String tokenParam = configuration.token();
String token = null;
String[] args = configuration.args(); //注意这里的configuration就是并发点,这里导致拿注解上的参数有误
return this.delegate.call(ctx); //注意这里的delegate也是并发点,这导致直接请求错误,即a请求到这时有可能已经变成b请求的delegate,这样一回调导致数据直接返回给b请求了
解决方法,先调试发现这个类始终只有一个,即是单例模式
经过排查发现在这个全局类里
public class AppBootstrap extends GlobalSettings
@Override
public <A> A getControllerInstance(Class<A> clazz) throws Exception {
/*String name = clazz.getName();
Object o = map.get(name);
if(o==null){
o = clazz.newInstance();
map.put(name, o);
}
return (A) o;*/
//这个东西搞死人了,这里不能用单例,不然CheckAction 里的configuration和delegate 会出现并发
return (A)clazz.newInstance();
}
有上面这个方法 调试发现这里用map实现了个单例。。。。。
去掉单例模式即解决