How can I autowire a list using java, without configuration?
Say I have the following classes:
public abstract class A {
public abstract doStuff();
}
public class B extends A {
#Override
public void doStuff() {
System.out.println("I'm B");
}
}
public class C extends A {
#Override
public void doStuff() {
System.out.println("I'm C");
}
}
And I have the class
public class Aggregator {
#Autowired
private List<A> stuffDoers;
private void doAllStuff() {
for(A a:stuffDoers) {
a.doStuff();
}
}
}
How can I autowire some of A's implementation into the Aggregator without configuring a list in XML?
EDIT: I'm looking for a way to be able to control the members of a list
#Autowired always works with instances of a class, not types. You have defined 3 types: A, B and C, but have not created any instances from them.
To autowire, you need to create these instances, and also register them with Spring. This is where the XML config or Java config comes in. It is basically a short form for creating Spring-registered instances. So you can specify:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ApplicationConfiguration {
#Bean
public B someA() {
return new B();
}
#Bean
public C anotherA() {
return new C();
}
#Bean
public B evenMoreA() {
return new B();
}
}
This gives you 3 independent instance beans (not a list). For more details, see Java-based container configuration.
Now, Spring will do the job of finding all beans of type A in those packages, and populate your Aggregator class with all three beans correctly.
NOTE: These beans don't need to be in the same file. They can be declared anywhere in your #ComponentScan packages.
As asked in a comment, what if you want to have only some of those instances?
If you want only some of the beans added to your list, the situation is more tricky. You will need to move the excluded beans to a separate #Configuration class, in a different package. You should not add that new package to the Spring #ComponentScan packages, so Spring will not find those beans to add to the list. As far as I know, this is the only way.
Of course, if you want only a single bean, then as usual, you have to autowire it using #Qualifier and specify the bean name. In this case, you don't use a List, just the variable of type A.
Related
If there are two beans of the same type but with different names. Will spring Autowire the bean based on the name without us adding #Qualifier on the variable? I saw in the documentation, "As a fallback Spring uses the bean name as a default qualifier value".
#Component
class A{
}
#Component
class B extends A{
}
class C{
#AutoWired
A a;
//Will a be of type class A, even without #Qualifier...?
}
If there are two beans of the same type but with different names. Will spring Autowire the bean based on the name without us adding #Qualifier on the variable?
#Autowire in the first place cares about type, later about the name. You will get exception saying that there are multiple candidates for injection while only 1 is expected.
#Resource on the other hand, cares about name first, type later.
In this case, B will get injected because there is an A and a B for Spring to choose from and only one of them matches what the #Autowired field is asking for (Class B, because A is not assignable to B).
However, if you had two B's, you would have to qualify it or mark one of them as the primary.
For example, given this:
#Configuration
public class MyConfig {
#Bean
public B example1() {
return new B();
}
#Bean
public B example2() {
return new B();
}
}
Well, now you have two instances of B, with different names. You can fix this one of two ways:
Qualify your Autowire
Note that I'm using field injection here, you really should use constructor, I'm doing it to save space.
#Component
public class SomeComponent {
#Autowired
#Qualifier("example1")
private B b;
}
Or
Mark A Bean as Primary
Redefine the beans, marking one as #Primary
#Configuration
public class MyConfig {
#Bean
#Primary // <-------- NEW!
public B example1() {
return new B();
}
#Bean
public B example2() {
return new B();
}
}
And then inject without needing to name it:
#Component
public class SomeComponent {
#Autowired // (Will pick Primary)
private B b;
}
I've seen one of the program where MyConfig(Spring Configuration file) is being referenced in constructor of one of the bean in order to get other bean defined in MyConfig.
I am not sure about this kind of configuration. I can see cyclic reference in this kind of code, though it is working fine but I am not able to understand the flow. How it is working. Below is the replica of that code -
#Configuration
public class MyConfig {
#Bean(name="a")
#Scope("prototype")
public A getA() {
return new A();
}
#Bean(name="b")
#Scope("prototype")
public B getB() {
return new B();
}
#Bean(name="c")
#Scope("prototype")
public C getC() {
return new C();
}
#Bean(name="queueListener")
#Scope("singleton")
public Queue getQueue() {
return new Queue(MyConfig config);
}
}
Here is my Queue class -
public class Queue implements MessageListener{
private MyConfig config;
public Q(MyConfig config) {
this.config = config;
}
#Override
public void onMessage() {
createC();
}
public void createC() {
C cObj = config.getC();
cObj.setConfig(config);
cObj.performTask();
}
}
The class is "C" look like this-
public class C{
private transient MyConfig config;
private MyConfig config;
public C() {
}
public void setConfig(MyConfig config) {
this.config = config;
}
public MyConfig getConfig() {
return config;
}
public void performTask() {
A a = config.getA(); // Is it right way to get bean?
B b = config.getB();
}
}
So my question is that is it right way to get bean in another bean?
Will the return object really be spring bean object or simple java class object?
I can see cyclic reference in above code cause When instance of Queue class will be created inside MyConfig will take instance/reference of MyConfig.
Will this create cyclic reference?
My Architect has suggested me above approach instead of autoWiring Application context in both classes Queue and class "C". According to architect context is very heavy and it is not best practice.
What will be the execution cycle or call hierarchy when bean Queue is getting created?
It would be very much helpful to understand the working of above code.
It is a really bad idea to inject the configuration instance into a specific bean. It complicates your code and makes it inconvenient for testing because for testing Queue instance you should somehow mock the whole configuration.
If you want to inject a prototype bean to the singleton you can use a technique described here :
Howto generate prototype objects with in a singleton bean using spring java configurations
Please see example at Spring Boot #Autowired creating instances on a runtime
You can see how to use singleton and prototypes right way
In Spring XML, I can define a bean that instantiates a class annotated with #Configuration. When I do, that bean is post-processed. Any methods inside that class with #Bean are also added to the container. How do I perform a similar post-processing in JavaConfig?
Here's the XML version:
<bean id="test" class="com.so.Test">
<property name="prop" value="set before instantiating #Beans defined in Test"/>
</bean>
The associated Test class:
#Configuration
class Test {
private String prop;
void setProp(final String prop) {
this.prop = prop;
}
#Bean
NeedThisBean needThisBeanToo() {
return new NeedThisBean(prop);
}
}
If I use Spring XML Config, both test and needThisBeanToo are available in the container. needThisBeanToo is added via a BeanPostProcessor, though I can't recall which one. If I use JavaConfig, only test is available in the container. How do I make needThisBeanToo available to the container? #Import would work, except that prop being set is required for needThisBeanToo to be initialized correctly.
The part that makes all of this complicated is that Test is vended from a library I'm consuming. I don't control Test, nor can I change it. If I drive it from JavaConfig, it would look like this:
#Configuration
class MyConfiguration
{
#Bean
Test test() {
Test test = new Test();
test.setProp("needed to init `needThisBeanToo` and others");
return test;
}
}
The JavaConfig example does not instantiate needThisBeanToo despite it being defined in Test. I need to get needThisBeanToo defined, preferably without doing it myself, since I don't want to copy code I don't own. Delegation isn't attractive, since there are a number of subsequent annotations/scopes defined on needThisBeanToo (and others defined inside Test).
Your problem is is that you're ignoring the #Configuration annotation completely. Why is that?
When code reaches this line Test test = new Test(); it just doesn't do anything with #Configuration. Why? Because annotation is not something that a constructor is aware of. Annotation only marks some meta-data for the class. When spring loads classes it searches for annotations, when you call a constructor of a class, you don't. So the #Configuration is just ignored because you instantiate Test with new Test() and not through spring.
What you need to do is to import Test as a spring bean. Either via XML as you showed in your question OR using #Import. You problem with prop is that the setter isn't called because that's just not the way to do it. What you need to be doing is either do something like that:
#Configuration
class Test {
private String prop = "set before instantiating #Beans defined in Test";
#Bean
NeedThisBean needThisBeanToo() {
return new NeedThisBean(prop);
}
}
Or to create a property in spring (this is a different subject) and inject the value:
#Configuration
class Test {
#Autowired
#Value("${some.property.to.inject}") // You can also use SPeL syntax with #{... expression ...}
private String prop;
#Bean
NeedThisBean needThisBeanToo() {
return new NeedThisBean(prop);
}
}
You can also create a bean of type String and inject it as follows:
#Configuration
class Test {
#Autowired
#Qualifer("nameOfBeanToInject")
private String prop;
#Bean
NeedThisBean needThisBeanToo() {
return new NeedThisBean(prop);
}
}
In the last case you can define your original MyConfiguration with this bean:
#Configuration
#Import(Test.class)
class MyConfiguration
{
#Bean(name = "nameOfBeanToInject")
String test() {
return "needed to init `needThisBeanToo` and others";
}
}
In any case you have to import Test either using #Import or as a normal XML bean. It won't work by calling the constructor explicitly.
Here's a way to handle vended #Configuration classes that require some properties to be set prior to creating their #Beans:
Vended #Configuration class:
#Configuration
class Test {
private String property;
public setProperty(final String property) {
this.property = property;
}
#Bean
PropertyUser propertyUser() {
return new PropertyUser(property);
}
#Bean
SomeBean someBean() {
// other instantiation logic
return new SomeBeanImpl();
}
}
Here's the consuming #Configuration class:
#Configuration
class MyConfig {
#Bean
static String myProperty() {
// Create myProperty
}
/**
* Extending Test allows Spring JavaConfig to create
* the beans provided by Test. Declaring
* Test as a #Bean does not provide the #Beans defined
* within it.
*/
#Configuration
static class ModifiedTest extends Test {
ModifiedTest() {
this.setProperty(myProperty());
}
#Override
#Bean
SomeBean someBean() {
return new SomeBeanCustomImpl(this.propertyUser());
}
}
Can anyone explain me why a #Bean on a static method is returning 2 different instances ?
I can understand that #Bean on a method non static like the class A is returning the same instance because default scope is singleton.
And If I try to inject the class B with #Autowire in a Service it won't work, so it looks like it's not load by the Spring App Context. So using a class like D will be similar !?
I think not because for #PropertySource we need to use in addition (used for the placeholder):
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
and if we remove #Bean from this, it won't work.
Is there other use case where it would be useful to use #Bean on a static method?
EXAMPLE:
when I run:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {Conf.class})
public class Test {
#org.junit.Test
public void test(){
}
}
for
#Configuration
#ComponentScan
public class Conf {
#Bean
public A aaa(){
return new A();
}
#Bean
public static B bbb(){
return new B();
}
#Bean
#Scope("prototype")
public C ccc(){
return new C();
}
public static D ddd(){
return new D();
}
#PostConstruct
public void post(){
System.out.println(aaa());
System.out.println(aaa());
System.out.println(bbb());
System.out.println(bbb());
System.out.println(ccc());
System.out.println(ccc());
System.out.println(ddd());
System.out.println(ddd());
}
}
public class A {
}
public class B {
}
public class C {
}
public class D {
}
I get:
uk.co.xxx.unit.A#6caf0677
uk.co.xxx.unit.A#6caf0677
uk.co.xxx.unit.B#413d1baf
uk.co.xxx.unit.B#16eb3ea3
uk.co.xxx.unit.C#353352b6
uk.co.xxx.unit.C#4681c175
uk.co.xxx.unit.D#57a78e3
uk.co.xxx.unit.D#402c4085
Because you create a new object for every method call to bbb(). Inter-bean dependencies (if you just call the bean producing method) work in that way, that a proxy is created for your configuration class, and the proxy intercepts method calls to the bean methods to deliver the correct bean (singleton, prototype etc.). However, static methods are not proxied, so when you call the static method, Spring doesn't know about it and you just get the regular Java object. With the PropertySourcesPlaceholderConfigurer it is different, because that method isn't directly called in that class, the bean will only be injected where it is used.
#Bean annotated methods get proxied in order to provide the correct bean instance. Static methods do not get proxied. Hence in your case bbb() invocation each time gives a new instance of B.
PropertySourcesPlaceholderConfigurer class is a special kind of bean since it implements BeanFactoryPostProcessor. In the container lifecycle, a BeanFactoryPostProcessor object must be instantiated earlier than an object of #Configuration-annotated class. Also you don't need to call this static method.
See Bootstrapping section in the java doc : [http://docs.spring.io/spring/docs/4.2.x/javadoc-api/org/springframework/context/annotation/Bean.html][1]
Special consideration must be taken for #Bean methods that return
Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects
must be instantiated very early in the container lifecycle, they can
interfere with processing of annotations such as #Autowired, #Value,
and #PostConstruct within #Configuration classes. To avoid these
lifecycle issues, mark BFPP-returning #Bean methods as static
I came across a situation that I had in another project that I'm not exactly sure the best way to do within Grails. To set it up, this is what I'm doing in a plain Spring project.
I have two classes that inherit from the same interface:
public interface BaseInterface {
void doSomething();
}
public class Impl1 implements BaseInterface {
public void doSomething(){
System.out.println("doing impl 1");
}
}
public class Impl2 implements BaseInterface {
public void doSomething(){
System.out.println("doing impl 2");
}
}
So far pretty standard, I have N beans that I want to call sequentially to do work. (The example is obviously trivial). Within another Java class I can then do some magic to get all the beans injected(autowired) as an array.
#Autowired(required=false)
private BaseInterface[] theWorkers;
This will give me an array of worker beans as long as I have added them to the bean container in the configuration.
Now I'm trying to do the same thing in Grails. The same formula doesn't work. Putting the #Autowired portion in a service, and creating Impl1 and Impl2 within resources.groovy does not seem to do the job. So I'm wondering what the best solution is:
1) I'm missing something simple that will make this work very easily.
2) Do something similar to what's suggested by duffymo here. I'd create a named bean in resources.groovy that used a custom factory. That factory would emit a class that would contain all the classes implementing a certain interface. I'd use something similar to the suggestion to pull the services/classes matching the criteria then have that service allow someone to iterate over it's subclasses to do work.
3) Create a named bean for each of the Impl# classes within resources.groovy and then just use their distinct names and inject all of them into the classes individually. This option would not really scale or give much dynamism, but would work.
If you get access to the Spring application context you can call getBeansOfType which returns all known beans that implement a specified interface or extend a specified base class. So I'd register each bean in resources.groovy but also a manager class that gets a reference to the application context and finds the interface implementations for you. You said you want to call them sequentially, so you should implement the Ordered interface too.
Here's the manager class (put it in src/groovy/ in the correct folder for the package and rename it to whatever you want):
package com.foo
import org.springframework.beans.factory.InitializingBean
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
class BaseInterfaceManager implements ApplicationContextAware, InitializingBean {
ApplicationContext applicationContext
List<BaseInterface> orderedImpls
void afterPropertiesSet() {
orderedImpls = applicationContext.getBeansOfType(BaseInterface).values().sort { it.order }
}
}
Then change the beans so they implement Ordered:
import org.springframework.core.Ordered;
public class Impl1 implements BaseInterface, Ordered {
public void doSomething(){
System.out.println("doing impl 1");
}
public int getOrder() {
return 42;
}
}
and
import org.springframework.core.Ordered;
public class Impl2 implements BaseInterface, Ordered {
public void doSomething(){
System.out.println("doing impl 2");
}
public int getOrder() {
return 666;
}
}
Register all three in resources.groovy (use whatever bean names you want):
beans = {
impl1(Impl1)
impl2(Impl2)
baseInterfaceManager(BaseInterfaceManager)
}
And then you can add a dependency injection in a service or controller or whatever for the baseInterfaceManager bean and use it to loop through the implementation classes in order:
class FooService {
def baseInterfaceManager
void someMethod() {
for (impl in baseInterfaceManager.orderedImpls) {
impl.doSomething()
}
}
}