简体   繁体   English

球衣2 + HK2-自动绑定课程

[英]Jersey 2 + HK2 - automatic binding of classess

Continuation of topic Jersey 2 + HK2 - @ApplicationScoped not working . 继续主题Jersey 2 + HK2-@ApplicationScoped无法正常工作

I already know, how to bind classes in order to @Inject them properly. 我已经知道,如何绑定类才能正确@Inject

Do you have any ideas, how to automize this process? 您有什么想法,如何使这一过程自动化? Putting every single service in bind statements seems like very bad smell in my application. 在我的应用程序中,将每个服务都放在bind语句中似乎很难闻。

After using Google's Guice for a number of years, I am accustomed to the availability of a Just-In-Time binder, allowing the injection of arbitrary types without requiring any upfront configuration. 在使用Google的Guice数年之后,我习惯了即时绑定器的可用性,它可以注入任意类型而无需任何前期配置。

I too found the idea of having to explicitly bind every service to be a bad code smell. 我也发现必须显式绑定每个服务的想法是一种不好的代码味道。 I'm also not crazy about the need to use a special build step and the added initialization code for the populator. 对于需要使用特殊的构建步骤以及为填充器添加的初始化代码,我也并不感到疯狂。

So I came up with the following JustInTimeResolver implementation: 因此,我提出了以下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<ActiveDescriptor<?>> descriptors = ServiceLocatorUtilities.addClasses( serviceLocator, requiredClass );

                if ( !descriptors.isEmpty() ) {
                    return true;
                }
            }
        }
        return false;
    }
} 

With this in my project, I simply added the following to my binder in my Jersey application configuration: 在我的项目中,我只是将以下内容添加到我的Jersey应用程序配置中的活页夹中:

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

and I get automatic binding creation like I did in Guice. 就像在Guice中一样,我可以自动创建绑定。

I would suggest first looking here: Automatic Service Population . 我建议首先在这里查看: 自动服务人口

The basic process is to use @Service annotations on your classes and use the JSR-269 (APT) processor ( Metadata Generator ) at build time. 基本过程是在类上使用@Service批注,并在构建时使用JSR-269(APT)处理器( Metadata Generator )。 Doing so will add some metadata to your jar files (normally under META-INF/hk2-locator/default). 这样做会将一些元数据添加到您的jar文件中(通常在META-INF / hk2-locator / default下)。

You can then make sure these services get picked up automatically rather than having to do all those pesky binds by using a Populator which you get from the Dynamic Configuration Service which is available in every ServiceLocator. 然后,您可以使用从每个ServiceLocator中可用的动态配置服务获得的Populator ,确保自动获取这些服务,而不必进行所有讨厌的绑定。

The pseudo-code would be something like this: 伪代码将如下所示:

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

In the above code the ClasspathDescriptorFileFinder is used to search through the classpath to find the metadata. 在上面的代码中,ClasspathDescriptorFileFinder用于搜索类路径以找到元数据。 Other strategies could be used in environments like OSGi. 其他策略也可以在OSGi等环境中使用。

IMO this is a much better way to add services rather than doing all the binds by yourself. IMO这是添加服务而不是自己进行所有绑定的更好的方法。

I Have a sugestion that solved my problem here, i've tried proposed solution and not worked here. 我有一个解决方案,在这里解决了我的问题,我已经尝试了建议的解决方案,但在这里没有工作。 In my solution it's necessary annotate each class with @MyInjectable annotation. 在我的解决方案中,必须使用@MyInjectable注释对每个类进行注释。

1-Create an Annotation 1-创建注释

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

2-Create a AbstractBinder implementation 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<URL> resources = classLoader.getResources(path);
        List<File> dirs = new ArrayList<>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        ArrayList<Class> classes = new ArrayList<Class>();
        for (File directory : dirs) {
            classes.addAll(findClasses(directory, packageName));
        }
        return classes.toArray(new Class[classes.size()]);
    }

    private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {
        List<Class> classes = new ArrayList<Class>();
        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-Create a ResourceConfig 3-创建一个ResourceConfig

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

4-Configure properly in web.xml 4-在web.xml中正确配置

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>br.com.solutiontrue.ws</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>your.package.name.MyApplication</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.server.resource.validation.disable</param-name>
        <param-value>true</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
</servlet>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM