Dynamically inject service implementation with Spring - java

I've already gone through some tips on how to do this, like this one: stack overflow; but my problem is that my own implementation needs other things to be injected in it. Here's the example:
public interface MyService {}
public class ServiceImplA implements MyService {
#Autowired
private final SomeStuffA a_stuff;
}
public class ServiceImplB implements MyService {
#Autowired
private final SomeStuffB b_stuff;
}
#Configuration
public class SpringConfig {
#Bean
#Scope("singleton")
public MyService getService() {
boolean useA = // read config file and decide impl
return useA ? new ServiceImplA() : new ServiceImplB();
// I can't instantiate this, so i need them to be injected as well
}
}
I'm familiar with Google Guice, where I would do something like this:
bind(MyServicle.class).to(useA ? ServiceImplA.class : ServiceImplB.class);
So, I need a way to do this using Spring

I think your problem is that your base class MyService is not marked for any profile.
When you define profile the beans that have such specification will override beans that implement the same interface and do not have profile definition. This does not work this way.
When working with active profile X spring starts all beans that are not targeted for any profile and beans targeted for current profile. In your case you can choose wisely.
I think that if you want to use profiles you should define at least 2: A and B (the names are taken just for example.)
Now mark ServiceImplA as A and ServiceImplB as B:
#Service
#Profile("A")
public ServiceImplA interface MyService { ... }
and some development implementation
#Service
#Profile("B")
public ServiceImplB interface MyService { ... }
More about profiling you will get here

Related

Dependency inversion in EJB based application

I want to make some of parts my JEE application independent from others ones using dependency inversion and dependency injection. Below is some code of main core part, that uses MyService, but is independent from other module that should provide implementation of MyService.
public interface MyService {
public void send(MyObject myObject);
}
.
#Stateless
#LocalBean
public class MyServiceWrapper implements MyService {
#Inject
private MyService myService;
#Override
public void send(MyObject myObject) {
myService.send(myObject);
}
}
To clarify:
Module A contains classes:
MyObject,
MyService,
MyServiceWrapper,
Module B contains implementation of MyService.
I want MyServiceWrapper to have injected implementation of MyService provided by module B, so module A can call implementation of MyService by using MyServiceWrapper, but in te same time module A is independent from module B.
The problem with above code, is that container do not know which implementation of MyService should be injected.
How it should be written so MyServiceWrapper, so it won't be injected to itself, but proper implementation (provided in other module) will be injected instead?
The correct way would be to use what is known as a Qualifier , one example from CDI would be the annotation #Named, this would get rid of ambiguity for the container.
public interface MyService {
void send(MyObject myObject);
}
and the implementation of MyService :
#Named("fromModuleA")
#ApplicationScoped
public class MyServiceWrapper implements MyService {
#Inject
#Named("fromModuleB")
private MyService someOtherBean;
#Override
public void send(MyObject myObject) {
this.someOtherBean.send(myObject);
}
}
#Named("fromModuleB")
#ApplicationScoped
public class SomeOtherBeanFromModuleB implements MyService{
#Override
public void send(MyObject myObject) {
// implementation
}
}
The #Inject comes from a Java specification called CDI (Context and Dependency Injection), with this annotation it doesn't matter whether you use it on EJBs or CDI beans, but #EJB will only work with the EJB Container. Also note you don't really need the Interface MyService at least not anymore but it's a good practice to code to the interface.

Implicitly qualified autowiring in Spring

I have a project with some independent bean X, that is autowired in a bunch of services. Services are used by each other, and finally used in single entry point (controller). Now there is new requirement: implement several versions of X, and decide witch one is to use according to entry point's parameter (enum XType). It would be nice to do it without changing services.
My idea of solution is to create custom scope UsesX and implement BeanFactoryPostProcessor, that will converts each BeanDefinition with UsesX to set of singletons for each XType. Also, it will adds qualifiers to this beans, to make it possible to make factory method for X and parameter-based selection in controller. But how to add this qualifier to #Autowired in services implicitly, without changing their classes?
UPD
Ok, example, I want to use db url "jdbc:mysql://Adb" when A requested, and "jdbc:mysql://Bdb" when B:
enum DatabaseType {A, B}
#Controller
#RequestMapping(/)
class MyController {
#Autowired ServiceProvider provider; // some way to get service by DatabaseType
void foo(#RequestParam DatabaseType dbType) {
ServiceA a = provider.getA(dbType);
a.bar();
ServiceB b = provider.getB(dbType);
b.baz();
}
}
#Service
class ServiceA {
// Don't want to get information about different databases in services
#Autowired ServiceB b;
#Autowired ServiceC c;
#Autowired DaoFoo dao;
//...
}
#Service
class ServiceB {
#Autowired ServiceC c;
#Autowired DaoFoo daoFoo;
#Autowired DaoBar daoBar;
//...
}
#Service
class ServiceC {
#Autowired DaoBar daoBar;
//...
}
#Repository
class DaoFoo {
DaoFoo(String dbURL) {/*...*/}
}
#Repository
class DaoBar {
DaoFoo(String dbURL) {/*...*/}
}
Also, it is required to "jdbc:mysql://Adb" and "jdbc:mysql://Bdb" be configured in XML configuration.
I want to wrap up your requirements so that it would be clear if I'm getting you right.
You have a set of #Services that you don't want to modify.
At this moment you have only one implementation of X type which is used by this services.
The choice of X implementation to be used in services would be defined by XType enum, which in turn would be available from request.
You want X type beans be configurable from xml.
OP: What X implementation should be used in case if one of this services would be called w/o XType?
So if my understanding is correct, it seems like you need Proxy for X type.
Within this Proxy you need to get this XType implicitly (f.ex. through ThreadLocal var).
As #Autowired is used, beans are identified by type in first place. Therefore, you need to use already existing X implementation for proxing and extract your current implementation and new one to different type.
As a result you might end up with following:
interface newX {
void save();
}
#Repository
class DaoFoo implements newX {
public void save() {...};
}
#Repository
class DaoBar implements newX {
public void save() {...};
}
class XImpl implements X, newX {
public final ThreadLocal<XType> currentXType = new ThreadLo...;
Map<XType, newX> mapping = ....
public void save() {mapping.get(currentXType.get()).save();};
}
Your example is a little confusing because your Services are named A and B, but you also use A and B for your DatabaseType. But I think I understand what you want.
I don't think you can do this with Autowired, but you can make your Services as #Scope("prototype") and retrieve them from context. The context should instantiate the Service the first time you request it, then reuse the same bean when the same input is provided.
#Configuration
public class ServiceProvider{
...
#Bean
#Scope("prototype")
public ServiceA serviceA(DatabaseType dbType) {
...
}
#Bean
#Scope("prototype")
public ServiceB serviceB(DatabaseType dbType) {
...
}
}
#Controller
#RequestMapping(/)
class MyController {
#Autowired
ConfigurableApplicationContext context
void foo(#RequestParam DatabaseType dbType) {
AutowireCapableBeanFactory beanFactory = context.getBeanFactory();
ServiceA serviceA = (ServiceA)context.getBean("serviceA", dbType);
...
}
}
Create a service interface like :
interface ServiceInterface{
public boolean isTheOne(String type); // or some suitable name.
}
all your services then need to implement this interface, then in controller
#Controller
#RequestMapping(/)
class MyController {
#Autowired
Set<ServiceInterface> provider;
void foo(#RequestParam DatabaseType dbType) {
ServiceInterface service = provider.stream().filter(s -> s.isTheOne(String dbType));
service.bar();
}
}
You can maintain your XType as an enumerator within a customised Qualifier by developing #Interface.
Please find below a sample which mentions conditional wiring of beans based upon different types of datatype:
#Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public static #interface DBHost{
public static enum DatabaseType {
A,
B
}
}
#Autowired
#DBHost(DBHost.DatabaseType.A)
ServiceBean serviceInstanceA;
Find additional usage of Qualifier annotation here

Spring annotations confusion

i am really confused with spring annotations.
where to use # Autowired, where class is # Bean or # Component,
i understand we cannot use
Example example=new Example("String");
in Spring
but how alone
#Autowired
Example example;
will solve the purpose?
what about Example Constructor ,how spring will provide String value to Example Constructor?
i went through one of the article but it does not make much sense to me.
it would be great if some one can give me just brief and simple explanation.
Spring doesn't say you can't do Example example = new Example("String"); That is still perfectly legal if Example does not need to be a singleton bean. Where #Autowired and #Bean come into play is when you want to instantiate a class as a singleton. In Spring, any bean you annotate with #Service, #Component or #Repository would get automatically registered as a singleton bean as long as your component scanning is setup correctly. The option of using #Bean allows you to define these singletons without annotating the classes explicitly. Instead you would create a class, annotate it with #Configuration and within that class, define one or more #Bean definitions.
So instead of
#Component
public class MyService {
public MyService() {}
}
You could have
public class MyService {
public MyService() {}
}
#Configuration
public class Application {
#Bean
public MyService myService() {
return new MyService();
}
#Autowired
#Bean
public MyOtherService myOtherService(MyService myService) {
return new MyOtherService();
}
}
The trade-off is having your beans defined in one place vs annotating individual classes. I typically use both depending on what I need.
You will first define a bean of type example:
<beans>
<bean name="example" class="Example">
<constructor-arg value="String">
</bean>
</beans>
or in Java code as:
#Bean
public Example example() {
return new Example("String");
}
Now when you use #Autowired the spring container will inject the bean created above into the parent bean.
Default constructor + #Component - Annotation is enough to get #Autowired work:
#Component
public class Example {
public Example(){
this.str = "string";
}
}
You should never instantiate a concrete implementation via #Bean declaration. Always do something like this:
public interface MyApiInterface{
void doSomeOperation();
}
#Component
public class MyApiV1 implements MyApiInterface {
public void doSomeOperation() {...}
}
And now you can use it in your code:
#Autowired
private MyApiInterface _api; // spring will AUTOmaticaly find the implementation

Spring Qualifier, service implementation when application starts

(spring version is 4.1.6)
I have a service Interface "ContractService" that retreives contracts of a person.
2 service classes ContratServiceImpl & ContratServiceImplWeb implementing this interface.
ContratServiceImpl calls dao to retreive data
ContratServiceImplWeb calls web service...
The Interface ContractService is used by another service (UTService):
#org.springframework.stereotype.Service
#Transactional(value="transactionManager")
public class UTServiceImpl implements UTService {
#Autowired #Qualifier(...<variable.propeties>...)
private ContractService contractService;
...
}
Here are services implementing the interface that can be in
#Service("ContratServiceImplWeb") #Transactional(value="transactionManager")
class ContratServiceImplWeb implements ContratService {
...
}
#Service("ContratServiceImpl") #Transactional(value="transactionManager")
class ContratServiceImpl implements ContratService {
...
}
Configuration class
#Configuration
#EnableTransactionManagement
#ImportResource(value={ "classpath:sessionFactory-datasource-spring.xml", "classpath:contrat_factories.xml"} )
#ComponentScan(basePackages = { "com.xxx.core.service.impl"
, "com.xxx.core.dao.impl"}
)
public class ContextCoreServiceConfiguration {
}
When my application starts I would like to "qualify" ContractService with ContratServiceImpl or ContratServiceImplWeb depending an external configuration file (.properties or XML) where bean names are set.
How can I do this ?
----- Last comments -------
contractServiceImpl & contractServiceImplWeb are set as #service and scanned by configuration.
In "UTServiceImple" class, 1 of the 2 classes need to be #autowired with a discriminating parameter (may Profile ?). This is not the only group of classes that is concerned.
Profile should not be the same from a couple to another.
So, I have to set a profile for each group of classes ?
I guess Spring profiles is exactly what you are looking for.
They let you choose a specific bean implementation dynamically based on a parameter (active profile).
For detailed information, please have a look here if you are using boot or here if using raw spring.
You are close. You want your ContractService declaration to look more like this:
#Autowired
private #Qualifier("contractServiceImpl") ContractService contractServive;
This of course presumes that your ContractServiceImpl bean was correctly configured and created, either manually or using the #Service or #Component annotation on your class.
I post the solution. I used #Profiles. It really feeds my needs.
Thanks for having given me this information.
#org.springframework.stereotype.Service
#Transactional(value="transactionManager")
public class UTServiceImpl implements UTService {
private static final Logger logger = Logger.getLogger(UTServiceImpl.class);
// SERVICES
#Autowired
private VerificationHabilitationService verificationHabilitationService;
#Autowired
private ContratService contratService;
...
}
Interface referenced in the main service
public interface ContratService {
Set rechercheIdentifiantAdherent(String numeroImmatriculation);
...
}
Database Service
#Service("ContratServiceDb") #Transactional(value="transactionManager") #Profile("contratServiceDb")
class ContratServiceImplDb implements ContratService {
private Logger logger = null;
#Autowired
private ContratFactory contratFactory;
...
}
Web Service
#Service("ContratServiceWeb") #Transactional(value="transactionManager") #Profile("contratServiceWeb")
class ContratServiceImplWeb implements ContratService {
private Logger logger = Logger.getLogger(ContratServiceImplWeb.class);
#Autowired
private ContratFactory contratFactory;
...
}
Configuration
#Configuration
#EnableTransactionManagement
#ImportResource(value={ "classpath:sessionFactory-datasource-spring.xml", "classpath:contrat_factories.xml"} )
#ComponentScan(basePackages = { "com.xxx.core.service.impl"
, "com.xxx.core.dao.impl"}
)
public class ContextCoreServiceConfiguration {
}
For each implementation classe I define a Pofile : contratServiceDb, contratServiceWeb. When context is initialized I set active profile (using external properties file). Then, services matching profiles are autowired. See below :
String configCoreClass = servlet.getInitParameter("contextCoreConfigurationClass");
String[] profiles = { PropertiesHelper.getProperty(PropertiesHelper.PROPERTY_SERVICE_CONTRAT)
,PropertiesHelper.getProperty(PropertiesHelper.PROPERTY_SERVICE_ADHERENT)
};
AnnotationContextCoreLocator.getInstance().getEnvironment().setActiveProfiles(profiles);
AnnotationContextCoreLocator.getInstance().register( Class.forName(configCoreClass) );
AnnotationContextCoreLocator.getInstance().refresh();

How to provide a default bean in Spring by condition?

I'd like to provide a default bean by a custom jar. Only if the user implements a specific abstract class the default bean injection should be skipped.
The following setup already works fine, except one thing: any injected classes within the default wired class are null! What might I be missing?
#Configration
public class AppConfig {
//use the default service if the user does not provide an own implementation
#Bean
#Conditional(MissingServiceBean.class)
public MyService myService() {
return new MyService() {};
}
}
#Component
public abstract class MyService {
#Autowired
private SomeOtherService other;
//default impl of the method, that may be overridden
public void run() {
System.out.println(other); //null! Why?
}
}
public class MissingServiceBean implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getBeanFactory().getBeansOfType(MyService.class).isEmpty();
}
}
The MyService bean is created and can also be injected. But contained classes are null.
If I remove the #Conditioanl annotation everything works as expected.
Your simplest possibility is the usage of the #Primary annotation. You define your interface/abstract class and build a default implementation. Until here thats the basic spring autowiring.
Now you create another implementation with #Primary and make it available in the application context. Spring will now pick up the primary implementation for the autowiring.
Another possibilty in Spring 4.1+ would be to autowire an ordered List<Intf> and ask the interface with a supports(...) call to fetch the current implementation for whatever parameter you give into supports. You give the default implementation a low priority and the more detailed ones a higher priority. Like this you can even build a more detailed default behavior. I'm using this approach for several configurations to handle different classes with default and specific implementations.
One example would be during permission evaluation where we have a default config for the base classes, another higher one for domain classes, and a even higher possible one for specific domain entities. The permission evaluator goes through the list and checks each implementation if it supports that class and delegates to the implementation in that case.
I dont have the code here but i could share it later if desired to make that more clear.
Change your code to the following:
public abstract class MyService {
private final SomeOtherService other;
public MyService(SomeOtherService other) {
this.other = other;
}
//default impl of the method, that may be overridden
public void run() {
System.out.println(other);
}
}
#Configration
public class AppConfig {
#Autowired
private SomeOtherService other;
//use the default service if the user does not provide an own implementation
#Bean
#Condition(MissingServiceBean.class)
public MyService myService() {
return new MyService(other) {};
}
}

Categories