According to this section of Spring Framework Reference documentation, when autowire-candidate is set to false in a bean's XML definition, it excludes the bean from the autowiring infrastructure. The section doesn't talk about any exceptions to this case.
This works when autowire is set to byType. But when it is set to byName, the autowire-candidate="false" configuration is ignored and the bean is still autowired.
My question is:
Is this by design and not documented (or)
Is it a bug (or)
Am I missing something in my configuration?
Following is the list of relevant source listings:
MovieDataStore.java
public class MovieDataStore {
// Just some dummy class
}
MovieDao.java
public class MovieDao {
private MovieDataStore movieDataStore;
public MovieDataStore getMovieDataStore() {
return movieDataStore;
}
public void setMovieDataStore(MovieDataStore movieDataStore) {
this.movieDataStore = movieDataStore;
}
}
spring-context.xml snippet
<bean id="movieDao" class="com.example.spring.MovieDao" autowire="byName"/>
<bean id="movieDataStore" class="com.example.spring.MovieDataStore"
autowire-candidate="false"/>
Testing code
ClassPathXmlApplicationContext ctx;
ctx = new ClassPathXmlApplicationContext("spring-context.xml");
MovieDao movieDao = ctx.getBean("movieDao", MovieDao.class);
System.out.println(movieDao.getMovieDataStore());
ctx.close();
I am expecting it to print null because the only dependency that I asked to autowire is actually excluded from autowiring. But, the above testing code prints this:
com.example.spring.MovieDataStore#22915056
Note that this happens only in case of autowire byName. If I autowire byType, it prints null as expected.
I am using Spring Framework version 4.3.5.RELEASE and Java 7.
According to this Spring JIRA ticket which I raised, it is by design and not documented.
Comment from Juergen Hoeller on the ticket:
This is an old design decision where autowire-candidate="false" only affects type-based autowiring attempts, not direct references by name... and not autowire="byName" either. While the latter may be debatable, I'm not inclined to change it at this point since autowire="byName" is an outdated mechanism to begin with. I'm therefore turning this into a documentation issue.
Related
I have a question around the usage of new keyword being used when using java configuration in spring. What is the need of using new keyword
Refer below mentioned example:
Code implemented using Java Config
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
The above code will be equivalent to the following XML configuration
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
In XML config, we do not use new keyword whereas in java config we are using new keyword. can someone please explain the difference
In the XML configuration, you explain to the system what class should be instanciated (there is a "new" but it is behind the scene) but in the Java Config you actually have to return an instance so that is why we use the 'new' keyword. 'new' simply creates an instance of your class.
The two examples shown in question are not really equivalent.
What the
<beans>
<bean id="helloWorld"
class="com.test.HelloWorld" />
</beans>
really does, is it tells Spring to instantiate class com.test.HelloWorld, and name the resulting bean "helloWorld".
Then the java-config approach is not really doing this. Instead this follows the factory-method pattern, when we tell Spring, that the return value of the method is the bean, and the method name is the name of that bean.
An equivalent of that in XML would be the mentioned factory-method approach, which in this case would look something like this:
<beans>
<bean id="helloWorldConfig"
class="com.test.HelloWorldConfig" />
<bean id="helloWorld"
factory-bean="helloWorldConfig"
factory-method="helloWorld" />
</beans>
Note that there are several approaches to factory-method. In the above, we are assuming, the `helloWorldConfig" is the factory, and we're specifying the method on that bean. Theare are cases with static factory methods too. See here for more examples.
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
This XML configurations tells Spring to "create an instance of com.test.HelloWorld and put it in the bean context with bean id helloWorld".
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
In this Java configuration, we are returning an instance of com.test.HelloWorld. Because of the #Bean annotation, this instance is put into the bean context. As no specific bean id is given, the bean id is derived from the method hellowWorld() and thus becomes helloWorld.
As you can see, both configurations require an instance of com.test.HelloWorld. The XML configuration implicitly creates the instance whereas in the Java configuration you have to explicitly do it yourself.
I am new to Spring and working on a project which is consisting of Spring in it .
It has got this piece of code inside the xml file
<bean id="quotClient" class="com..at.client.QuoteClient" scope="singleton" />
<bean id="streamClient" class="com.at.client.StreamClient" scope="singleton" />
And inside the java class it has got this piece of code
#Autowired
#Qualifier("streamClient")
private StreamClient sclient;
#Autowired
#Qualifier("quotClient")
private QuoteClient quotesClient;
public void setQuotesClient(QuoteClient quotesClient) {
this.quotesClient = quotesClient;
}
Please let me know why there is no method by name set for the StreamClient class , but which has got corresponding set method for QuoteClient .
Since you're using annotation driven Autowiring of the beans you don't need any setters for injunction (these are set by using reflection). Even setQuotesClient isn't needed by Spring DI framework to inject those 2 bean instances.
PS: From spring version 3.0, you can start using #Inject instead of #Autowired.
Check: How does Spring #Autowired work
i think that setter method wrote by mistake.
remove that setter and test the application. it should work.
I am beginner to spring, ESP Inversion of control. I was puzzled understanding the difference between the following
<bean id="demo" class="Demo" lazy-init="false"/>
<bean id="demo" class="Demo" lazy-init="true"/>
<bean id="demo" class="Demo" lazy-init="default"/>
To my understanding : lazy-init=false creates the bean at the startup and lazy-init=true doesn't create a bean at the startup rather creates the bean upon request for a particular bean.
Correct me here, If my interpretation is wrong.
what exactly the default behavior of lazy-init is? How would it instantiate?
The default behaviour is false:
By default, ApplicationContext implementations eagerly create and
configure all singleton beans as part of the initialization process.
Generally, this pre-instantiation is desirable, because errors in the
configuration or surrounding environment are discovered immediately,
as opposed to hours or even days later. When this behavior is not
desirable, you can prevent pre-instantiation of a singleton bean by
marking the bean definition as lazy-initialized. A lazy-initialized
bean tells the IoC container to create a bean instance when it is
first requested, rather than at startup.
I suggest reading up
For those coming here and are using Java config you can set the Bean to lazy-init using annotations like this:
In the configuration class:
#Configuration
// #Lazy - For all Beans to load lazily
public class AppConf {
#Bean
#Lazy
public Demo demo() {
return new Demo();
}
}
For component scanning and auto-wiring:
#Component
#Lazy
public class Demo {
....
....
}
#Component
public class B {
#Autowired
#Lazy // If this is not here, Demo will still get eagerly instantiated to satisfy this request.
private Demo demo;
.......
}
The lazy-init="default" setting on a bean only refers to what is set by the default-lazy-init attribute of the enclosing beans element. The implicit default value of default-lazy-init is false.
If there is no lazy-init attribute specified on a bean, it's always eagerly instantiated.
lazy-init is the attribute of bean. The values of lazy-init can be true and false. If lazy-init is true, then that bean will be initialized when a request is made to bean. This bean will not be initialized when the spring container is initialized
and
if lazy-init is false then the bean will be initialized with the spring container initialization.
When we use lazy-init="default" as an attribute in element, the container picks up the value specified by default-lazy-init="true|false" attribute of element and uses it as lazy-init="true|false".
If default-lazy-init attribute is not present in element than lazy-init="default" in element will behave as if lazy-init-"false".
I use org.springframework.web.jsf.el.SpringBeanFacesELResolver in my JSF + Spring application. Every backing bean needs an interface to be resolved. I guess that it's interface type of dependency injection.
#{bean.text}
public interface IBean {
String getText();
}
#Named
#Scope("session")
public class Bean implements IBean {
public String getText() {
return "Hello World!";
}
}
I would like to get rid of the interface. It's kind of bureaucracy for me. Is it possible?
I finally solved it. The problem was in beans with scope depending on HTTP (request, session). By default interfaces should be manually created. This can be avoided by using proxies.
If using component scan:
<context:component-scan base-package="..." scoped-proxy="targetClass" />
Or in bean definition:
<bean ...>
<aop:scoped-proxy>
</bean>
See chapter 4.5.4.5 Scoped beans as dependencies in Spring documentation. http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html
I have following code inside my class
public void startListeners() throws Exception {
List<QueueConfiguration> queueConfigs = queueConfigResolver.getQueueConfigurations();
for(QueueConfiguration queueConfig : queueConfigs){
//TODO : work on this make it more testable
ICustomListener readerListener = new MyCustomListener(queueConfig);
readerListeners.add(readerListener);
readerListener.start();
}
}
I am using Spring for dependency injection(not in this case but overall). Now there two problems with this code.
I cannot put mock for each of the listeners created, while testing.
I dont want to use ApplicationContext.getBean() because it will have same affect. AFAIK spring cannot do this dynamically , but any other pointers?
As far as I can understand, you want to create a new bean instead of
ICustomListener readerListener = new MyCustomListener(queueConfig);
If that is the case, creating a factory for mycustomlistener and using
public abstract TestClient createTestClient();
to create your beans, and defining
<bean id="testClient" class="com.myproject.testbeans.TestClient" scope="prototype">
</bean>
<bean id="testClientFactory" class="com.myproject.testbeans.TestClientFactory">
<lookup-method name="createTestClient" bean="testClient" />
</bean>
in your context will solve your problem. This way, every time the createTestClient method of the factory is called, a new bean is created and given to your code. However, you have to give the config object via a setter instead of the constructor.