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.
How to Use @Autowired and @Qualifier in Spring 1 Create Service Interface. Let’s create an EmployeeService interface with only one method. ... 2 Implement Service Interface. Lets now create two Service classes which will implement the above mentioned EmployeeService interface. 3 Use @Qualifier to Differentiate Beans in RestController. ...
Autowiring feature of spring framework enables you to inject the object dependency implicitly. It internally uses setter or constructor injection. Autowiring can't be used to inject primitive and string values. It works with reference only.
Although it's useful, there are use cases for which this annotation alone isn't enough for Spring to understand which bean to inject. By default, Spring resolves autowired entries by type.
The Spring framework enables automatic dependency injection. In other words, by declaring all the bean dependencies in a Spring configuration file, Spring container can autowire relationships between collaborating beans. This is called Spring bean autowiring.
I want to wrap up your requirements so that it would be clear if I'm getting you right.
@Service
s that you don't want to modify.X
type which is used by this services.X
implementation to be used in services would be defined by XType
enum, which in turn would be available from request.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();};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With