Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
升级到JAVA 8后tomcat错误行为的Threadlocal_Java_Spring_Tomcat_Thread Local - Fatal编程技术网

升级到JAVA 8后tomcat错误行为的Threadlocal

升级到JAVA 8后tomcat错误行为的Threadlocal,java,spring,tomcat,thread-local,Java,Spring,Tomcat,Thread Local,我使用thread local来存储用户请求特定的功能(例如浏览器代理),它在JAVA 7上正常工作,但是现在在升级到JAVA 8之后,在某些情况下,我看到来自android浏览器的请求被当作来自iOS浏览器一样处理,尽管它被正确地检测为android浏览器,但后来在处理请求时,它被另一个线程本地值替换了!我不确定我在这里遗漏了什么有人能帮我吗?我的环境设置(升级之前/之后)为: Tomcat8前后 JAVA从7升级到8 Spring从4.1.7升级到4.2.5 Spring security

我使用thread local来存储用户请求特定的功能(例如浏览器代理),它在JAVA 7上正常工作,但是现在在升级到JAVA 8之后,在某些情况下,我看到来自android浏览器的请求被当作来自iOS浏览器一样处理,尽管它被正确地检测为android浏览器,但后来在处理请求时,它被另一个线程本地值替换了!我不确定我在这里遗漏了什么有人能帮我吗?我的环境设置(升级之前/之后)为:

  • Tomcat8前后
  • JAVA从7升级到8
  • Spring从4.1.7升级到4.2.5
  • Spring security从3.2.3升级到4.03
我有一个安全过滤器,看起来像这样:

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.GenericFilterBean;

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
private final IdentityService identityService;

public AuthenticationTokenProcessingFilter(IdentityService userService) {
    this.identityService = userService;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    SecurityManager.manager().clearManager();
    HttpServletRequest httpRequest = this.getAsHttpRequest(request);
    String agent = httpRequest.getHeader("User-Agent");
    SecurityManager.manager().setAgent(agent);

    ...

    chain.doFilter(request, response);
}

}
import com.appseleon.platform.web.shared.CrossAppConstants;

public class SecurityManager {
private static SecurityManager manager;

private final ThreadLocal<String> agentContext = new ThreadLocal<String>();

private SecurityManager() {
    manager = this;
}

public void clearManager() {
    agentContext.set(null);
}

public static SecurityManager manager() {
    return manager;
}


public String getAgent() {
    String os = agentContext.get();
    if (os == null) {
        os = CrossAppConstants.DEFAULT_OS;
    }
    return os;
}

public void setAgent(String agent) {
    System.out.println("### os detected: " + agent);
    agentContext.set(agent);
}

}
安全管理器如下所示:

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.GenericFilterBean;

public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
private final IdentityService identityService;

public AuthenticationTokenProcessingFilter(IdentityService userService) {
    this.identityService = userService;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    SecurityManager.manager().clearManager();
    HttpServletRequest httpRequest = this.getAsHttpRequest(request);
    String agent = httpRequest.getHeader("User-Agent");
    SecurityManager.manager().setAgent(agent);

    ...

    chain.doFilter(request, response);
}

}
import com.appseleon.platform.web.shared.CrossAppConstants;

public class SecurityManager {
private static SecurityManager manager;

private final ThreadLocal<String> agentContext = new ThreadLocal<String>();

private SecurityManager() {
    manager = this;
}

public void clearManager() {
    agentContext.set(null);
}

public static SecurityManager manager() {
    return manager;
}


public String getAgent() {
    String os = agentContext.get();
    if (os == null) {
        os = CrossAppConstants.DEFAULT_OS;
    }
    return os;
}

public void setAgent(String agent) {
    System.out.println("### os detected: " + agent);
    agentContext.set(agent);
}

}
有谁能帮我找出这个问题的原因,或者找到一种更可靠的方法来解决这个问题


提前感谢:)

首先,您的
SecurityManager
存在缺陷。您不应该获取实例,而只需使用
static
直接获取/设置
ThreadLocal
上的值。当前,当在不同的类加载器中加载东西时,即没有检测到单例时,您可能会遇到问题

public abstract class SecurityManager {

  private static final ThreadLocal<String> agentContext = new ThreadLocal<String>();

  private SecurityManager() { }

  public static void clearManager() {
      agentContext.set(null);
  }


  public static String getAgent() {
      String os = agentContext.get();
      if (os == null) {
          os = CrossAppConstants.DEFAULT_OS;
      }
      return os;
  }

  public static void setAgent(String agent) {
      System.out.println("### os detected: " + agent);
      agentContext.set(agent);
  }

}
另外,与扩展
GenericFilterBean
不同,您可能希望扩展
OncePerRequestFilter
,以确保此功能只调用一次(如果逻辑中有一些转发,则此功能特别有用),并且它仅适用于
HttpServletRequest
类型的请求,从而为您保存一些代码

public class AuthenticationTokenProcessingFilter extends OncePerRequestFilter {
...

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse ress, FilterChain chain) throws IOException, ServletException {

        String agent = req.getHeader("User-Agent");
        SecurityManager.setAgent(agent);

        ...
        try {
            chain.doFilter(request, response);
        } finally {
            SecurityManager.clearManager();
        }
    }
}

这也是Spring安全性的工作方式,例如Spring事务管理(使用静态方法和shared
ThreadLocal

首先,您的
SecurityManager
存在缺陷。您不应该获取实例,而应该使用
static
直接获取/设置
ThreadLocal
上的值。当前,当在不同的类加载器中加载东西时,即没有检测到单例时,您可能会遇到问题

public abstract class SecurityManager {

  private static final ThreadLocal<String> agentContext = new ThreadLocal<String>();

  private SecurityManager() { }

  public static void clearManager() {
      agentContext.set(null);
  }


  public static String getAgent() {
      String os = agentContext.get();
      if (os == null) {
          os = CrossAppConstants.DEFAULT_OS;
      }
      return os;
  }

  public static void setAgent(String agent) {
      System.out.println("### os detected: " + agent);
      agentContext.set(agent);
  }

}
另外,与扩展
GenericFilterBean
不同,您可能希望扩展
OncePerRequestFilter
,以确保此功能只调用一次(如果逻辑中有一些转发,则此功能特别有用),并且它仅适用于
HttpServletRequest
类型的请求,从而为您保存一些代码

public class AuthenticationTokenProcessingFilter extends OncePerRequestFilter {
...

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse ress, FilterChain chain) throws IOException, ServletException {

        String agent = req.getHeader("User-Agent");
        SecurityManager.setAgent(agent);

        ...
        try {
            chain.doFilter(request, response);
        } finally {
            SecurityManager.clearManager();
        }
    }
}

这也是Spring安全性的工作方式,例如Spring事务管理(使用静态方法和shared
ThreadLocal

非常感谢你,我将尝试它,并张贴结果回来!我花了我的时间来测试和监控它,这个解决方案工作得很好:)谢谢!非常感谢你,我将尝试它,并张贴结果回来!我花了我的时间来测试和监控它,这个解决方案工作得很好:)谢谢!