我正在使用 Spring MVC,我想从请求标头中获取一些参数,并将它们存储在当前请求期间应用程序中任何位置可用的对象中。想象一个应用程序范围的元数据类。
我想避免使用 RequestContextHolder 因为控制器下面的应用程序的其他部分不应该关心这些值来自请求。它应该是可用的。
我还考虑过使用请求范围的 bean,但随后我必须将它连接到我想要使用它的任何地方。I 反对“只要有它可用”
任何关于从哪里开始的信息都会很棒。
更新:
这是我的想法。我担心当其他请求到来时,他们会设置上一个请求的transactionId。
连接请求作用域 bean:
<bean id="metaDataContextHolder" class="com.yp.common.context.MetadataContextHolder" scope="request">
<aop:scoped-proxy/>
</bean>
Run Code Online (Sandbox Code Playgroud)
这是请求作用域的 bean
public class MetadataContextHolder {
private static String transactionId;
//removed other properties for brevity
public static String getTransactionId() {
return transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
}
Run Code Online (Sandbox Code Playgroud)
捕获要存储的过滤器中的请求标头以供整个应用程序使用:
public class RequestMetatDataFilter implements Filter
{
@Autowired
MetadataContextHolder metaDataHolder;
@Override
public void init(FilterConfig arg0) throws ServletException
{
}
/**
* This filter will add common request metatdata to the MetaDataContextHolder
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filerChain) throws IOException, ServletException
{
HttpServletRequest request = ((HttpServletRequest)servletRequest);
String transactionId = request.getHeader("transactionId");
metaDataHolder.setTransactionId(transactionId);
...
//store other values
...
filerChain.doFilter(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以在任何地方访问元数据,而无需再次连接元数据 bean,如下所示:
MetaDataContextHolder.getTransactionId();
Run Code Online (Sandbox Code Playgroud)
更新2
正如我怀疑的那样,MetadataContextHolder 中的静态属性“transactionId”会根据每个请求进行更新。
有可能实现我想做的事情吗?
为了存储请求范围的对象并能够以静态方式检索它,我需要实现自己的上下文持有者并将对象存储在线程本地中。
我首先复制代码,RequestContextHolder但我使用 Metadata 类参数化我的线程本地对象。
public class MetadataContextHolder {
private static final ThreadLocal<Metadata> metadataHolder =
new NamedThreadLocal<Metadata>("Metadata Context");
private static final ThreadLocal<Metadata> inheritableMetadataHolder =
new NamedInheritableThreadLocal<Metadata>("Metadata Context");
/**
* Reset the metadata for the current thread.
*/
public static void resetMetadata() {
metadataHolder.remove();
}
/**
* Bind the given Metadata to the current thread,
* <i>not</i> exposing it as inheritable for child threads.
* @param metadata the Metadata to expose
* @see #setMetadata(Metadata, boolean)
*/
public static void setMetadata(Metadata metadata) {
setMetadata(metadata, false);
}
/**
* Bind the given Metadata to the current thread.
* @param metadata the Metadata to expose,
* or {@code null} to reset the thread-bound context
* @param inheritable whether to expose the Metadata as inheritable
* for child threads (using an {@link InheritableThreadLocal})
*/
public static void setMetadata(Metadata metadata, boolean inheritable) {
if (metadata == null) {
resetMetadata();
}
else {
if (inheritable) {
inheritableMetadataHolder.set(metadata);
metadataHolder.remove();
}
else {
metadataHolder.set(metadata);
inheritableMetadataHolder.remove();
}
}
}
/**
* Return the Metadata currently bound to the thread.
* @return the Metadata currently bound to the thread,
* or {@code null} if none bound
*/
public static Metadata getMetadata() {
Metadata metadata = metadataHolder.get();
if (metadata == null) {
metadata = inheritableMetadataHolder.get();
}
return metadata;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我创建了一个过滤器来填充元数据上下文,但这实际上可以填充在任何地方:
public class RequestMetatDataFilter implements Filter
{
@Override
public void init(FilterConfig arg0) throws ServletException
{
}
/**
* This filter will add common request metatdata to the MetadataContextHolder
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filerChain) throws IOException, ServletException
{
HttpServletRequest request = ((HttpServletRequest)servletRequest);
String transactionId = request.getHeader("transactionId");
Metadata metadata = new Metadata(transactionId);
MetadataContextHolder.setMetadata(metadata);
filerChain.doFilter(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我需要在 web.xml 中注册一个请求侦听器,以便在请求完成时清理本地线程:
<listener>
<listener-class>com.ws.listener.RequestListener</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)
最后我需要在请求侦听器中执行清理:
public class RequestListener implements ServletRequestListener {
/**
* Reset the metadata for the current request thread
*/
public void requestDestroyed(ServletRequestEvent event) {
MetadataContextHolder.resetMetadata();
}
/**
* Don't do anything when the request is initialized
*/
public void requestInitialized(ServletRequestEvent event) {
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个很好的元数据对象:
public class Metadata {
private String idTransaccion;
//Other properties removed for brevity
public Metadata(String idTransaccion) {
super();
this.idTransaccion = idTransaccion;
}
public String getIdTransaccion() {
return idTransaccion;
}
public void setIdTransaccion(String idTransaccion) {
this.idTransaccion = idTransaccion;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9125 次 |
| 最近记录: |