对命名字符串字段进行Guice注入

时间:2012-05-31 17:25:42

标签: java dependency-injection guice

我有一个班级:

public class FizzBuzz {
    @Named("Red") private String redService;

    public static void main(String[] args) {
        GuiceTest testApp = new GuiceTest();

        testApp.run();
    }

    private void run() {
        Injector inj = Guice.createInjector(new MyModule());

        redService = (String)inj.getInstance(String.class);

        // Should print "red-service" but is instead an empty string!
        System.out.println("redService = " + redService);
    }

    // ... Rest of class omitted for brevity
}

public class MyModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(String.class).annotatedWith(Names.named("Red")).toInstance("red-service");
    }
}

在我的模块中,我指示Guice将所有String.class实例@Named“Red”绑定到字符串实例“red-service”,但是我没有在输出的print语句中看到它。我如何错误地使用Guice?

3 个答案:

答案 0 :(得分:22)

让我简单总结一下这里已经提出的一些意见......

  1. 您忘记了@Inject注释
  2. 我强烈建议将Guice / Injector留在FizzFuzz之外。使用静态main方法引导您的应用程序(不是run())。
  3. 可以通过bindConstant轻松地将字符串绑定到常量。
  4. 这会带给你类似的东西:

    public class FizzFuzz {
        @Inject
        @Named("red")
        private String service;
    
        public static void main(String[] args) {
            FizzFuzz fizzFuzz = Guice.createInjector(new AbstractModule() {
                @Override
                protected void configure() {
                    bindConstant().annotatedWith(Names.named("red")).to("red-service");
                }    
            }).getInstance(FizzFuzz.class);
    
            System.out.println(fizzFuzz.service);
        }
    }
    

答案 1 :(得分:4)

您在@Inject之前忘记了@Named("Red")。 使用bindConstant()也可以解决这些问题。

P.S。你为什么从inj而不是String收到FizzBuzz

答案 2 :(得分:2)

我的方式应该更漂亮。
首先创建注释

@Retention(RetentionPolicy.RUNTIME)
public @interface InjectSetting {
     String value();
}

创建你的guice模块

@Slf4j
public class SettingModule extends AbstractModule {
    private final Properties properties;

    private SettingModule(Properties properties) {
        this.properties = properties;
    }

    @Override
    protected void configure() {
        binder().bindListener(Matchers.any(), listener(((type, encounter) -> {
            for (Field field : type.getRawType().getDeclaredFields()) {
                if (field.isAnnotationPresent(InjectSetting.class)) {
                    field.setAccessible(true);

                    encounter.register(injector(instance -> {
                        try {
                            Object value = properties.get(
                                    field.getAnnotation(InjectSetting.class).value());

                            field.set(instance, parse(value, field));
                        } catch (IllegalAccessException e) {
                            binder().addError(e);
                        }
                    }));
                }
            }
        })));
    }

    TypeListener listener(BiConsumer<TypeLiteral<?>, TypeEncounter<?>> consumer) {
        return consumer::accept;
    }

    MembersInjector<Object> injector(Consumer<Object> consumer) {
        return consumer::accept;
    }

    Object parse(Object value, Field field) {
        Type type = field.getType();

        if(type == boolean.class)
            value = Boolean.parseBoolean(value.toString());
        else if(type == int.class)
            value = Integer.parseInt(value.toString());

        return value;
    }

    public static Module of(String propertiesPath, String... more) {
        Properties properties = new Properties();

        try {
            properties.load(Files.newInputStream(Paths.get(propertiesPath, more)));
        } catch(Exception e) {
            log.error("can't load config file {}", propertiesPath);
            throw new RuntimeException(e);
        }

        return new SettingModule(properties);
    }
}

然后注入你的领域

@InjectSetting("database.port")
private int port;