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
Related
I am new to Spring. I have at work in spring-config.xml this :
<bean id="statusEmailSender" class="my.package.email.StatusEmailSenderImpl">
<property name="mailSender" ref="mailSender"/>
<property name="templateMessage" ref="templateMessage"/>
</bean>
In some classes already defined I see something like this:
#Autowired
private StatusEmailSender statusEmailSender;
And it works. When I do it in my own class, I get a NullPointerException.
I know the reason: I am creating my class with new():
return new EmailAction(config,logger);
My class looks like this:
public class EmailAction{
#Autowired
StatusEmailSender statusEmailSender;
public EmailAction(...)
{
...
}
}
Do you know how I can get around this? This is legacy code, and it's extremely difficult to get around the new EmailAction() call.
You want use a spring bean inside a non-spring class(legacy code). In order to do that you need to make the Spring's ApplicationContext (which holds BeanFactory where spring beans are residing) available to legacy code.
For that you need to create a spring bean something like:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
and define this bean inside your Spring configuration file (or if you are using annotation driven, annotate bean with #Component)
<bean id="springContext" class="com.util.SpringContext />
Since SpringContext exposes a static method, the legacy code can access it.for example if the legacy code needs spring bean EmailAction, call like:
EmailAction emailAction= (EmailAction)SpringContext.getApplicationContext.getBean(EmailAction.class);
now the emailAction will contain all its dependencies set.
Why don't you just autowire your EmailAction class when you need it?
EmailAction.java:
#Component
public class EmailAction{
// ...
}
WhereYouNeedIt.java:
public class WhereYouNeedIt{
#Autowired
EmailAction emailAction;
// access emailAction here
}
In my jsp, I have a custom tag
<ex:SelfService />
which intrun calls the java class
public class SelfServiceClass extends SimpleTagSupport{
#Autowired
private ReloadablePropertyManagerImpl reloadableProperty;
public ReloadablePropertyManagerImpl getReloadableProperty() {
return reloadableProperty;
}
public void setReloadableProperty(
ReloadablePropertyManagerImpl reloadableProperty) {
this.reloadableProperty = reloadableProperty;
}
public void doTag() throws IOException {
JspWriter out = getJspContext().getOut();
out.println(getReloadableProperty().getPropertyValue("print.service"));
}
}
And in my spring.xml I have configured the bean,
<bean id="reloadableProperty" class="com.testing.portal.util.ReloadablePropertyManagerImpl" />
But I am getting null pointer exception when I call getPropertyValue() on reloadableProperty object.
Any help will be much appreciated.
Since your class is not managed by Spring you have to load the ReloadablePropertyManagerImpl from the application context by yourself. In order to do so you should create a class which implements ApplicationContextAware with a static getter for the context.
See more in this sample.
Is Spring aware of SelfServiceClass class? It has to be. You either annotate it with #Component or it is returned by a #Configuration as a #Bean or include it as you did with reloadebleProperty in the xml, i.e.: make it a spring managed bean
From this Q/A: How to define a List bean in Spring? I know I can define a List<Foo> fooList filled with Foo bean instances but using XML configuration. Here's an example:
public interface Foo {
//methods here...
void fooMethod();
}
#Service("foo")
#Scope("prototype")
public class FooImpl implements Foo {
//fields and methods...
#Override
public void fooMethod() {
//...
}
}
#Service("fooCache")
#Scope
public class FooCacheImpl implements Foo {
//fields and methods...
#Override
public void fooMethod() {
//retrieves data from some cache
//...
}
}
#Service("fooWS")
#Scope("prototype")
public class FooWSImpl implements Foo {
//fields and methods...
#Override
public void fooMethod() {
//retrieves data from web service
//...
}
}
I can configure a client through XML:
<bean id="fooClient" class="some.package.FooClient">
<property name="fooList">
<list>
<bean ... /> <!-- This may be fooImpl -->
<bean ... /> <!-- This may be fooCacheImpl -->
<bean ... /> <!-- This may be fooWSImpl -->
<!-- I can have more beans here -->
</list>
</property>
</bean>
I want to know if this can be done with annotations only, no need to define the bean through XML. Something like this:
#Component
#Scope("prototype")
public class FooClient {
//which annotation(s) to use here to fill this list with FooImpl instances?
//I understand that if I have two implementations of Foo I may use a #Qualifier
//or use another list to note the different implementations.
private List<Foo> fooList;
public void bar() {
for (Foo foo : fooList) {
foo.fooMethod();
}
}
}
I think it would be better a solution that doesn't involve injecting the ApplicationContext nor the BeanFactory so FooClient is not tightly coupled to Spring classes. Also, for my case, I cannot use any Java EE classes like javax.inject.Provider as shown in this blog post: Spring 2.5.x+3.0.x: Create prototype instances from code.
What about using a Factory Bean?
I know you mentioned you did not want to be too coupled to spring - with a factory bean your bean containing the list is not so coupled - just your factory is.
Something like
#Component("fooList")
class ListFactory<List<Foo>> implements FactoryBean, ApplicationContextAware {
ApplicationContext context;
public List<Foo>> getObject() {
List<Foo> list = new ArrayList();
list.add(context.getBean("foo");
list.add(context.getBean("foo");
return list;
}
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
public boolean isSingleton() {
return false;
}
}
#Component
#Scope("prototype")
class FooClient {
#Inject
#Named("footList")
private List<Foo> fooList;
public void bar() {
for (Foo foo : fooList) {
foo.fooMethod();
}
}
}
Haven't tried it myself, or had the scenario where I've needed it so I'm not sure it will work.
If you're doing it in the code directly, then I think using the PostConstruct annotation would be the way to go:
#Component
#Scope("prototype")
public class FooClient {
....
#PostConstruct
public void init() throws Exception {
fooList = new ArrayList<Foo>();
fooList.add(new FooImpl());
}
I think using this approach would be more flexible, since I think you will struggle with annotations only if the FooImpl objects themselves require additional configuration.
That's a limitation (or feature) of prototype scope. The docs say this
In contrast to the other scopes, Spring does not manage the complete
lifecycle of a prototype bean: the container instantiates, configures,
and otherwise assembles a prototype object, and hands it to the
client, with no further record of that prototype instance.
So after Spring hands it off to you, it doesn't keep any reference to it and therefore cannot autowire any of them into your fooList. If you did add #Autowired
#Autowired
private List<Foo> fooList;
it would just create a new FooImpl object and autowire that as the single element in your List.
If you're trying to keep a reference of all the Foo instances created, you'll most likely have to do it yourself.
You can use method injection as this:
public class PrototypeClient {
protected abstract PrototypeBean createPrototype();
private List<PrototypeBean> createPrototypeList() {
int listSize = calculateListSize();
List<Prototype> result = new ArrayList<Prototype(listSize);
for (int i = 0; i < listSize; i++) {
result.add(createPrototype());
}
return result;
}
private int calculateListSize() {
// do your stuff here
}
// ...
}
and have an Spring config as:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="prototypeBean"
class="fully.qualified.class.name.of.Prototype"
scope="prototype" />
<bean id="prototyeClient"
class="fully.qualified.class.name.of.PrototypeClient">
<lookup-method name="createPrototype" bean="prototypeBean"/>
</bean>
</beans>
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.
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