I have a class which takes a configuration interface implementation through DI.
#Inject
private PRCConfiguration prcConfig;
There are various implementations of the PRCConfiguration interface. Currently it is injecting the default implementation. I wish to create a value in a config text file which will define what particular implementation of PRCCOnfiguration to inject.
I wish the #Inject notation to verify what value is in the config file, and based on that inject the particular implementation.
I believe we can annotate different implementation through qualifiers and then inject, such as
#Inject #NewImplementation
private PRCConfiguration prcConfig;
But again i am injecting on compiletime through hard coding.
My config file would be something like
"injectconfig":"NewImplementation"
to inject the #NewImplementation implementation, subsequently if i want a different implementation to be injected. I could just change config file value as
"injectconfig":"DifferentImplementation"
and the different implementation will be injected.
Is what i require possible through CDI?
You can use producer methods to achieve something like that.
Basically you just have to create a CDI bean which a method that returns the correct configuration instance and annotate it with #Produces.
Something like this:
#ApplicationScoped
public class ConfigurationProducer {
#Produces
#ApplicationScoped
public PRCConfiguration getConfig() {
if( someCondition ) {
return new NewConfigurationImpl();
}
else {
return new OldConfigurationImpl();
}
}
}
In this case you should annotated both implementations with #Vetoed or you will get ambiguous dependencies errors. Using #Vetoed on the implementations will tell CDI that using the producer is the only way to obtain PRCConfiguration instances.
Related
I'm looking for a pattern to simplify bean creation for a team of developers.
For now, I've been trying to use abstract classes like this:
public abstract class BaseClass {
#Bean
public BeanA generateBeanA() {
...
return beanA;
}
#Bean
public BeanB generateBeanB() {
...
return beanB;
}
}
The idea behind: I provide the BaseClass and I'd like developers to extend it many times. For each extension, every beans should be generated. But this approach doesn't work : for each extension, developers have to redeclare beans for 2 reasons :
bean declaration is not inherited
to avoid name clashing, they have to name beans manually in each extension
Is there a better pattern that would allow the following?
centralized bean naming (ie: the developer declare a base name in the extension and every bean of the extension is renamed accordingly: ${baseName}${beanName} )
overriden beans would be declared (instead of parent version)
parent beans would be declared if not overriden
There are 3 ways to configure beans in Spring container:
Declare them using XML configuration.
Declare beans using the #Bean
annotation in a configuration class.
Mark the class with one of the
annotations from the org.springframework.stereotype package, and
leave the rest to component scanning.
So, the way you declare Spring bean is wrong.
IMHO, let the developers declare beans as they want, and they just #Autowired them or something.
Please continue by reading this
Suppose I have several components that depend on one service:
public interface MyService { ... }
// in package1
#Component
public class Package1Component1 {
#Autowired
private final MyService myService;
}
public class Package1Component2 {
#Autowired
private final MyService myService;
}
// in package 2
public class Package2Component1 {
#Autowired
private final MyService myService;
}
public class Package2Component2 {
#Autowired
private final MyService myService;
}
And I have two implementations of MyService:
#Service
public class MyServiceImpl1 implements MyService { ... }
#Service
public class MyServiceImpl2 implements MyService { ... }
And I want MyServiceImpl2 to be injected into all components in package2 and MyServiceImpl1 everywhere else
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere (MyServiceImpl2 is temporary implementation that should be used only in specific scope).
Is there any way to specify bean for scope (java package?), like in Angular I can override module providers (AuthService in this case):
#NgModule({
declarations: [LoginComponent, UserInfoComponent],
providers: [
{
provide: AuthService,
useClass: FacebookAuthService,
},
],
})
export class AuthModule {}
You can introduce your meta-annotation annotated with #Qualifier and use it.
Once you are ready to change, just change Qualifier on your meta annotation.
I think it's not really correct to co-relate Angular specificities with Spring, as they are simply two radically different infrastructures, in all aspects.
Why don't you want to use #Qualifier? for what reason? because, the problem you describe is exactly why people came up with #Qualifier implementation.
I don't want to use #Qualifier to resolve ambiguity as it will require to always specify it when you need to inject MyService and to change a lot of files when I need to switch to single implementation everywhere.
Not really. You can provide ID for your bean definition, and disregarding of what implementation you'll use later, same bean, with that same ID, will be injected wherever you'll qualify it to be injected. You will only swap the implementation class.
Also, package in Java, is not a scope for Beans. Package is facility for grouping a logically similar classes, and it can be considered as a scope, but for class and its members' accessibility/visibility, not for the beans.
Bean scopes have a different semantics, and you can read about them here.
The is another way to specify, that the bean should qualify as a candidate, if there are more than one implementations of a type you're injecting. It's #Primary; however, this #Primary will always override any other candidates, while with #Qualifier you can leverage more fine-grained control on what to inject where.
I wanna switch from xml based spring configuration into java-based. For constructor type injection it is easy. Example I am using:
#Configuration
public class BeanConfiguration {
#Bean
public GreetingService greetingService(GreetingDao greetingDao) {
return new GreetingService(greetingDao);
}
#Bean
public GreetingDao greetingDao() {
return new GreetingDao();
}
}
However, when I want to inject through setter method I am doing something like this:
#Configuration
public class BeanConfiguration {
#Bean
public MeetingDao meetingDao() {
return new MeetingDao();
}
#Bean
public MeetingService meetingService(MeetingDao meetingDao) {
MeetingService meetingService = new MeetingService();
meetingService.setMeetingDao(meetingDao);
return meetingService;
}
}
I am not sure if this is a possible way to inject with Java-based Configuration and setter method. Unfortunately I cannot find any example (for constructor dependencies a lot of examples exists). Also I am not sure in case of Java-based configuration when should I use constructor and when setter. In Spring docs it is described that I should use constructor for required and setter for optional dependency. However, I see it as the same result for this kind of approach.
Thanks for any clarification.
Adam
Under the assumption that you cannot change the classes themselves, you could always just not return the bean until you have injected all the values.
#Configuration
public class YourConfig{
#Value("${some.value.from.properties}")
private String someValue;
#Bean
#Autowired
public YourBean yourBean(TheDependency theDependency){
YourBean bean = new YourBean();
bean.setTheDependency(theDependency);
bean.setSomeValue(someValue);
return bean;
}
}
Constructor injection is always preferred with class dependencies, but not always possible.
If you have access to changing the source for these services and beans you are creating, then I suggest using constructor injection and placing "#Service" on the class and "#Autowired" on the constructors.
Properties are an example of "optional" dependencies; it is common to default values and behavior if not provided. I prefer just placing the "#Value" directly on that field instead of my constructor because otherwise you might end up with WAY too many parameters. This is "setter" injection, but you don't want an actual setter method (again, not normally anyways); you only want Spring to change the value, not any of your other code.
Using "#Value" is fine if you only have one or two properties(or 3? It's not an exact science); however, if you find you have a lot of fields with "#Value" then you should use a configuration bean instead. An "#ConfigurationProperties" bean can also be treated the same way with "setter" injection, but I prefer constructor injection to be sure that at least the bean is never null, even though it's values might be.
I have a Spring application consisting of multiple modules. One of these modules requires certain Spring beans to be present in the context (it cannot run standalone as it does not have a complete context itself).
This module provides basic functionality that needs to be shared amongst many applications that customize this module by making the correct beans available (singleton or request scoped, depending on needs).
This works perfectly and we're very happy with this setup as it provides a seperation between core functionality and business specific logic.
My question is now, I have a class that can optionally be used to satisfy one of the depedencies. It is not annotated with #Component to prevent it being scanned, however I would like the projects to be able to choose to use this class or supply their own implementation.
The core module looks like this:
public interface AProvider;
#Component
public class AService {
#Inject private AProvider aProvider;
}
And it provides this implementation that can optionally be used:
public class DatabaseBasedAProvider implements AProvider {
#Inject private SomeOtherDependency dependency; // <-- this needs to be injected still if used!
}
An example project that uses the core module then must make sure that one bean of type AProvider is present on the context. This can be achieved like:
#Configuration
public class Configuration {
#Bean
AProvider getAProvider() {
return new OurOwnAProviderImplementation();
}
}
What I would like though is something like:
#BeanClass // <-- some annotation I made up
Class<AProvider> getAProviderClass() {
return DatabaseBasedAProvider.class; // <-- have spring inject this!
}
What I don't want is:
#Bean
AProvider getAProvider() {
return new DatabaseBasedAProvider( ... add dependencies here myself ... );
}
I have solved a case similar to yours (if I understand correctly), using the #Primary annotation. Might be something for you.
public interface AProvider { }
For every module to have some implementation of the interface, create a default implementation that is shared.
#Service
public class DefaultAProvider implements AProvider {}
Then, if some module wishes to use its own implementation, "override" the bean using #Primary.
#Primary
#Service
public class MyVerySpecialAProvider implements AProvider {}
Then, anytime you inject AProvider, Spring will pick the #Primary implementation.
An alternative will be to use #Profile, another alternative would be to annotate your AProvider classes with #Component in combination with #ConditionalOnProperty and document the different choices to your consumers.
Example
#Component
#ConditionalOnProperty(name = "my.aprovider.choice", havingValue = "database")
public class DatabaseBasedAProvider implements AProvider {
#Inject private SomeOtherDependency dependency; // <-- this needs to be injected still if used!
}
I've found a solution that allows me to decide at the client what class I want to use for AProvider.
It is not super nice, but it does mean I don't need to make specific changes to the code in the core module (as this module is supposed to be generic).
In a #Configuration class in the client's config I'm now doing this:
#Component
static class MyDatabaseBasedAProvider extends DatabaseBasedAProvider {
// No implementation
}
This makes Spring construct the class and handle all the injections. It could be shorter and it does require the class to be non-final but it works.
The client is now alerted if the bean is missing, is free to make their own implementation and free to pick one of the existing implementations if one suits their needs, without the core module having to decide before hand how AProvider might be supplied.
I'd like to create a Module that dynamically binds instances to named annotations. The use case is I would like to automatically bind the values in my configuration with the key in the properties file being the #Named value.
However the configuration is bound in a different module so I need the config to be injected. Solutions I've looked at are:
Binding in the configure() method.
This method is not injected into and I can not get the base configuration.
Using a Provider/#Provides.
Providers only bind a single instance.
Using MultiBinder.
My use case is a little different then what is provided by this extension. Multi-binding allows you to bind multiple instances separately and then have them injected as a Collection more complex containing type. I would like to bind each instance separately and have them by uniquely identifiable for injection latter.
Use a childInjector.
Unfortunately this isn't possible without some extensive modification of existing code. This answer is a very good description of how to solve this problem this way though.
Inject the binder somehow. (I started getting a little hackier)
Guice allows injecting the Injector for latter use, I tried injecting the Binder into the Module though a #Provides method and then using the binder directly to make multiple binds within the method. Guice would not inject the binder.
Remember that all of the configure methods configure all of the bindings in an Injector before any injection can happen. That said, a few things:
Binding #Named properties to the contents of a single Properties instance is so useful, there's a Names.bindProperties(...) method that does it automatically for you. The only trick is that you need to have the Properties instance at the time configure() is run.
If they're all available at the same time, don't worry about binding the properties in one module and binding the application in another. As long as they all go into the same Injector, Guice will combine them all and let them satisfy each others' dependencies.
Providers can return different instances, and usually do--but you're right that it won't help you differentiate between keys. If injecting the Properties instance directly is too ugly, consider making a lightweight factory instead:
public class ConfigOracle {
#Inject private Properties properties;
public String getAsString(String key) { ... }
public int getAsInt(String key) { ... }
}
public class SomeConfigUser {
#Inject private ConfigOracle configOracle;
public void doStuff() {
doStuffBasedOn(configOracle.getAsString("my.properties.key"));
}
}
You should never need to inject a Binder (or anything else) into a Module.
If you implement Module, the binder will be a parameter of configure(). If you extend AbstractModule as you should, just call the binder() method.
You can pass in dependencies through constructor arguments to the Module, if need be, which (as far as I'm concerned) is the only way Modules should vary the bindings they create.
There's no reason you couldn't create a Module through an Injector, but you'd have to have an Injector first, and it sounds like you're trying to get away with only having one.
If you need other instances from the Injector you can always write a Provider implementation with #Inject fields/methods/constructors, or even take in parameters in a #Provides method (which will be filled in with dependencies automatically).
Overall I still favor the child injector approach (thanks for the link and compliment to my previous answer!), which fits your "dynamic bindings based on an injected instance" description the best, and would literally be this simple:
class PropertiesModule extends AbstractModule {
Properties properties;
PropertiesModule(Properties properties) {
this.properties = properties;
}
#Override public void configure() {
Names.bindProperties(binder(), properties);
}
}
Injector oldInjector = Guice.createInjector(allYourOtherModules);
Module myModule = new PropertiesModule(oldInjector.get(Properties.class));
Injector injector = oldInjector.createChildInjector(myModule);