使用自定义hk2 InjectionResolver注入应用程序配置

时间:2014-10-15 15:12:39

标签: java dependency-injection jersey-2.0 hk2

my previous question的后续行动。我正在尝试使用JSR-330标准注释和与泽西捆绑的HK2框架注入应用程序配置数据。

理想情况下,我想为InjectionResolver注释创建自定义Named,该注释将在我将填充的MapProperties对象中查找所需的值从其他地方的数据读在我的第一次尝试中,我创建了一个Application实例,如

public class MyApplication extends ResourceConfig {
    ...
    packages(MY_PACKAGES);
    property(MY_CONFIG_PROPERTY, someValue);
    register(new AbstractBinder() {
        @Override
        protected void configure() {
            bind(ConfigurationInjectionResolver.class)
            .to(new TypeLiteral<InjectionResolver<Named>>(){})
            .in(Singleton.class)
        }
    });
}

然后我的InjectionResolver看起来像

public class ConfigurationInjectionResolver implements InjectionResolver<Named> {
    @Context Application application;

    @Override
    public Object resolve(Injectee injectee, ServiceHandle<?> serviceHandle) {
        // lookup data in application.getProperties();
    }
}

我的问题是application.getProperties()是空的。知道什么是错的吗?另外,我可以绑定我的Injector实例而不是绑定类吗?这样我就可以构造将Map数据作为参数传递的实例。

1 个答案:

答案 0 :(得分:5)

  

“我的问题是application.getProperties()是空的。知道什么是错的吗?

没有。这实际上对我来说非常好。

public class ConfigurationInjectionResolver implements InjectionResolver<Named> {  
    @Context
    Application application;

    @Override
    public Object resolve(Injectee injectee, ServiceHandle<?> root) {
        Named annotation = injectee.getParent().getAnnotation(Named.class);
        Map<String, Object> props = application.getProperties();
        String name = annotation.value();
        System.out.println(props.get(name));
        return props.get(name);
    }

    @Override
    public boolean isConstructorParameterIndicator() { return false; }
    @Override
    public boolean isMethodParameterIndicator() { return false; }  
}

@ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {

    public JerseyApplication() {
        packages("jersey.startup.test");
        property("hello.config", "Hello World Property");
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bind(ConfigurationInjectionResolver.class)
                        .to(new TypeLiteral<InjectionResolver<Named>>() {
                        }).in(Singleton.class);
            }
        });
    }
}

资源

@Path("/config")
public class ConfigResource {

    @Named("hello.config")
    String hello;

    @GET
    public Response getHello() {
        return Response.ok(hello).build();
    }
}
  

C:\>curl http://localhost:8080/test/rest/config
  Hello World Property

就个人而言,在这种情况下,我会创建自己的注释,以便不覆盖@Named注释的任何现有功能。


另一个很酷的选择

HK2有一个配置扩展,您可以从Properties文件加载.properties对象,并使用@Configured注释自动注入这些属性。我找不到任何关于此的文档,但在HK2 source code examples中有一个示例用法。

这是一个示例实现

必需的依赖项。检查泽西岛版本,看看它依赖的HK2版本。在我的情况下,泽西岛2.13使用HK2 2.3.0-b10,因此应该是${hk2.version}

<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-configuration-hub</artifactId>
    <version>${hk2.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-configuration-integration</artifactId>
    <version>${hk2.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-property-file</artifactId>
    <version>${hk2.version}</version>
</dependency>

App config

@ApplicationPath("/rest")
public class JerseyApplication extends ResourceConfig {

    @Inject
    public JerseyApplication(ServiceLocator locator) {
        packages("jersey.startup.test");
        ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);
        try {
            loadConfigurationProperties(locator);
        } catch (IOException ex) {
            Logger.getLogger(JerseyApplication.class.getName())
                                   .log(Level.SEVERE, null, ex);
        }
    }

    private void loadConfigurationProperties(ServiceLocator locator) 
                                                 throws IOException {
        ConfigurationUtilities.enableConfigurationSystem(locator);
        PropertyFileUtilities.enablePropertyFileService(locator);
        PropertyFileService propertyFileService 
                = locator.getService(PropertyFileService.class);
        Properties props = new Properties();
        URL url = getClass().getResource("/configuration.properties");
        props.load(url.openStream());
        PropertyFileHandle propertyFileHandle 
                = propertyFileService.createPropertyHandleOfAnyType();
        propertyFileHandle.readProperties(props);
    }
}

configuration.properties

AppConfiguration.App.hello=Hello Squirrel Property!

资源

@Path("/config")
@ConfiguredBy("AppConfiguration")
public class ConfigResource {

    @Configured
    String hello;

    @GET
    public Response getHello() {
        return Response.ok(hello).build();
    }
}
  

C:\>curl http://localhost:8080/test/rest/config
  Hello Squirrel Property!

Diclaimer:由于此功能没有详细记录,我不确定我是否在这方面做得很好。只是通过反复试验。比如这个

ServiceLocatorUtilities.addClasses(locator, ConfigResource.class);

我觉得不应该是必要的。这似乎是多余的,因为我已经是打包扫描。因此,将ConfigResource显式添加到定位器上下文对我来说似乎并不合适。