问题
My overall goal is to load properties from a properties file and then inject those properties into my objects. I would also like to use those properties to instantiate certain singleton classes using Guice. My singleton class looks like this:
public class MainStore(){
private String hostname;
@Inject
public void setHostname(@Named("hostname") String hostname){
this.hostname = hostname;
}
public MainStore(){
System.out.println(hostname);
}
}
I'm trying to instantiate a singleton using this provider:
public class MainStoreProvider implements Provider<MainStore> {
@Override
public MainStore get(){
MainStore mainStore = new MainStore();
return mainStore;
}
}
My configurationModule is a module that loads a configuration from a property file specified at runtime:
public class ConfigurationModule extends AbstractModule {
@Override
protected void configure(){
Properties properties = loadProperties();
Names.bindProperties(binder(), properties);
}
private static Properties loadProperties() {
String resourceFileName = "example.properties";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(resourceFileName);
Properties properties = new Properties();
properties.load(inputStream);
return properties;
}
}
And my example.properties files contains:
hostname = testHostName
Then when I need the MainStore singleton I'm using:
Injector injector = Guice.createInjector(new ConfigurationModule());
MainStoreProvider mainStoreProvider = injector.getInstance(MainStoreProvider.class);
MainStore mainStore = mainStoreProvider.get(); //MainClass singleton
Is this the right path to go down? Should I be doing this a completely different way? Why does my MainStore not print out the correct hostname?
回答1:
I have written up a small example that demonstrates how to bind a Singleton, how to inject a property and so on.
public class TestModule extends AbstractModule {
@Override
protected void configure() {
Properties p = new Properties();
p.setProperty("my.test.string", "Some String"); // works with boolean, int, double ....
Names.bindProperties(binder(),p);
bind(X.class).to(Test.class).in(Singleton.class); // This is now a guice managed singleton
}
public interface X {
}
public static class Test implements X {
private String test;
@Inject
public Test(@Named("my.test.string") String test) {
this.test = test;
System.out.println(this.test);
}
public String getTest() {
return test;
}
}
public static void main(String[] args) {
Injector createInjector = Guice.createInjector(new TestModule());
Test instance = createInjector.getInstance(Test.class);
}
}
The configure method is now responsible to tell guice that my Test class is a singleton.
It prints the correct hostname (property test) because I inject the constructor and set the property.
You can do this with a provider as well, however you will then have to create your objects manually. In my case, this would look like this:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
public TestProvider(@Named("my.test.string") String test) {
this.test = test;
}
@Override
public X get() {
if(instance == null) {
instance = new Test(test);
}
return instance;
}
}
Binding will then look like this:
bind(X.class).toProvider(TestProvider.class);
Is this what you wanted?
Cheers,
Artur
Edit:
I did some test and found this to note:
You can bind a provider as a singleton:
bind(X.class).toProvider(TestProvider.class).in(Singleton.class);
That way you do not need to handle singleton creation yourself:
public static class TestProvider implements Provider<X> {
private String test;
private X instance;
@Inject
public TestProvider(@Named("my.test.string") String test) {
this.test = test;
}
@Override
public X get() {
return instance;
}
}
The above code will create singletons of the object X.
来源:https://stackoverflow.com/questions/38589940/how-can-i-a-get-singleton-from-guice-thats-configured-with-runtime-parameters