我希望在java EE中的请求的整个生命周期中都有一个变量。 例如,它可以用于日志记录功能,以便我可以按请求过滤所有日志条目。
我想要了解的关键部分是它必须相对容易在现有的应用程序中实现,因此如果可能的话,某种依赖注入会获得与特定请求相关的变量。
我尝试过注入一个@RequestScoped
变量,但它不起作用,因为它只限于容器。我需要能够将相同的对象注入不同的容器。这是可能吗?
编辑:我想要的是:
@RequestScoped
public class RequestVariables {
public String id;
}
@Stateless
public class Logger {
@Inject
private RequestVariables requestVariables;
public void log(String message) {
System.out.println(requestVariables.id + ":" + message);
}
}
@Stateless
public class Service {
@Inject
private Logger logger;
@Inject
private RequestVariables requestVariables;
public void save(String data) {
logger.log("Save");
session.save(data + requestVariables.id); //Maybe add request parameter to save aswell
}
}
public class API {
@Inject
private Service service;
@Inject
private Logger logger;
@Inject
private RequestVariables requestVariables;
@Path("/1")
@GET
public Response get(@QueryParam("data") String data) {
requestVariables.id = UUID.randomUUID().toString()
service.save(data);
logger.log("Get");
return Response.status(204).build();
}
}
目前这是我的实验:
@RequestScoped
public class RequestScope {
private int test = 0;
public RequestScope(int test) {
this.test = test;
}
public RequestScope(){}
public int getTest() {
return test;
}
public void setTest(int test) {
this.test = test;
}
}
@Provider
public class RequestScopeFilter implements ContainerRequestFilter {
@Inject
private javax.inject.Provider<RequestScope> requestScopeProvider;
@Context
private HttpServletRequest request;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestScopeProvider.get().setTest(42);
request.setAttribute("test", "superTest");
}
}
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
@TransactionAttribute(value=TransactionAttributeType.NOT_SUPPORTED)
public class Service {
@Context
private HttpServletRequest httpServletRequest;
@Inject
private Provider<RequestScope> requestScopeProvider;
public void test() {
RequestScope scope = requestScopeProvider.get();
String test = (String)httpServletRequest.getAttribute("test");
}
}
所以当我从我的服务中获取范围时,它是一个新的对象,test
设置为0,然后它会抛出一个NPE,因为httpServletRequest
为空
答案 0 :(得分:1)
选项#1
实现拦截器并将请求ID设置为HttpServletRequest
属性:
@AroundInvoke
public Object setRequestId(InvocationContext ic) throws Exception {
HttpServletRequest request = [..] // getHttpServletRequest(ic);
request.setAttribute("request-id", UUID.randomUUID().toString());
return ic.proceed();
}
然后在您需要的任何地方使用HttpServletRequest
@Context
private HttpServletRequest httpRequest;
选项#2
如果只想按唯一ID过滤日志,可以配置Logger来打印线程名称:[%t]
选项#3
使用自定义java bean封装请求数据(查询参数,请求ID等),并将此bean传递给您的应用程序服务。
public class API {
@Inject
private Service service;
@Path("/1")
@GET
public Response get(MyCustomRequestBean data) {
service.doSomejob(data);
return Response.status(204).build();
}
}
在ParamConverter
:
Jax-RS ParamConverter - ParamConverterProvider method return type mismatch
答案 1 :(得分:0)
您可以在服务中注入提供者:
@Inject
Provider<RequestVariables> vars
然后调用get()来获取实例。如果您尝试在请求范围上下文之外的线程中获取(),您将获得异常。然而,我会尝试以不允许这种情况发生的方式构建
答案 2 :(得分:0)
我发现的解决方案是使用ThreadLocal变量。它似乎相当脏,但它的工作原理是每个请求都在它自己的线程上执行(据我所知)。所以这就是我得到的:
UITableview
如果需要的话,我也可以轻松地交换let height : CGFloat = CGFloat((self.transactionArr.count*60)+70)
let width = self.view.frame.size.width*2
self.tblWidth.constant = self.view.frame.size.width
self.view.updateConstraintsIfNeeded()
self.tableView.contentSize = CGSize(width: width, height: height)
以返回更具体的内容。
我可以从几乎任何地方获取变量,假设请求没有启动不同的线程