Why is there a need to specify the class in both the xml file and in the getBean() method in Spring - spring

This might be an obvious but I'm having a hard time understanding why we need to define the class of a bean in two places....
From the spring reference manual...
...
<bean id="petStore"
class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
// retrieve configured instance
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
Shouldn't the xml fine be enough for the container to know the class of petStore?

You can use the following method:
context.getBean("petStore")
However, as this returns a java.lang.Object, you'd still need to have a cast:
PetStoreServiceImpl petstore = (PetStoreServiceImpl)context.getBean("petStore");
However, this could lead to problems if your "petStore" bean is not actually a PetStoreServiceImpl, and to avoid casts (which since the advent of Generics are being seen as a bit dirty), you can use the above method to infer the type (and let's spring check whether the bean you're expecting is really of the right class, so hence you've got:
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
Hope that helps.
EDIT:
Personally, I would avoid calling context.getBean() to lookup methods as it goes against the idea of dependency injection. Really, the component that uses the petstore bean should have a property, which can then be injected with the correct component.
private PetStoreService petStoreService;
// setter omitted for brevity
public void someotherMethod() {
// no need for calling getBean()
petStoreService.somePetstoreMethod();
}
Then you can hook up the beans in the application context:
You could also do away with the configuration via XML and use annotation to wire up your beans:
#Autowired
private PetStoreService petStoreService;
As long as you've got
in your spring context, the "petStore" bean defined in your application context will automatically be injected. If you've got more than one bean with the type "PetStoreService", then you'd need to add a qualifier:
#Autowired
#Qualifier("petStore")
private PetStoreService petStoreService;

There's no requirement to specify the class in the getBean() method. It's just a question of safety. Note there's also a getBean() that takes only a class so that you can just look up beans by type instead of needing to know the name.

Related

How to override a Spring #Autowire annotation and set a field to null?

I am a Spring neophyte who is working on a large Spring-based project that has extensive coupling between Spring beans. I am trying to write some integration tests that exercise subsets of the total application functionality. To do so, I'd like to override some of the autowiring.
For example, suppose I have a class
public class MyDataServiceImpl implements MyDataService {
#Qualifier("notNeededForMyDataServiceTest")
#Autowired
private NotNeededForMyDataServiceTest notNeededForMyDataServiceTest;
//...
}
and a context file with:
<bean id="myDataService"
class="MyDataServiceImpl">
</bean>
In my test, I have no need to use the notNeededForMyDataServiceTest field. Is there some way I can override the #Autowired annotation and set notNeededForMyDataServiceTest to null, perhaps in the XML file? I don't want to modify any of the Java classes, but I do want to avoid the (problematic) configuration of notNeededForMyDataServiceTest.
I tried doing:
<bean id="myDataService"
class="MyDataServiceImpl">
<property name="notNeededForMyDataServiceTest"><null/></property>
</bean>
That doesn't work. IntelliJ informs me "Cannot resolve property 'notNeededForMyDataServiceTest'", apparently because there are no getters and setters for that field.
I'm using Spring Framework 3.1.3.
The following configuration should work, I took the liberty of mixing in Java configuration
#Configuration
//This will load your beans from whichever xml file you are using
#ImportResource("classpath:/path/beans.xml")
public class TestConfigLoader{
// This will declare the unused bean and inject MyDataServiceImpl with null.
public #Bean(name="notNeededForMyDataServiceTest") NotNeededForMyDataServiceTest getNotNeededForMyDataServiceTest(){
return null;
}
... any other configuration beans if required.
}
And annotate your test class like so:
// In your test class applicationContext will be loaded from TestConfigLoader
#ContextConfiguration(classes = {TestConfigLoader.class})
public class MyTest {
// class body...
}
These could help:
Context configuration with annotated classes
Testing with #Configuration Classes and Profiles
Spring TestContext Framework
and profiles:
beans profile="..."
Introducing #Profile
You could create different beans definition in the XML configuration and then activate them using the -Dspring.profiles.active="profile1,profile2" env.
You're using the #Autowired mechanism wrong. The qualifier is not a property that you need to set. That's actually the name of a bean, so that the container will be able to choose one particular instance in case multiple beans of the same type are defined in the same context.
So the container will look for a bean of type NotNeededForMyDataServiceTest and the name (which would actually be the bean id in XML): notNeededForMyDataServiceTest.
What I think you want is to instruct the container to not inject anything in that field if no bean of type NotNeededForMyDataServiceTest is defined in the application context. That could be achieved simply by setting the required attribute of the annotation to false:
#Autowired(required = false)
NotNeededForMyDataServiceTest someOptionalDependency;
The only drawback of this approach would be that the container will never complain at runtime if there's nothing to inject in that field (and perhaps you would want this sanity check when your code runs in production).
If you don't want to make that dependency optional (or you can't edit that code for some reason), you'll need to provide a mock / null value for that field by setting that explicitly in your context. One option to do that would be to use Java configuration instead of XML (like in #Abe's answer) and another approach would be to make use of a factory bean which returns null (like in this question).

How to know if the wiring for a bean is complete with autowiring?

I have a bean with autowired beans.
So something like:
class A
{
#Autowired
B b;
#Autowired
C c;
void function()
{
// here I would like to do something when I an sure the wiring has been done
// being sure that I won't wait forever
...
Something has to exist, but I can't find it.
Thanks for your help!
You can annotate your 'function' method with #PostConstruct and specify <context:annotation-config/> in your spring config XML. Then, function will only be invoked after autowiring, so you could check in function whether your beans have been injected successfully.
A classic way to achieve this is to implement InitializingBean:
Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory: for example, to perform custom initialization, or merely to check that all mandatory properties have been set.
An alternative to implementing InitializingBean is specifying a custom init-method, for example in an XML bean definition. For a list of all bean lifecycle methods, see the BeanFactory javadocs.
I also suggest reading other answers:
How to call a method after bean initialization is complete?
What is the difference between BeanPostProcessor and init/destroy method in Spring?
If you are using default scope for beans that is singleton, then autowiring will always be done at the application startup only. If wiring for any field fails, then spring container will throw an exception and the application will not start properly. So, if the control of code is in your method , it means wiring has already been done.

Make a bean unautowireable or that disposes of it self?

We need a spring bean that will either
Prevent the framework from #Autowired -ing it.
or
Once it does its work it destroys itself?
The bean roughly looks like this:
public final class Registrar implements ApplicationListener<SOFrameworkInitializedEvent>
So after it receives this 1 time event do the work and go away. We are using Spring 3.0.7.
Use the autowire-candidate property in the bean definition XML, e.g.:
<bean id="MyBean" class="com.acme.SimpleTestServiceImpl" autowire-candidate="false"/>

Spring AOP - Error Generating proxies

I'm using spring AOP's around advice to capture processing time of a transaction. I'm getting the following error during application startup
error creating bean "coreMessageResourceAccesor"
Could not generate CGLIB subclass of class
[class org.springframework.context.support.MessageSourceAccessor]:
Common causes of this problem include using a final class or a non-visible class;
nested exception is java.lang.IllegalArgumentException:
Superclass has no null constructors but no arguments were given
I identified what the problem is with the help of this thread. But I cannot change coreMessageResourceAccesor bean to use setter based injection because its using a spring class & that class doesn't have no arg constructor
Below is the configuration for the bean
<bean id="coreMessageSourceAccessor"
class="org.springframework.context.support.MessageSourceAccessor" >
<constructor-arg type="org.springframework.context.MessageSource"
ref="coreMessageSource" />
</bean>
I would really appreciate if someone could help. Thanks for your time.
You don't need really need to configure MessageSourceAccessor accessor as a bean, it's generally easier to instantiate it manually as required. So rather than inject the MessageSourceAccessor into your beans, inject the raw MessageSource, and then wrap it in a MessageSourceAccessor as required (i.e. using new MessageSourceAccessor(messageSource)).
You can then put the advice around the MessageSource rather than the MessageSourceAccessor, which will work better. Also, MessageSourceAccessor will not itself add any significant processing time, it's just a thin wrapper around MessageSource.

Accessing legacy out-of-container instantiated objects from Spring beans

We have a legacy system where something like a Service Locator is used to instantiate and provide all service objects:
class ServiceLocator {
ServiceA serviceA;
ServiceB serviceB;
public ServiceLocator () {
serviceA = ...;
serviceB = ...;
}
public ServiceA getServiceA() {
return serviceA;
}
public ServiceB getServiceB() {
return serviceB;
}
}
(imagine 70 more fields and getters...)
This object is then passed around from class to class to provide access to the service objects.
It is outside the scope of the project to change this design for existing code, but to at least not make things worse, we would like to introduce Spring to progressively instantiate future services with DI similar to Introducing an IoC Container to Legacy Code.
In contrast to the aforementioned situation, we already know how we will access the spring created spring bean objects from our legacy code. Our problem are objects we plan to create with spring, that need any of the service objects created outside of the spring context.
We came up with the following solution:
Create a static accessor for the ServiceLocator and set it in the constructor, load the spring application context object. In the spring configuration create a bean for the ServiceLocator with the static accessor as described in Section 3.3.2.2 in the Spring reference:
<bean id="serviceLocator"
class="ServiceLocator"
factory-method="getInstance"/>
for each Service create another bean using "instance factory method" as described in Section 3.3.2.3:
<bean id="serviceA"
factory-bean="serviceLocator"
factory-method="getServiceA"/>
Create other beans referencing these "dummy beans".
I guess this would work, but creates a lot of seamingly unnessessary pseudo configuration. What I'd rather like is something like this:
"If a bean is referenced and that bean is not explicitly defined, search for a method with the needed signature and name in the ServiceLocator class and use this object."
Is it possible to do so? Are there any entry points into the spring bean instantiation process that I am not aware of and that can be used here? Can I do this by subclassing the spring application context class?
Any help would be greatly appreciated!
You can define a BeanFactoryPostProcessor to populate your application context with beans from ServiceLocator.
In BeanFactoryPostProcessor, use beanFactory.registerSingleton(...) to add a fully instantiated bean, or ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(...) to add a definition (note that some application contexts may not implement BeanDefinitionRegistry, though all typical contexts implement it).

Resources