I'm writing an integration test where an application context xml is initialized during startup. There are several test methods in the test class which make use of a specific bean 'X'(already defined in the xml). My actual requirement is to mock bean X only for one of the test methods.
Inside a test method: I tried creating a separate application context using ClassPathXMLApplicationContext with only the mock bean 'M'.
Now I have two Application Contexts (AC):
1. One created during test case startup (which contains the actual bean X) and
2. One created using ClassPathXMLApplicationContext within the test method (which has the mock bean M).
I want to replaced the actual bean definition 'X' within AC:1, using the mock bean definition 'M' from AC:2.
Can somebody throw some light on this please?
You can :
use the Profile annotation if you have spring 3.1.
use the Primary annotation
use qualifiers
wire the bean yourself in the spring context
and i'm sure there are even more options.
There is not a clear way to replace a a bean in a refreshed ApplicationContext unless you close it and refresh it again.
To emulate it, the common approach is to use a Proxy of the bean that you want to replace and change the target at runtime.
You can do it easily using the framework aop support classes:
<bean id="realBean" class="RealClass" />
<bean id="mockBean" class="MockClass" />
<bean id="targetSource" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="realBean" />
</bean>
<bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="targetSource" />
</bean>
#Test
public void testWithMockBean() {
Object real = targetSource.swap(mock);
....
// do your test work
...
targetSource.swap(real);
}
Create a testApplicationContext with
<beans>
<import resource="classpath*:appContext.xml" />
<bean id="mockbeanOfX" class=....../>
</beans>
and then load this test application context in your testcase. Now you can get the mock bean from the application context and pass it whereever needed.
Related
My applicationContext initialization was working fine with Spring 3.2.1.
But when I upgraded to 4.0.9 without changing any code or bean definitions), the initialization got stuck. The following statement kept on happening. There's no obvious circular reference though.
Requested bean is currently in creation: Is there an unresolvable circular reference?
I continued to investigate. I deliberately removed a bean definition.
Spring 3.2.1 had the expected outcome: threw a fatal error almost immediately.
Spring 4.0.9 was still getting into this infinite loop, trying to find a different seed bean definition to make things work.
Here's the log statement that kept on happening.
[factory.support.DefaultListableBeanFactory.getTypeForFactoryBean()] - Ignoring bean creation exception on FactoryBean type check:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'someSeedBean-which-is-different-in-every-instance-of-this-log' defined in the class path resource ........ ;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'someDataSource' is defined
What's changed? Any ideas would be helpful.
Bean definitions that work in both Spring 3.x and 4.x
<bean id="abstractDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" abstract="true" scope="singleton">
<property ....>
</bean>
<bean id="someDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" scope="singleton" parent="abstractDataSource">
<property name="driverClass" .... />
</bean>
<bean id="someSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"> <ref bean="someDataSource" /> </property>
<property name="packagesToScan"> <list>......</list> </property>
....
Bean definitions that work in Spring 3.x but not in 4.0.9.
#Configuration
public class SomeSpringConfiguration{
// Moving this beanDef to Java for features not available in XML
#Bean(destroyMethod = "close")
public DataSource someDataSource() { // also tried setting this to ComboPooledDataSource
// verified that this beanDefinition is recognized by Spring
// but this bean is never created / this method is never executed
...
return datasource;
}
}
<bean class="SomeSpringConfiguration" />
<bean id="someSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource"> <ref bean="someDataSource" /> </property>
<property name="packagesToScan"> <list>......</list> </property>
....
</bean>
Error I get with Spring 4.0.9 is
Cannot resolve reference to bean 'someSessionFactory' while setting constructor argument;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'someSessionFactory':
Requested bean is currently in creation: Is there an unresolvable circular reference?
Please note that the application has thousands of beans defined in/via xml, #Component, and #Configuration. I had to move above bean from xml to a #Configuration class to execute a complicated bean build procedure.
-----------------------UPDATE
I found the issue: 'tons of MethodInvokingFactoryBean[MIB] usages'. For some reason, Spring 4 was getting confused in presence of tons of MIBs. The exact same code base worked fine with Spring 3. I migrated all the logic performed by various MIBs to an ApplicationListener. Please note that ApplicationListener is not an intended replacement for MIBs but in my case I could reproduce the logic in a listener because the MIBs were just performing static injection of Spring beans into classes not managed by Spring. It not only fixed this issue but decreased Spring startup time to ~200 seconds from ~300 seconds.
Unfortunately, I neither could figure out the root cause in Spring nor could reproduce the issue in a smaller code-base (to share here).
Remove
<bean class="SomeSpringConfiguration" />
from XML, it's already annotated with #Configuration. If it's being scanned it's likely the beans in it are getting created twice. You should move everything into Javaconfig.
Circular references are common during development, when you have a lot of beans and are not careful when you autowire them together. The stacktrace should contain the complete list of beans, telling you where the circular reference starts and ends.
I have never seen random circular references (and I encountered circular references many times over the last 7 years)! As far as I know, the code that builds the dependency tree and instantiates/wire the beans is deterministic. So you should always get the same circular reference every time you run. If you don't, I can only thing of two reasons
There is a bug in the Spring version you are using (I'm 99% sure there is a unit test for this)
You have one of more beans that starts a thread as part of bean instantiation, and the thread uses the applicationContext to load another bean lazily (while the context is still loading).
When I teach Spring classes, I recommend that constructors should only contain field assignments, if you need to start threads (or anything else with a lifecycle) you should use the lifecycle methods. Personally I prefer to implement SmartLifeCycle (over InitializingBean/DisposableBean, #PostConstruct/#PreDestroy), since this ensures that nothing will started until after all beans have been instantiated and wired together.
The core of it is as Strelok says, you are mixing annotations and xml config.
The point of the #Configuration annotation is to avoid xml. When you added the component scan for the package after removing SomeSpringConfiguration from xml.
You would start to create multiples of someDataSource, because it is defined in multiple places (#Bean annotation, and in xml).
Please avoid mixing annotations and xml, only use one of them and stick to that, and this problem will, if not resolved but at least much easier to spot.
If you can create an example project and upload it somewhere I can take a closer look if you are still having this issue.
We have upgraded Spring WebFlow from 1 to 2.4.1. Now we need to rewrite all of our Unit tests. One issue is stopping us dead in our tracks. Most of our flows still import action beans and forms, as we are still using XML configurations. In addition, all of the action beans inherit configuration via an abstract bean reference in the webflow configuration file. So we have the following bean reference in our webflowContext.xml:
<bean id="serviceInjected" abstract="true">
<property name="serviceLocator" ref="serviceLocator"/>
<property name="misAssembler" ref="misAssembler"/>
<property name="formObjectScope" value="FLOW"/>
</bean>
All of the Action beans thus inherit the serviceLocator, misAssembler and formObjectScope. When I try to unit test the flows, the tests fails because there is no "serviceInjected" bean reference. So my question is:: How can we insert bean configuration inheritance into the test before we attempt to start the flow. Using configureFlowBuilderContext will not work as this change the ApplicationContext and not the ExternalContext. I have only seen one other reference to this on the internet and that question was not answered, so here is hoping I have better luck.
I am using an external library that requires that I configure it using an XML Bean definition; in the Bean definition I need to provide an external class with a Bean from my project. I am using spring annotations with component scanning.
How do I reference my annotated Bean within the XML Bean Definition?
Are there any alternatives to creating an XML Bean Definition?
Details: Spring 3.0.7
No matter how it got created (based on XML- or annotation- metadata), every bean ends up in the application context under a unique name.
If you've just annotated your class with #Component or derivatives, without stating any name, the default naming scheme will be applied and the bean name will be your class name with the first character lowercased: ClassName => "className".
With that in mind, if you need to inject that bean in an XML bean definition, you do it like with any other bean in your context:
<bean id="someBean" class="SomeClass">
<property name="someProp" ref="className"/><!-- to stick to the above example -->
</bean>
Since you're mixing annotations with XML, the application context will be able to locate the "className" bean properly.
The #Service annotation takes an optional String value which can be used to give the bean a name of your choosing. For example, if your custom bean looks like:
#Service("mySpecialName")
public class MyClass { ... }
Then your xml could have:
<bean class="com.someone.else.library.SomeClass">
<property name="someProp" ref="mySpecialName"/>
</bean>
Make sure add below code in your xml file
<context:component-scan base-package="" />
<context:annotation-config />
I wonder how can I properly inject a prototype bean to a singleton one in a web app. Consider this example:
<bean id="order" class="com.foo.Order" scope="prototype"/>
<bean id="orderService" class="com.foo.OrderService">
<property name="userPreferences" ref="userPreferences"/>
</bean>
I thought of using getBean() but isn't that a way to make my code dependent to spring itself?
I need a short java code example to demonstrate how to inject an order bean in my OrderService singleton.
Thanks
You can use jsr-330 Providers, just put:
#Autowired
Provider<Order> orderProvider;
in your singleton bean, and then use the provider:
public Whatever yourMethod() {
Order order = orderProvider.get();
}
I want to declare two beans and instantiate them using Spring dependency injection?
<bean id="sessionFactory" class="SessionFactoryImpl">
<property name="entityInterceptor" ref="entityInterceptor"/>
</bean>
<bean id="entityInterceptor" class="EntityInterceptorImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
But Spring throws an exception saying "FactoryBean which is currently in creation returned null from getObject"
Why is inter-dependent bean wiring not working here? Should i specify defferred property binding anywhere?
Unfortunately the way container initialization works in Spring, a bean can only be injected in another bean once it is fully initialized. In your case you have a circular dependency that prevents either bean to be initialized because they depend on each other. To get around this you can implement BeanFactoryAware in one of the beans and obtain the reference to the other bean using beanFactory.getBean("beanName").
neesh is right, Spring doesn't do this out of the box.
Interdependent beans hint at a design problem. The "clean" way to do this is to redesign your services in such a way that there are no such odd dependencies, of course provided that you have control over the implementations.
You can implement a BeanPostProcessor that sets the dependency.
Or...
See Costin's reply here:
http://forum.springframework.org/showthread.php?t=19569&highlight=circular+dependencies
See Andreas' reply here:
http://forum.springframework.org/showthread.php?t=29572&highlight=circular+dependencies
you can extend the ApplicactionContext that are using and override the method createBeanFactory()
protected DefaultListableBeanFactory createBeanFactory(){
DefaultListableBeanFactory beanFactory = super.createBeanFactory();
// By default this is false;
beanFactory.setAllowRawInjectionDespiteWrapping( true );
return beanFactory;
}
This works, but be careful because this allows circular references.