Google Guice-如何自动添加绑定 [英] Google Guice - how to automatically add binding

查看:64
本文介绍了Google Guice-如何自动添加绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中,我正在使用 Google Guice 进行依赖项注入.在扩展Google Guice的AbstactModule的Module类中,我有一个MapBinder,其中的键是项目的名称,值是我的Item接口的实现(例如FirstItem).

In my project I am using Google Guice for dependency injection. In my Module class which extends Google Guice's AbstactModule I have a MapBinder, where the key is a name of an item and the value is an implementation of my Item interface (e.g. FirstItem).

MapBinder<String, Item> itemMapBinder = MapBinder.newMapBinder(binder(), String.class, Item.class);
itemMapBinder.addBinding("FirstItem").to(FirstItem.class);

当前,每次我添加Item的新实现(例如SecondItem)时,我还必须向Module添加新行,例如

Currently every time I add new implementation of Item (e.g. SecondItem) I also have to add a new line to Module, e.g.

itemMapBinder.addBinding("SecondItem").to(SecondItem.class);

我在我的ItemFactory中使用了这张物品地图.

I am using this map of items in my ItemFactory.

public class ItemFactoryImpl implements ItemFactory {

    private final Map<String, Item> items;

    @Inject
    public ItemFactoryImpl(Map<String, Item> items) {
        this.items = items;
    }

    @Override
    public Item getItem(String name) {
        if (name == null) throw new IllegalArgumentException("Name cannot be null");
        return items.get(name);
    }
}

我正在尝试找到一种方法,该方法如何自动为Item接口的新实现添加绑定.我的想法是使用自定义注释,该注释将被添加到Item接口的新实现中,并以某种方式修改Module#configure来添加具有该自定义注释的所有类的绑定.我完成了这样的事情:

I was trying to find a way how to automatically add binding for a new implementation of Item interface. My idea was use a custom annotation which will be added to new implementation of Item interface and modify Module#configure somehow to add binding for all classes with this custom annotation. I finished with something like this:

// cz.milanhlinak.guiceautobinding.item.AutoBindableItem.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoBindableItem {
}

// cz.milanhlinak.guiceautobinding.item.Item.java
public interface Item {
}

// cz.milanhlinak.guiceautobinding.item.SecondItem.java
@AutoBindableItem
public class SecondItem implements Item {
}

// cz.milanhlinak.guiceautobinding.Module.java
public class Module extends AbstractModule {

    @Override
    protected void configure() {

        MapBinder<String, Item> itemMapBinder = MapBinder.newMapBinder(binder(), String.class, Item.class);
        new Reflections("cz.milanhlinak.guiceautobinding.item")
            .getTypesAnnotatedWith(AutoBindableItem.class)
            .stream()
            .filter(Item.class::isAssignableFrom)
            .forEach(typeAnnotatedWith -> itemMapBinder
                    .addBinding(typeAnnotatedWith.getSimpleName())
                    .to((Class<? extends Item>) typeAnnotatedWith)
            );

        bind(ItemFactory.class).to(ItemFactoryImpl.class).in(Singleton.class);
    }
}

完整的代码可在我的 GitHub存储库中找到.

Full code is available in my GitHub repository.

我想知道是否有更好的方法来实现与Google Guice的自动绑定,因为如您所见,我当前正在使用一个附加库-

I would like to know if there is a better way how to achieve the automatic binding with Google Guice, because as you can see, I am currently using an additional library - Reflections.

更新

另一个选择可能是使用 Google Guava 而不是

Another option might be using of Google Guava instead of Reflections

public class Module extends AbstractModule {

    @Override
    protected void configure() {

        MapBinder<String, Item> itemMapBinder = MapBinder.newMapBinder(binder(), String.class, Item.class);

        ClassPath classPath;
        try {
            classPath = ClassPath.from(Thread.currentThread().getContextClassLoader());
        } catch (IOException e) {
            throw new RuntimeException("Unable to read class path resources", e);
        }

        ImmutableSet<ClassPath.ClassInfo> topLevelClasses = classPath.getTopLevelClassesRecursive("cz.milanhlinak.guiceautobinding.item");
        topLevelClasses.stream()
                .map(ClassPath.ClassInfo::load)
                .filter(clazz -> clazz.isAnnotationPresent(AutoBindableItem.class) && Item.class.isAssignableFrom(clazz))
                .forEach(clazz -> itemMapBinder
                        .addBinding(clazz.getSimpleName())
                        .to((Class<? extends Item>) clazz));

        bind(ItemFactory.class).to(ItemFactoryImpl.class).in(Singleton.class);
    }
}

推荐答案

您没有做错任何事情.

使用Reflections没有任何问题.该工具非常出色,可以完成您想要的工作.

You're not doing anything wrong.

There is nothing wrong with using Reflections. That tool is excellent and does the job that you want.

Guice没有发现工具,因此没有默认"方式只能在Guice中执行您想要的操作.

Guice has no discovery tool, so there is no "default" way to do what you want in Guice only.

如果要使用除Reflections之外的其他功能,则可以使用 java.util.ServiceLoader ,但是 ServiceLoader 并不是真正的Guice友好型,因为它会自动创建实例,但是您通常使用Guice是因为您希望它为您创建实例,而不是让另一个框架为您做实例.

If you want to use something else than Reflections, you can fall back on java.util.ServiceLoader, but ServiceLoader is not really Guice-friendly because it automatically creates instances, but you usually use Guice because you want it to create instances for you instead of letting another framework do that for you.

使用Guava的 Classpath 的替代方法也很有意义,但是Reflections功能更强大,因为您还可以加载不在类路径中的类.

The alternative of using Guava's Classpath also makes sense, but Reflections is way more powerful because you can also load classes not in your class path.

最重要的是,您已经做出了更好的选择.

Bottom line, you've already made the better choice.

这篇关于Google Guice-如何自动添加绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆