泽西2 + HK2 – 自动绑定classess

继续主题泽西2 + HK2 – @ApplicationScoped无效 。

我已经知道了,如何绑定类以便@Inject正确。

你有任何想法,如何自动化这个过程? 将所有单个服务放在bind语句中似乎在我的应用程序中非常难闻。

在使用Google的Guice多年后,我习惯于使用Just-In-Time绑定器,允许注入任意类型而无需任何前期配置。

我也发现必须明确地将每个服务绑定为一个糟糕的代码气味的想法。 我也没有为使用特殊构建步骤和添加的populator初始化代码的需要而疯狂。

所以我提出了以下JustInTimeResolver实现:

 /** * Mimic GUICE's ability to satisfy injection points automatically, * without needing to explicitly bind every class, and without needing * to add an extra build step. */ @Service public class JustInTimeServiceResolver implements JustInTimeInjectionResolver { @Inject private ServiceLocator serviceLocator; @Override public boolean justInTimeResolution( Injectee injectee ) { final Type requiredType = injectee.getRequiredType(); if ( injectee.getRequiredQualifiers().isEmpty() && requiredType instanceof Class ) { final Class requiredClass = (Class) requiredType; // IMPORTANT: check the package name, so we don't accidentally preempt other framework JIT resolvers if ( requiredClass.getName().startsWith( "com.fastmodel" )) { final List> descriptors = ServiceLocatorUtilities.addClasses( serviceLocator, requiredClass ); if ( !descriptors.isEmpty() ) { return true; } } } return false; } } 

在我的项目中,我只是在Jersey应用程序配置中将以下内容添加到我的活页夹中:

 bind( JustInTimeServiceResolver.class ).to( JustInTimeInjectionResolver.class ); 

我像Guice那样得到自动绑定创建。

我建议先看这里: 自动服务人口 。

基本过程是在类上使用@Service注释,并在构建时使用JSR-269(APT)处理器( 元数据生成器 )。 这样做会在jar文件中添加一些元数据(通常在META-INF / hk2-locator / default下)。

然后,您可以确保自动获取这些服务,而不是通过使用从每个ServiceLocator中提供的动态配置服务获得的Populator来完成所有这些令人讨厌的绑定。

伪代码将是这样的:

 public void populate(ServiceLocator locator) throws Exception { DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class); Populator populator = dcs.getPopulator(); populator.populate(new ClasspathDescriptorFileFinder(getClass().getClassLoader())); } 

在上面的代码中,ClasspathDescriptorFileFinder用于搜索类路径以查找元数据。 其他策略可以在OSGi等环境中使用。

IMO这是一种更好的方式来添加服务,而不是自己做所有的绑定。

我有一个解决我的问题的消化,我尝试过提出的解决方案而不是在这里工作。 在我的解决方案中,必须使用@MyInjectable注释来注释每个类。

1 – 创建注释

 @Retention(RUNTIME) @Target(ElementType.TYPE) public @interface MyInjectable { } 

2 – 创建AbstractBinder实现

 public class MyApplicationBinder extends AbstractBinder { @Override protected void configure() { bindFactory(EMFFactory.class).to(EntityManagerFactory.class).in(Singleton.class); bindFactory(EMFactory.class).to(EntityManager.class).in(RequestScoped.class); bind(Environment.class).to(Environment.class); scanAndBind("com.yourpackage.here"); } private void scanAndBind(String packageName) { try { Class[] classes = getClasses(packageName); for (Class klazz: classes) { MyInjectable annotation = klazz.getAnnotation(MyInjectable.class); if (annotation!= null) { bind(klazz).to(klazz); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static Class[] getClasses(String packageName) throws ClassNotFoundException, IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; String path = packageName.replace('.', '/'); Enumeration resources = classLoader.getResources(path); List dirs = new ArrayList<>(); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); dirs.add(new File(resource.getFile())); } ArrayList classes = new ArrayList(); for (File directory : dirs) { classes.addAll(findClasses(directory, packageName)); } return classes.toArray(new Class[classes.size()]); } private static List findClasses(File directory, String packageName) throws ClassNotFoundException { List classes = new ArrayList(); if (!directory.exists()) { return classes; } File[] files = directory.listFiles(); for (File file : files) { if (file.isDirectory()) { assert !file.getName().contains("."); classes.addAll(findClasses(file, packageName + "." + file.getName())); } else if (file.getName().endsWith(".class")) { classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6))); } } return classes; } } 

3 – 创建ResourceConfig

 public class MyApplication extends ResourceConfig { @Inject public MyApplication(ServiceLocator locator) { ServiceLocatorUtilities.enableImmediateScope(locator); .... register(new MyApplicationBinder()); } } 

4 – 在web.xml中正确配置

  Jersey Web Application org.glassfish.jersey.servlet.ServletContainer  jersey.config.server.provider.packages br.com.solutiontrue.ws   com.sun.jersey.api.json.POJOMappingFeature true   javax.ws.rs.Application your.package.name.MyApplication   jersey.config.server.resource.validation.disable true  1