I am pretty new to spring or dependency injection. I have an abstract class A in a jar file built already, which is not managed by Spring (This is based on the fact that it does not have any of its dependencies auto-wired, no spring annotations used in the library.).
I have project which needs to use this class and want to inject my implementations of class A's dependency (say, of Type B). This project uses springboot.
How can I inject dependency of type B into A?
I tried following :
1. Created a configuration (#Configuration) class and added a method getB() annotated as #Bean which will return object of type B using my implementation of B.
#Bean
public B getB () {
return new MyB();
}
If you want to inject B into A you cannot. Since A is not managed by Spring, the IOC container will never inject anything in a class that he does not know.
The key to your problem is the way you want to get and use the instance of A.
If you want to use A in your code managed by spring then you have to create yourself a factory for A :
#Bean
public A a() {
B b = new MyB();
A a = new A(b); // new A is not possible since A is abstract but you got the idea
return a;
}
// ...
class MyService {
#Autowired
A a;
void something() {
(a.b instanceof MyB) // true
}
}
Related
I have 3 beans which implements same interface. But i want to instantiate only one of them, if A is available then A, if there is no A then B, and if there is no A and B then C.
When i had only two of them it was simple, default one had '#ConditionalOnMissingBean' annotation. But not sure will that work with 3 of them.
Is it possible to solve this with annotations?
I don't want to create factory method, as I have multiple applications using those components, and i dont have ability to change some of them
Yes, using the #ConditionalOnMissingBean annotation , you should set the code like this:
#Configuration
public class ConditionalOnMissingBeanConfig {
#Bean
public A beanA(){
return new A(); // will initialize as normal
}
#Bean
#ConditionalOnMissingBean(name="beanA")
public B beanB(){
return new B(); // it will not initialize as
// beanA is present in the beanFactory.
}
#Bean
#ConditionalOnMissingBean(name="beanB")
public C beanC(){
return new C(); // will get initialized as there is no
// bean with name beanB in BeanFactory.
}
}
Conditional that only matches when the specified bean is missing from the beanfactory. This will only match when the bean definition is processed by the application context and as such is recommended to be used by auto-configuration classes only.
Let me propose an alternative approach:
You can introduce a configuration variable that will denote the "domain" related explanation of what should the system do
Example:
If A, B, C are, say, different caching strategies (in-memory, redis, ehcache), then introduce the following configuration value:
caching.type=ehcache // or in-memory or redis
Then the beans can be declared as follows:
#ConditionalOnProperty(name="caching.type" , havingValue="in-memory", matchIfMissing = true) // this is a fallback if no property is specified
class InMemoryCaching implements CachingStrategy {}
#ConditionalOnProperty(name="caching.type" , havingValue="ehcache", matchIfMissing = false)
class EhcacheCaching implements CachingStrategy {}
#ConditionalOnProperty(name="caching.type" , havingValue="redis", matchIfMissing = false)
class RedisCaching implements CachingStrategy {}
I know its slightly different solution, but it has the following benefits:
its easy to add yet another implementation of the interface - no code changes in existing beans
beans are not aware of each other even not at the level of bean names in spring
easy to debug - just look at the configuration property value
this approach can be applied to #Configuration and manage set of beans
Suppose I have something like this:
#Component(immediate = true)
public class A {}
public class B {
#Reference
public void injectA(A a) {...}
}
Is there a way to have A be injected into B if I manually create instances of B?
If not, is the only alternative to just use the service registry or is there a go-to pattern?
UPDATE:
I can't manually inject an instance of A (without using the service registry) because the code that creates instances of B doesn't have it.
Clearly you can do new B().injectA(new A()). But if you want to manually inject the A instance created by SCR, you need to get that A instance from the service registry which is where SCR makes it available.
I have a class B which implements W interface. It has a default implementation of W's method. class C and D override default implementation for which they need a service whose bean is instantiated by spring. String a and b comes from user and hence there is no way I can create a bean of B/C/D in advance. So I have a factory which creates a new object based on user parameters (it will create B/C/D based on parameters). Is there any clean way I can use service beans(aa/bb/cc/dd etc.) from inside C and D (spring autowires during server startup, at that time parameter required for instantiating B/C/D are not available) or is there any better way to solve the problem ?
Class B implements W{
String a;
String b;
B (String a, String b);
w_method(){
}
}
Class C extends B {
#Autowired
Service aa;
#Autowired
Service bb;
#Autowired
Service cc;
#override
w_method(){
}
}
Class D extends B {
#Autowired
Service dd;
#override
w_method(){
}
}
There are three possible approaches:
The fact that constructor arguments come from user doesn't mean that these objects cannot be created by Spring.
You can declare them as Spring beans of scope prototype and do the following in your factory:
public C createC(String a, String b) {
return applicationContext.getBean("c", a, b);
}
A disadvantage of this method is that your factory depends on ApplicationContext.
You can annotate these classes with #Configurable and enable AspectJ weaving. In this case Spring will configure objects of these classes even if you create them with new. See 7.8.1 Using AspectJ to dependency inject domain objects with Spring.
You can trigger autowiring manually as
applicationContext.getAutowireCapableBeanFactory().autowireBean(...);
This approach is useful when you don't have control over creation of objects that you need to autowire (servlets, etc).
I think the simplest method would be to wire the services into the factory and call setters on the B / C / D objects before you return them, rather than attempting to use #Autowired.
Or use axtavt's constructor argument method. If you want to avoid depending on ApplicationContext, you can use Lookup Method Injection, but you'll have to patch Spring per this blog post: http://nurkiewicz.blogspot.co.uk/2010/08/creating-prototype-spring-beans-on.html
I have a Spring bean, let's say:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class AImpl implements A {
public void setSomeDependency(D dependency) {
// This setter DOES NOT BELONG to interface A
}
}
<bean id="aImpl" class="AImpl"/>
Now I want to integration test it, but first I need to mock the dependency D, because it does too much stuff. Since the AImpl implements an interface and contains a transactional annotation, the generated proxy is only compatible with the interface A, so I can do this:
#Inject #Named("aImpl")
private A a;
but cannot:
#Inject #Named("aImpl")
private AImpl a;
As a result, I can't mock my dependency.
Please note that adding void setSomeDependency(D dependency) to interface A is not an option, as it has no business meaning. Neither it is using the proxy-target-class="true", as it breaks a whole lot of other beans (this attribute affects all beans in the context).
Is there a way to unproxy the injected bean A, so I could cast it to AImpl?
Try this:
if(AopUtils.isAopProxy(a) && a instanceof Advised) {
Object target = ((Advised)a).getTargetSource().getTarget();
AImpl ai = (AImpl)target;
}
Bonus: in Scala I am using the following equivalent function for the very same purpose:
def unwrapProxy(a: AnyRef) = a match {
case advised: Advised if(AopUtils.isAopProxy(advised)) =>
advised.getTargetSource.getTarget
case notProxy => notProxy
}
With the introduction of Spring 4.2.RC1, there is now a dedicated utility class in the spring-test module that handles this case for you.
The class is called AopTestUtils and provides the methods:
getTargetObject (unwraps only the top-level proxy)
getUltimateTargetObject (unwraps multiple levels of proxies if they exist).
Check out the relevant commit as well as the respective issue.
Suppose that I have two classes, first a class without any properties, fields or annotations:
public class B {}
And a class which gets B injected, like this:
public class A {
#Inject
private B b;
public B getB() {
return b;
}
}
Now class A is pretty useless until we use it, so there are two options:
#Inject it
Construct it manually, using the trusty "new A()"
If A gets injected, CDI manages it and is kind enough to inject B which has the implicit scope of #Dependent. Cool, just what I want.
However, if I manually construct A (let's say in a factory or a builder), CDI completely ignores my object and won't inject an object of type B.
Example I'm talking about when it doesn't work, here object a will always remain null:
public class Builder {
#Inject
private A a;
public static Builder ofTypeSomething() {
// do some magic here
return new Builder();
}
private Builder() {
// and some more here
}
}
Why doesn't this work?
Class A is a valid managed bean and has a valid scope, just like class B. Even if I add #Producer to the static method, it won't change anything (which is fine, cause the idea of the static method is to call it, not to inject Builder anywhere).
Dependency injection, while useful, is not magical. The way DI works is that when you ask the container for an instance of an object the container first constructs it (via new()) and then sets the dependencies (how this happens depends on your framework).
If you construct the entity yourself then the container has no idea you've constructed the entity and can't set the dependencies of the entity.
If you want to use a factory then most frameworks have some way of configuring the entity so that the container knows to make a static factory method call and not call the constructor of the entity. However, you still have to obtain your entity from the container.
Edit: This site seems to demonstrate how to use a factory in CDI.