A prototypical portion of an application context:
<bean id="option_A" class="class_a" lazy-init="true"/>
<bean id="option_B" class="class_b" lazy-init="true" depends-on="setup_bean"/>
<alias name="option_${OPTION_PROPERTY}" alias="thingChosen"/>
<bean id="setup_bean" class="class_setup" lazy-init="true"/>
The concept here is that if OPTION_PROPERTY is set to "A", then
<bean id="foo" class="whatever"><property name="bar" ref="thingChosen"/></bean>
will get an instance of class_a injected into the bar property, and if the property is set to "B", then it will get an instance of class b injected, but class b has a hidden dependency on setup_bean (which class a lacks), so setup_bean must be created first.
What is happening is that if OPTION_PROPERTY is set to "A", then setup_bean is still created. I've tried this using Spring 3.2.4.RELEASE, and it's consistent. This seems like either a bug or a misunderstanding on my part.
If a bean is lazy-init, then shouldn't depends-on beans wait until that bean is lazily created before being created themselves?
If a bean is lazy-init, then shouldn't depends-on beans wait until
that bean is lazily created before being created themselves?
Yes. In other words option_B will not be created until setup_bean is requested and initialized. If option_B is requested first, then that will force setup_bean to be initialized first.
The documentation says
However, when a lazy-initialized bean is a dependency of a singleton
bean that is not lazy-initialized, the ApplicationContext creates the
lazy-initialized bean at startup, because it must satisfy the
singleton's dependencies.
Therefore, this bean declaration
<bean id="foo" class="whatever"><property name="bar" ref="thingChosen"/></bean>
will force the initialization of thingChosen, which in this case is aliasing option_A.
I cannot reproduce what you are experiencing (and should not). Double check what you are doing. Maybe another bean is referencing setup_bean.
Here's an SSCCE
public class Test {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
System.out.println("context initialized");
context.getBean("shouldnot");
}
public static class MyClass {
public MyClass() {
System.out.println("myclass");
}
}
public static class SetupBean {
public SetupBean() {
System.out.println("setup");
}
}
public static class MyOtherClass {
private MyClass myClass;
public MyOtherClass() {
System.out.println("myotherclass");
}
public MyClass getMyClass() {
return myClass;
}
public void setMyClass(MyClass myClass) {
this.myClass = myClass;
}
}
}
and spring.xml beans
<bean id="myref" class="test.Test$MyClass" lazy-init="true"></bean>
<bean id="shouldnot" class="test.Test$MyClass" lazy-init="true" depends-on="setup_bean"></bean>
<bean class="test.Test$MyOtherClass" >
<property name="myClass" ref="myref"></property>
</bean>
<bean id="setup_bean" class="test.Test$SetupBean" lazy-init="true"></bean>
it prints (minus Spring logs)
myotherclass
myclass
context initialized
setup
myclass
In other words, setup is only created when shouldnot is requested.
It turns out that elsewhere in the context, there's this little gem:
<context:annotation-config />
This, it appears, results in lazy-init being ignored.
Trying to figure out how the exclusion machinery works is the next step, but is out-of-scope for this question.
Related
This may looks like a duplicate of this question. But this is different.
I was trying to refactor my legacy code by using method injection in spring.
I have a bean class which contains many static helper methods. My targeted method as follows:
Context.java
private static MessageSender messageSender;
//...
public static MessageSender getMessageSender(){
return messageSender;
}
Context bean
<bean id="context" class="org.abc.Context">
<property name="messageSender"><ref bean="mailMessageSender"/></property>
</bean>
MailMessageSender.java
public abstract class MailMessageSender{
protected abstract Session createSession();
//using createSession() somewhere in this class
}
MailMessageSender bean
<bean id="session" class="javax.mail.Session" scope="prototype" />
<bean id="mailMessageSender" class="org.abc.MailMessageSender">
<lookup-method name="createSession" bean="session"/>
</bean>
I'm getting invalid property error when I'm installing the project.
You can't inject static field, change your variable in Context.java become like this:
private MessageSender messageSender;
//...
public MessageSender getMessageSender(){
return messageSender;
}
I am working on this Spring MVC project where I have trouble getting this Dao class auto wired in the controller through an Interface that is implemented by the Dao. This is portion of my spring-config.xml. I am using aspectJ, Annotation and TX management.
<aop:aspectj-autoproxy />
<context:component-scan base-package="com.simulator" />
<context:annotation-config />
<tx:annotation-driven />
<context:property-placeholder
location="classpath*:config.properties" />
<bean id="oidDao" class="com.simulator.service.OidDao">
<property name="ipaddressNC" value="${ipaddressNC}" />
<property name="ipaddressOM" value="${ipaddressOM}" />
</bean>
Dao class:
#Component
public class OidDao implements OidManager {
#Autowired
private SessionFactory sessionFactory;
private String ipaddressNC;
private String ipaddressOM;
public String getIpaddressNC() {
return this.ipaddressNC;
}
public void setIpaddressNC(String ipaddressNC) {
this.ipaddressNC = ipaddressNC;
}
public String getIpaddressOM() {
return ipaddressOM;
}
public void setIpaddressOM(String ipaddressOM) {
this.ipaddressOM = ipaddressOM;
}
OidManager:
public interface OidManager {
public String getIpaddressNC();
public String getIpaddressOM();
}
Controller:
#Controller
public class HomeController {
#Autowired
OidManager oim;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String indexpage(ModelMap modelMap) {
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"spring-config.xml"});
o = (OidManager)context.getBean("oidDao");
o.getIpaddressNC(); // ---> this returns data read from ext properties file and works fine
oim.getIpaddressNC(); // ---> this returns null`
I am trying to re-use the Dao, hence I dont want to call the ApplicationContext multiple times from each method. What am I doing wrong? If I make the variables getIpaddressNC, getIpaddressOM static, then auto wiring works, if not oim returns null though the variables are initialized via setters on application load.
You used both Component Scanning and Manual Wiring for OidDao. You defined oidDao in xml config, as follows:
<bean id="oidDao" class="com.simulator.service.OidDao">
<property name="ipaddressNC" value="${ipaddressNC}" />
<property name="ipaddressOM" value="${ipaddressOM}" />
</bean>
Then, added a Component annotation on OidDao, as follows:
#Component
public class OidDao implements OidManager {
...
}
Drop the Component annotation and you'll be fine, i guess! Because otherwise, <context:component-scan base-package="com.simulator" /> will pick OidDao and instantiate an instance from it with default constructor and without calling your setters.
You are using #Component annotation + you have also defined a bean. Therefore actually two beans are created. One created due to use of #Component would have the properties set to 'null'. This is expected since you are not setting the properties to any value. Either remove #Component annotation and use 'autowire-candidate="true"' property on bean definition or else remove the bean definition in XML and use relevant annotation on the class to set properties to correct values from property file.
Change your bean definition to:
<bean id="oim" class="com.simulator.service.OidDao">
<property name="ipaddressNC" value="${ipaddressNC}" />
<property name="ipaddressOM" value="${ipaddressOM}" />
</bean>
Let this create bean with id oim which can be set to the property oim in your Controller.
I currently have the following Spring bean definitions:
<bean id="myAwesomeBeanSetup" class="com.beanpckg.SuperBean" scope="singleton" init-method="doPreStep"/>
<bean id="myAwesomeBean" class="com.beanpckg.SuperBean" scope="prototype" depends-on="myAwesomeBeanSetup"/>
Essentially, what I need is to run SuperBean.doPreStep only once, but still have a fresh instance of SuperBean for subsequent calls. Since I have a lot of beans with such structure, I was wondering, is there a more elegant way to achieve this without having two lines of definitions? Note that there could also be "cross-bean" dependencies, for example:
<bean id="myAwesomeBeanSetup" class="com.beanpckg.SuperBean" scope="singleton" init-method="doPreStep"/>
<bean id="myAwesomeBean2Setup" class="com.beanpckg.SuperBean2" scope="singleton" init-method="doPreStep"/>
<bean id="myAwesomeBean" class="com.beanpckg.SuperBean" scope="prototype" depends-on="myAwesomeBeanSetup,myAwesomeBean2Setup"/>
You can put your code in the static initialization block as following:
public class SuperBean {
// …
static {
doPreStep();
}
public static void doPreStep() {
}
}
Alternatively, if you want a pure Spring solution, you can implement a FactoryBean and invoke the doPreStep() in its init method as following:
public class SuperFactoryBean implements FactoryBean<SuperBean>{
public void init() {
SuperBean.doPreStep();
}
public boolean isSingleton() {
return false;
}
public SuperBean getObject(){
return new SuperBean();
}
public Class<SuperBean> getObjectType() {
return SuperBean.class ;
}
}
And define your bean as following:
<bean id="myAwesomeBean" class="com.beanpckg.SuperFactoryBean" init-method="init">
</bean>
Depending what you want to achieve within your awesome superclass:
For me this would be the perfect usecase of having a separate singleton with the common code and autowire it into your prototype.
Since your init will not be different per bean why having it in a superclass?
I have a factory that creates instances:
public class myFactory {
public static getInstace() {
switch(someInt) {
case 1:
return new MySpringBean();
case 2:
return new MyOtherSpringBean();
}
}
}
I need to return a new instance of the beans that are "managed" by Spring bc they have Transactional business logic methods. I have read in many posts here that I should not use getBean method to get a singleton or a new instance from the applicationContext. But I cannot find the proper way to do it for my case. I have used #Resource and it seems to work but it doesn't support static fields.
Thanx
There are many ways to achieve this in spring, the most obvious way given the factory class that you have is to use JavaConfig. If you used the spring enabled JavaConfig annotations you could do the following to construct your beans and add them to the application context:
#Configuration
public class myFactory {
#Bean
public static getInstance() {
switch(someInt) {
case 1:
return new MySpringBean();
case 2:
return new MyOtherSpringBean();
}
}
}
One way is create a factory class and store the instances of the beans (each implementing a common interface MyBean) as values under some key in a map (beans):
public class MyBeanFactory {
private Map<Integer, MyBean> beans;
public MyBean create(Integer which) {
if (which != null)
return beans.get(which);
else
throw new IllegalArgumentException("Unknown bean");
}
public void setBeans(Map<Integer, MyBean> beans) {
this.beans = beans;
}
}
In your Spring applicationContext.xml now create bean a of the factory and set the beans:
<beans...>
<bean id="myBeanFactory" class="foo.bar.MyBeanFactory">
<property name="beans">
<map>
<entry key="1">
<bean class="foo.bar.MyBeanA" />
</entry>
<entry key="2">
<bean class="foo.bar.MyBeanB" />
</entry>
</map>
</property>
</bean>
</beans>
Finally you can inject your bean factory as usual and get instances from like e.g. this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/applicationContext.xml" })
public class MyBeanFactoryTest {
#Autowired
private MyBeanFactory myBeanFactory;
#Test
public void test() {
Assert.assertTrue(myBeanFactory.create(1) instanceof MyBeanA);
Assert.assertTrue(myBeanFactory.create(2) instanceof MyBeanB);
}
}
You implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.
The FactoryBean interface is a point of pluggability into the Spring IoC container's instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.
The FactoryBean interface provides three methods:
Object getObject(): returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.
boolean isSingleton(): returns true if this FactoryBean returns singletons, false otherwise.
Class getObjectType(): returns the object type returned by the getObject() method or null if the type is not known in advance
Take a look at Spring Docs
I want to create Factory Class. for example is FooFactory. before Foo instanced, FooFacoty must be injected ServletContext to the constructor. I have snippet as follows:
public class FooFactory() {
public static Foo getFoo() {
ctx = //getservlet context
Foo foo = new Foo(ctx);
return foo;
}
}
EDIT: You can use ServletContextFactoryBean. You can then pass a reference to this into your factory (e.g. as a method argument.). Like this
<bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean"/>
<bean id="foo" class="FooFactory" factory-method="getFoo">
<constructor-arg index="0" ref="servletContext"/>
</bean>
You then change FooFactory.getFoo to
public static Foo getFoo(ServletContext ctx) {
Foo foo = new Foo(ctx);
return foo;
}
There is no direct way that I know of, but you can do it indirectly by implementing ServletContextAware or ApplicationContextAware.
This article describes the details.
I came across this post on my search for how to do this very thing. It helped me as a starting point, but since ServletContextFactoryBean is deprecated in Spring 3, I had to try something different.
I found two options:
#Autowired
public AnAutowiredConstructor(WebApplicationContext webApplicationContext)
{
servletContext = webApplicationContext.getServletContext();
}
Or you can implement org.springframework.web.context.ServletContextAware.
public class SomeClass implements ServletContextAware
{
public void setServletContext(ServletContext servletContext)
{
}
}
You can directly inject the instance of ServletContext which is kept by the Spring WebApplicationContext into you bean using xml:
<bean id="myBean" class="foo.bar.SomeClass">
<constructor-arg ref="servletContext"/>
Indeed the servlet context is registered in the application context as "servletContext". See http://docs.spring.io/spring/docs/4.0.x/javadoc-api/org/springframework/web/context/WebApplicationContext.html#SERVLET_CONTEXT_BEAN_NAME. Also works with Spring 3.x