ResourceConfig中的java依赖解析程序
在jetty/jersey2自托管应用程序中,api端点是在ApiServiceConfig类中以编程方式生成的
ConfigurationProperties
类读取属性文件并将其加载到java.util.Properties
类中
Jetty服务器实例化按以下方式完成
// Create and register resources
final ResourceConfig resourceConfig = new ApiServiceConfig()
.register(new DependencyInjectionBinder());
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/mydomain/api");
Server jettyServer = new Server(8585);
jettyServer.setHandler(contextHandler);
ServletHolder jerseyServlet = new ServletHolder(new ServletContainer(resourceConfig));
contextHandler.addServlet(jerseyServlet, "/*");
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
jettyServer.destroy();
}
public class ApiServiceConfig extends ResourceConfig {
public ApiServiceConfig() {
for(JsonNode jsonNode: nodeArray) {
// JSON endpoint service description example.
//{
// "service": "/item/{id}",
// "method": "GET",
// "process": {
// "@type": "com.mycompany.projectx.endpoint.services.GetController",
// "uri_param": "id",
// "type": "item",
// "fields": "uuid,name,content_area,title,grade,dok,bloom,item_banks,...,item_banks_titles"
// }
//}
// Json property "service" describes a URL pattern for a request (eg. "/item/{id}").
final String path = jsonNode.get("service").asText();
// Api RESTful verb ('GET', 'POST', etc.)
final String method = jsonNode.get("method").asText();
// Map a process description of a service to specific controller implementation class.
// This is the instance creation where I want injection to happen.
IController controller = this.objectMapper.convertValue(jsonNode.get("process"), AbstractBaseController.class);
// Controller is added to a HashMap
...
final Resource.Builder resourceBuilder = Resource.builder();
resourceBuilder.path(path);
final ResourceMethod.Builder methodBuilder = resourceBuilder.addMethod(method);
methodBuilder.produces(new MediaType("text", "plain"))
handledBy((Inflector)(ctx) -> {
// Controller is retrieved from the HashMap
controller.execute(new ProcessEvent());
...
return responseResult;
});
final Resource resource = resourceBuilder.build();
registerResources(resource);
}
}
}
GetController
public class GetController extends AbstractBaseController {
@Config("data.cassandra")
String connectionString; // == null, but should be a string injected.
public GetController() {
}
@Override
public ProcessEvent process(ProcessEvent event) throws Exception {
String uri_param = this.uri_param;
event.contentType = "application/json";
event.object = ".Get method of Item endpoint got executed. Cassandra IP: " + getApplicationProperties().getProperty("data.cassandra");
return event;
}
依赖项解析程序绑定器已在DependencyInjectionBinder
类中注册:
public class DependencyInjectionBinder extends AbstractBinder {
@Override
protected void configure() {
bind(ConfigInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<Config>>() {})
.in(Singleton.class);
}
}
ConfigInjectionResolver实现InjectionResolver并解析一些逻辑
循环中的ApiServiceConfig
遍历描述并创建端点。为每个端点创建、填充资源生成器并注册资源。在创建端点资源的过程中,会在jackson databind的帮助下实例化一个类:
IController controller = this.objectMapper.convertValue(jsonNode.get("process"), AbstractBaseController.class);
这门课应该再注射一门课。创建controller
实例时,解析程序依赖注入绑定器未启动。
如果我将DependencyInjectionBinder实例化作为第一个操作移动到ApiServiceConfiguration构造函数中,那么将属性注入到controller
实例中无论如何都不会发生
但是,当我注册一个类定义的端点时:
resourceConfig.register(AnEndpointClass.class);
DI解析器将起作用并增加依赖性
如何使依赖解析程序在以编程方式创建和注册端点的同时为实例化的类工作
# 1 楼答案
要显式地注入对象,需要获得
ServiceLocator
,并调用locator.inject(controller)
。如this post中所述,可以在Feature
中获取ServiceLocator
由于还需要使用控制器注册资源,因此还需要一种在
Feature
中注册资源的方法。为此,您可以使用ModelProcessor
。你可以在Jersey documentation中阅读更多关于它的信息。它允许你改变泽西岛的资源模型。在这里,我们可以注册所有以编程方式构建的资源下面是一个使用Jersey Test Framework的完整示例。您可以像运行任何其他JUnit测试一样运行它