How to use the same bean in two different spring contexts? - spring

I have two spring contexts and I need to use the same bean in both of them. Is there a way to share a bean between two contexts without making a parent context?

I don't think what you want is a good idea. If you have the same bean in two contexts, then which context manages the bean's lifecycle? By having a common parent owning the bean, you have a clear, unambiguous answer to that important question: the bean belongs to the parent context.
Now, if you know the beans will belong to context A and only want to bind them to some name in context B, I guess you could hack some kind of "guest" bean factory or whatever, that does something like:
Java:
public class GuestBeanFactory {
private ApplicationContext guestBeanContext;
#Inject
public void setGuestBeanContext(ApplicationContext guestBeanContext) {
this.guestBeanContext = guestBeanContext;
}
private String guestBeanName;
#Inject
public void setGuestBeanName(String guestBeanName) {
this.guestBeanName = guestBeanName;
}
public Object getBean() {
return guestBeanContext.getBean(guestBeanName);
}
}
applicationContext.xml:
<beans ...>
...
<bean id="myGuestFactory" class="GuestBeanFactory" scope="singleton">
<property name="guestBeanContext" ref="...get a reference to the guest bean and inject it here" />
<property name="guestBeanName" value="name-of-this-bean-inside-guestBeanContext"/>
</bean>
<bean id="myGuestBean" factory-bean="myGuestFactory" factory-method="getBean"/>
...
</beans>
This way, guestBeanContext manages name-of-this-bean-inside-guestBeanContext, but the "host" context can access that bean using the name myGuestBean.

Related

How can I create the spring bean after all other beans?

For example, I have 3 beans in my spring configuration: A, B, C. And I want to create bean B and C as usual. And than (when all others beans were created) I want to ask spring to create bean A.
Any suggestion ?
Thanks.
Spring framework triggers a ContextRefreshedEvent once the contexts has been fully refreshed and all the configured beans have been created.
You could try to create a listener to catch that event and initialise bean A.
#Component
public class ContextRefreshedEventListener implements
ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
// Init your bean here
}
}
You should try #DependsOn adnotation
For example
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
I know it's not really a bean ordering answer, but maybe you can achieve your goal with a #PostConstruct method that will be called just after a bean is constructed, dependencies are injected and all properties are set.
best nas
Easier way to do this would be using #Lazy annotation to your bean. This makes your bean do not get initialized eagerly during context initialization. In simple words,your bean will get created when you ask for it, not before.
#Bean
#Lazy
public A beanA() {
//some code here
}

Constructor injection in Spring

I'm working on a code where a class A is constructing an object of class B using parameterized constructor of class B. As of now, class B is not yet spring injected. The requirement is that I should always have a new non-singleton object of class B. The code somewhat looks like this:
class A{
private List<ClassB> classBList = new ArrayList<ClassB>();
void parseInfo(File f, Element e){
ClassB b = new ClassB(this,f,e);
classBList.add(b);
}
}
How should my spring-config look like if i have to inject class B using spring?
Define the bean as prototype
<!-- A bean definition with singleton scope -->
<bean id="classBBean" class="ClassB" scope="prototype"/>
Use applicationContext getBean method to create bean each time by passing arguments.
class A implements ApplicationContextAware{
private List<ClassB> classBList = new ArrayList<ClassB>();
#Autowired
private ApplicationContext appContext;
void parseInfo(File f, Element e){
ClassB b = (ClassB)appContext.getBean("classBBean",new Object[]{this,f,e});
classBList.add(b);
}
}
If I understand correctly, you are asking about Spring scopes
Basically, you need to declare your bean with scope prototype if it's a general spring application
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="prototype">
<!-- collaborators and configuration for this bean go here -->
</bean>
or request, if it's a web spring application
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="request">
<!-- collaborators and configuration for this bean go here -->
</bean>
For more examples look at
http://www.tutorialspoint.com/spring/spring_bean_scopes.htm

Is default constructor required in Spring injection?

I'm trying to inject a constructor that takes some arguments. After compiling Spring complains it couldn't find a default constructor (I haven't defined it) and throws BeanInstatiationException and NoSuchMethodException.
After defining a default constructor the exceptions don't appear anymore, however my object is never initialized with the argument constructor, only the default one is called. Does Spring really require a default constructor in this case? And if yes, how can I make it use the argument constructor instead of the default one?
This is how I wire everything:
public class Servlet {
#Autowired
private Module module;
(code that uses module...)
}
#Component
public class Module {
public Module(String arg) {}
...
}
Bean configuration:
<beans>
<bean id="module" class="com.client.Module">
<constructor-arg type="java.lang.String" index="0">
<value>Text</value>
</constructor-arg>
</bean>
...
</beans>
Stack trace:
WARNING: Could not get url for /javax/servlet/resources/j2ee_web_services_1_1.xsd
ERROR initWebApplicationContext, Context initialization failed
[tomcat:launch] org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'module' defined in URL [...]: Instantiation of bean failed;
nested exception is org.springframework.beans.BeanInstantiationException: Could not
instantiate bean class [com.client.Module]: No default constructor found; nested
exception is java.lang.NoSuchMethodException: com.client.Module.<init>()
Spring only "requires" a default constructor if you plan on instantiating it without any arguments.
for example, if your class is like this;
public class MyClass {
private String something;
public MyClass(String something) {
this.something = something;
}
public void setSomething(String something) {
this.something = something;
}
}
and you set it up in Spring like this;
<bean id="myClass" class="foo.bar.MyClass">
<property name="something" value="hello"/>
</bean>
you're going to get an error. the reason is that Spring instantiates your class new MyClass() then tries to set call setSomething(..).
so instead, the Spring xml should look like this;
<bean id="myClass" class="foo.bar.MyClass">
<constructor-arg value="hello"/>
</bean>
so have a look at your com.client.Module and see how its configured in your Spring xml
Most probably you are using component-scanning and since you define annotation #Component for class Module it tries to instantiate the bean. You do not need #Component annotation if You are using XML for bean definition.
Just faced the same problem, i guess till now you might have solved the problem.
Below is what you could have changed your bean configuration to,
<bean id="module" class="com.client.Module">
<constructor-arg value="Text"/>
</bean>

Possibilities of resolving backing beans in JSF and Spring

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

Session object's autowired properties do not autowire if the session object is declared <aop:scoped-proxy>

Session object's autowired properties do not autowire if the session object is declared
<bean id="user" class="org.User" scope="session">
<aop:scoped-proxy/>
</bean>
The user objects proerty is #autowired but the property doesn't get autowired.
public class User
{
TemplateService templateService;
#Autowired
public void setTemplateService(TemplateService templateService) {
this.templateService = templateService;
}
}
I wonder why this is so.
Is replacing the autowire annotations with xml declarations the only solution. Are there any other solutions?
Thanks

Resources