Let's say I have a HigherLevelBean that depends on LittleService. The LittleService is an interface with two implementations.
There is no static or semi-static way to tell which of the two implementations should be used, it's all dynamic (session scoped, in fact). When request from this user comes in use the LegacyLittleService, and for requests from that other user use NewShinyLittleService.
The services are not going to be that small. They will have their own dependencies that will need to be injected and they will probably come from two different application contexts. Think about using one app over two different schemas/data models.
How can I achieve this kind of runtime dynamic? Ideally with annotation-driven configuration. What are my options, their pros and cons?
You could simply have a factory, where both services are injected:
#Component
public class LittleServiceFactory {
#Autowired
private LegacyLittleService legacy;
#Autowired
private NewShinyLittleService newShiny;
#Autowired
private TheSessionScopedBean theSessionScopedBean;
public LittleService get() {
if (theSessionScopedBean.shouldUseLegacy()) {
return legacy;
}
else {
return newShiny;
}
}
}
Now inject this factory anywhere you want, and call get() to access the appropriate LittleService instance.
Related
Suppose I want to use a service in a POJO class, like an implementation of some sort, can I just pass this service as a parameter to this POJO? Or would that be bad practice?
#Service
public class MyService {
// Inject AnotherService in this service
public MyService(AnotherService anotherService) {
// Now pass that service in a POJO
SomeImplementation impl = new SomeImplementation(anotherService);
}
}
public class SomeImplementation {
public SomeImplementation(AnotherService anotherService) {
// start using the AnotherService here...
}
}
For this example I used Java and Spring, but this question applies to all languages with dependency injection.
I would say that it's just not making use of the framework you're operating within. That's exactly what DI is for: letting the container handle the components and their relations (eg. if you inject sth multiple times, DI helps you avoid multiple instantiations).
Now, in your case, you can use the #Configurable annotation, which adds a POJO component to the Spring context, and so lets you inject stuff into it.
I have been using dependency injection using #Autowired in Spring boot. From all the articles that I have read about dependency injection, they mention that dependency injection is very useful when we (if) decide to change the implementing class in the future.
For example, let us deal with a Car class and a Wheel interface. The Car class requires an implementation of the Wheel interface for it to work. So, we go ahead and use dependency injection in this scenario
// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}
// Wheel interface implementation
public class MRF impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Car class
public class Car {
#Autowired
Wheel wheel;
}
Now in the above scenario, ApplicationContext will figure out that there is an implementation of the Wheel interface and thus bind it to the Car class. In the future, if we change the implementation to say, XYZWheel implementing class and remove the MRF implementation, then the same should work.
However, if we decide to keep both the implementations of Wheel interface in our application, then we will need to specifically mention the dependency we are interested in while Autowiring it. So, the changes would be as follows -
// Wheel interface
public interface Wheel{
public int wheelCount();
public void wheelName();
...
}
#Qualifier("MRF")
// Wheel interface implementation
public class MRF impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Wheel interface implementation
#Qualifier("XYZWheel")
public class XYZWheel impements Wheel{
#Override
public int wheelCount(){
......
}...
}
// Car class
public class Car {
#Autowired
#Qualifier("XYZWheel")
Wheel wheel;
}
So, now I have to manually define the specific implementation that I want to Autowire. So, how does dependency injection help here ? I can very well use the new operator to actually instantiate the implementing class that I need instead of relying on Spring to autowire it for me.
So my question is, what are the benefit of autowiring/dependency injection when I have multiple implementing classes and thus I need to manually specify the type I am interested in ?
You don't have to necessarily hard-wire an implementation if you selectively use the qualifier for #Primary and #Conditional for setting up your beans.
A real-world example for this applies to implementation of authentication. For our application, we have a real auth service that integrates to another system, and a mocked one for when we want to do local testing without depending on that system.
This is the base user details service for auth. We do not specify any qualifiers for it, even though there are potentially two #Service targets for it, Mock and Real.
#Autowired
BaseUserDetailsService userDetailsService;
This base service is abstract and has all the implementations of methods that are shared between mock and real auth, and two methods related specifically to mock that throw exceptions by default, so our Real auth service can't accidentally be used to mock.
public abstract class BaseUserDetailsService implements UserDetailsService {
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
throw new AuthException("Default service cannot mock users!");
}
public UserDetails getMockedUser() {
throw new AuthException("Default service cannot fetch mock users!");
}
//... other methods related to user details
}
From there, we have the real auth service extending this base class, and being #Primary.
#Service
#Primary
#ConditionalOnProperty(
value="app.mockAuthenticationEnabled",
havingValue = "false",
matchIfMissing = true)
public class RealUserDetailsService extends BaseUserDetailsService {
}
This class may seem sparse, because it is. The base service this implements was originally the only authentication service at one point, and we extended it to support mock auth, and have an extended class become the "real" auth. Real auth is the primary auth and is always enabled unless mock auth is enabled.
We also have the mocked auth service, which has a few overrides to actually mock, and a warning:
#Slf4j
#Service
#ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockUserDetailsService extends BaseUserDetailsService {
private User mockedUser;
#PostConstruct
public void sendMessage() {
log.warn("!!! Mock user authentication is enabled !!!");
}
#Override
public void mockUser(AuthorizedUserPrincipal authorizedUserPrincipal) {
log.warn("Mocked user is being created: " + authorizedUserPrincipal.toString());
user = authorizedUserPrincipal;
}
#Override
public UserDetails getMockedUser() {
log.warn("Mocked user is being fetched from the system! ");
return mockedUser;
}
}
We use these methods in an endpoint dedicated to mocking, which is also conditional:
#RestController
#RequestMapping("/api/mockUser")
#ConditionalOnProperty(value = "app.mockAuthenticationEnabled")
public class MockAuthController {
//...
}
In our application settings, we can toggle mock auth with a simple property.
app:
mockAuthenticationEnabled: true
With the conditional properties, we should never have more than one auth service ready, but even if we do, we don't have any conflicts.
Something went horribly wrong: no Real, no Mock - Application fails to start, no bean.
mockAuthEnabled = true: no Real, Mock - Application uses Mock.
mockAuthEnabled = false: Real, no Mock - Application uses Real.
Something went horribly wrong: Real AND Mock both - Application uses Real bean.
The best way (I think) to understand Dependency Injection (DI) is like this :
DI is a mecanism that allows you to dynamically replace your
#autowired interface by your implementation at run time. This is the
role of your DI framework (Spring, Guice etc...) to perform this
action.
In your Car example, you create an instance of your Wheel as an interface, but during the execution, Spring creates an instance of your implementation such as MRF or XYZWheel.
To answer your question:
I think it depends on the logic you want to implement. This is not the
role of your DI framework to choose which kind of Wheel you want for
your Car. Somehow you will have to define the interfaces you want to
inject as dependencies.
Please any other answer will be useful, because DI is sometimes source of confusion. Thanks in advance.
(spring boot 1.5, java 8)
Suppose there is a Foundation, some Wall types, and Ceilings. They depend on each other, just like their physical counterparts.
This configuration class has a Foundation injected and creates Wall beans, so that Ceilings can have Walls injected. Don't mind the bad practices, I'm just trying to keep the code as short as possible without changing the essential mechanisms.
#Configuration
class Config {
#Autowired
Foundation foundation;
#Bean
// assume there is a lot of repetitive logic here
WoodenWall wood() { return new WoodenWall(foundation); }
#Bean
BrickWall brick() { return new BrickWall(foundation); }
}
And a ceiling:
#Component
class KitchenCeiling {
#Autowired
WoodWall wall;
}
I'm going to be making a lot more Wall types and want them all registered as beans. Instead of having to define a #Bean method for each and every one of them, I want to instantiate them all in a loop and register them manually in a single go. Think of an AllTypesOfWallsBeanFactory if you wish.
#Configuration
class Config implements ??? {
#Autowired
Foundation foundation;
#Override
void addBeans(??? beanRegistry) {
for (Class beanClass : wallClasses) {
// instantiate BrickWall, WoodWall, etc
registry.add(beanClass.getSimpleName(), beanClass, wallInstance);
}
}
}
The problem is, I can't find the right interface to implement or the right SpringBeanRegistryPostProcessorFactoryImplementationThingamajig to go to. I've tried the answers given on all the other SO posts I could find but none do the right thing.
One issue here is that I need the context to already be initializing beans since I need a Foundation, but I also want to add some more beans to the context so that Ceilings yet to be initialized can inject my freshly made Walls.
#Bean methods do exactly that: they can take dependencies that are already initialized and return new beans to be used elsewhere at the same time. I just need the programmatic equivalent to this exact mechanism.
I know dependency resolution is harder in this situation (since there isn't any reflective information for spring to figure out the total following order), but it's gotta be possible to tell spring to
initialize what it has dependencies for
process the newly created beans
goto 1
BeanDefinition doesn't fit the bill because it doesn't take any instances, and to use the factoryMethod setting I would need to make a factory class for each Wall. Back to square one.
Most of the BeanDefinitionRegistryPostProcessor et al interfaces are called too late, don't inject the beans I give them into dependent beans (there was 1 that took instances but didn't do anything with them), or demand a default constructor (i.e. no dependencies). They also tend to give you objects that only take BeanDefinition.
In another project where there was a similar need, what ended up being used was a factory method with still a #Bean method for each instance it needed to produce. I'm starting to think it isn't really possible and what was done in this project is as good as it'll get.
You can try using #PostConstructwith ConfigurableApplicationContext
#Configuration
class Config {
#Autowired
Foundation foundation;
#Autowired
ConfigurableApplicationContext ctx;
#PostConstruct
void addBeans() {
for (Class beanClass : wallClasses) {
ctx.getBeanFactory().registerSingleton(beanClass.getSimpleName(), beanClass, wallInstance);
}
}
}
I'm going to conclude that it just isn't possible to do this reliably. The best one can do is making a factory method and a #Bean method calling the factory for each bean instance that needs to be registered. It doesn't seem possible to cut the #Bean methods out of the picture.
We are using Spring's TransactionInterceptor to set some database partition information using ThreadLocal whenever a DAO method marked with the #Transactional annotation is executed. We need this to be able to route our queries to different database partitions.
This works fine for most DAO methods:
// this causes the invoke method to set a thread-local with the host name of
// the database server the partition is on
#Transactional
public int deleteAll() throws LocalDataException {
The problem is when we need to reference the DAO proxy object itself inside of the DAO. Typically we have to have the caller pass in the proxy-dao:
public Pager<Foo, Long> getPager(FooDao proxyDao) {
This looks like the following in code which is obviously gross.
fooDao.getPager(fooDao);
The problem is that when we are inside of FooDao, the this is not the proxy DAO that we need.
Is there a better mechanism for a bean to discover that it has a proxy wrapper around it? I've looked at the Spring AOPUtils but I see no way to find the proxy for an object. I don't want isAopProxy(...) for example. I've also read the Spring AOP docs but I can't see a solution there unless I implement my own AOP native code which I was hoping to avoid.
I suspect that I might be able to inject the DAO into itself with a ApplicationContextAware utility bean and a setProxyDao(...) method, but that seems like a hack as well. Any other ideas how I can detect the proxy so I can make use of it from within the bean itself? Thanks for any help.
A hacky solution along the lines of what you have suggested, considering that AspectJ compile time or load time weaving will not work for you:
Create an interface along these lines:
public interface ProxyAware<T> {
void setProxy(T proxy);
}
Let your Dao's implement the ProxyAware implementation, now create a BeanPostProcessor with an Ordered interface to run last, along these lines:
public class ProxyInjectingBeanPostProcessor implements BeanPostProcessor, Ordered {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (AopUtils.isAopProxy((bean))){
try {
Object target = ((Advised)bean).getTargetSource().getTarget();
if (target instanceof ProxyAware){
((ProxyAware) target).setProxy(bean);
}
} catch (Exception e) {
// ignore
}
}
return bean;
}
#Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
It is ugly, but works.
There is a handy static utility AopContext.currentProxy() method provided by Spring which returns a proxy to object from which it was called.
Although using it is considered a bad practice, semantically the same method exists in Java EE as well: SessionContext.getBusinessObject().
I wrote few articles about this utility method and various pitfalls: 1, 2, 3.
Use Spring to inject a bean reference into the bean, even the same bean, just as you would for any other bean reference. No special action required.
The presence of such a variable explicitly acknowledges in the class design that the class expects to be proxied in some manner. This is not necessarily a bad thing, as aop can change behavior that breaks the class contract.
The bean reference would typically be for an interface, and that interface could even be a different one for the self-referenced internal methods.
Keep it simple. That way lies madness. :-)
More importantly, be sure that the semantics make sense. The need to do this may be a code smell that the class is mixing in multiple responsibilities best decomposed into separate beans.
Now my colleagues work on logging subsystem and they want to bind separate operations, that was initiated from some business method. For example, if method from bean A calls to some method in bean B and then in bean C it will be great to know than business methods in bean B and bean C does some staff for method from bean A. Especially it will be great to know that methods from B and C done some unit of work for concrete call of bean A.
So, the question is how to tie this units of work into something total? Obviously, it is not beautiful to use method arguments for binding!
And also I think that it is time to ask another question, that is close enough to previous one. What if I want to propagate some context information from bean A to another beans, that are called from A? Something like security credentials and security principal? What can I do?
May be questions that I asked is some kind of bad practice?
Looks like a good use case for mdc, available in both Logback and Log4J. Essentially you are attaching some custom value to a thread and all logging messages comming from that thread can attach that value to the message.
I think the best way to implement this in EJB will be an interceptor:
public class MdcInterceptor {
#AroundInvoke
public Object addMdcValue(InvocationContext context) throws Exception {
MDC.put("cid", RandomStringUtils.randomAlphanumeric(16));
try {
return context.proceed();
} finaly {
MDC.remove("cid");
}
}
}
Now all you have to do is add:
%X{user}
to your logging pattern (logback.xml or log4j.xml).
See also
Logging user activity in web app
For general purpose context information you can use TransactionSynchronizationRegistry. It could look something like this:
#Stateless
public class MyBean {
#Resource
TransactionSynchronizationRegistry registry;
#AroundInvoke
public Object setEntryName(InvocationContext ic) throws Exception {
registry.putResource(NAME, "MyBean");
return ic.proceed();
}
}
#Stateless
public class MyBean2 {
#Resource
TransactionSynchronizationRegistry registry;
public void doJob() {
String entryName = (String)registry.getResource(NAME);
...
}
}
I believe it is usually implemented using ThreadLocal variables as normally each transaction maps to a sigle thread in application servers. So if TransactionSynchronizationRegistry is not implemented in your AS (like e.g. in JBoss 4.2.3) or you need lower level tool, you could use ThreadLocal variables directly.
BTW I guess that MDC utilities use the same thing under the covers.