I am using spring for quite some time but this morning I came across with some unexpected behavior. As I could not decide by myself whether that was a desired functionality or a bug I am presenting it here with the hope I will get some good explanations about why would this be happening.
In short I have multiple beans defined in an application context and I create two map beans using utils:map name space with only part of my beans added to those maps. The two maps have exactly the same entries.
Then I auto wire those maps. One auto wire is done using @Autowired
annotation and the other one is done using @Resource
To my surprise the bean annotated with @Autowired
had got all beans in the context not only the ones I specifically put in the map. The other one auto wired using @Resource
annotation had only the expected two entries in it.
I am mainly interested in:
1. Why all the beans declared in my context of that time appear in the @Autowired
map and not the ones I added
2. Why @Resource
and @Autowired
would behave differently
Here is the working code that reproduces the scenario described above.
Some interface here:
package my.testing.pkg;
public interface Foo {
void doStuff();
}
And its implementation:
package my.testing.pkg;
public class FooImpl implements Foo {
@Override
public void doStuff() {}
}
The spring config file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:utils="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="foo_1" class="my.testing.pkg.FooImpl"/>
<bean id="foo_2" class="my.testing.pkg.FooImpl"/>
<bean id="foo_3" class="my.testing.pkg.FooImpl"/>
<bean id="foo_4" class="my.testing.pkg.FooImpl"/>
<utils:map id="fooMap1" map-class="java.util.HashMap">
<entry key="foo_1" value-ref="foo_1"/>
<entry key="foo_2" value-ref="foo_2"/>
</utils:map>
<utils:map id="fooMap2" map-class="java.util.HashMap">
<entry key="foo_1" value-ref="foo_1"/>
<entry key="foo_2" value-ref="foo_2"/>
</utils:map>
</beans>
And the test case to reproduce the behavior:
package my.testing.pkg;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.Map;
import static org.junit.Assert.assertEquals;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/test-context.xml")
public class SpringMapCreatingTest {
@Autowired
private Map<String, Foo> fooMap1;
@Resource
private Map<String, Foo> fooMap2;
@Test
public void shouldInjectATwoEntriesMap() throws Exception {
assertEquals("fooMap1 should have to entries", 2, fooMap1.size());
assertEquals("fooMap2 map should have to entries", 2, fooMap1.size());
}
}
Thank you in advance for your clarifications.