Correct way to get beans from applicationContext Spring - java

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

Related

Invoke a one-time (static) initialization in a prototype spring bean

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?

initializing my factory through spring

Can I have a factory as follows?
public class Factory
{
private static Map<EnumXyz, IDAO> map = new HashMap<Sting, Object>();
public static void init()
{
//how do i initialize my map through spring initialization
}
public static IDAO getDAO(EnumXyz dao)
{
if (map.containsKey(dao))
return map.get(dao);
else
{
throw new IllegalArgumentException("dao not supported " + dao);
}
return null;
}
}
How do I take care of the initialization of my factory through spring?
Is this way of building a factory correct?
Any other, better approach?
Don't make everything static, especially not the init() method.
Annotate your bean with #Component
Annotate your init() method with #PostConstruct.
Now the init() method is called when Spring constructs your Factory class, providing it a hook to initialize itself.
I would instantiate your factory as a bean itself, and have an instance of it - don't make everything static. Spring itself can control whether your bean is a singleton (it will default as such).
e.g.
public class Factory {
public Factory(final Map<String,Object} map) {
this.map = map;
}
}
and your Spring config:
<bean id="myFactory" class="Factory">
<constructor-arg>
<util:map>
<!-- configure your map here, or reference it as a separate bean -->
<entry key="java.lang.String" value="key">....</entry>
</util:map>
</constructor-arg>
</bean>
In your constructor, pass in the map which is defined itself in your Spring config.

Get servletcontext for factory class in spring

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

Spring FactoryBean and scopes working together

I'd like to use FactoryBeans and scopes together. Specifically, I'd like the object created and returned by a FactoryBean to be placed into a specified (perhaps custom) scope. The issue is that doing the following:
<bean class="x.y.z.TestFactoryBean" scope="test" />
Results in the FactoryBean itself being scoped, and has somewhat unpredictable behaviour on the object created by the factory. I understand why this is; the factory itself is a first-class spring-managed bean, and has its own lifecycle. However, I can't find a way to specify that the object returned from the factory should itself be scoped.
On the other hand, this does exactly what I want (as long as TestFactoryBean does NOT implement the FactoryBean interface):
<bean class="x.y.z.TestFactoryBean" name="testFactory">
<bean class="x.y.z.TestBean" factory-bean="testFactory"
factory-method="getObject" scope="test" />
So the real question is, how can I make Spring behave like it does for the 2nd example above, but using real FactoryBeans?
You can't easily use a custom scope on a bean returned from a FactoryBean.
From Spring's Java documentation:
FactoryBeans can support singletons and prototypes
If you want the FactoryBean's returned bean to have the prototype scope, then you must implement the isSingleton() method like this:
public class TestFactoryBean implements FactoryBean<TestBean> {
// the rest of the required methods are removed for simplicity reasons..
public boolean isSingleton() {
return false;
}
}
To support a custom scope, you have to implement the logic yourself and it will not be very intuitive, since the FactoryBean only provides the isSingleton() method. I will rather recommend using another solution than FactoryBean for beans with custom scope.
Hope this helps!
I solved the same issue using custom holder bean.
Factory bean:
#Component
#Configurable()
public class EventBusFactory implements FactoryBean<EventBus> {
#Override
public EventBus getObject() throws Exception {
return new SimpleEventBus();
}
#Override
public Class<?> getObjectType() {
return EventBus.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
Bean holder:
#Configurable
#Component
#Scope("session")
public class EventBusHolder {
#Autowired
private EventBus eventBus;
public EventBus getEventBus() {
return eventBus;
}
public void setEventBus(EventBus eventBus) {
this.eventBus = eventBus;
}
}
And then I use holder instead of the required entity.
#Component
#Configurable
#Scope("session")
public class UicPlaceController extends PlaceController {
#Autowired
public UicPlaceController(EventBusHolder eventBus) {
super(eventBus.getEventBus());
}
...
}
The solution looks a little bit ugly, but still, it solves the issue.

Automatic dynamic binding in spring

I am using spring MVC and would like to expose default validator for javascript to use.
I have a bunch of controllers extending a common abstract class and bunch of validators implementing a common interface. The situation is something like this:
public abstract class AbstractController {
protected Validator validator;
}
public class FooController extends AbstractController{}
public class BarController extends AbstractController{}
public interface Validator {}
public class FooValidator implementes Validator{}
public class BarValidator implementes Validator{}
I would like to automatically set the validator field for each concrete controller respectivelly (so that FooController.validator would be instance of FooValidator).
The matching should be done by class names automatically.
You could create a BeanPostProcessor to do this and register it in the application context. The post processor could look for AbstractController instances with the proper naming convention, generate the validator name, instantiate the validator object via reflection, and set it in the controller. Something like this:
public Object postProcessAfterInitialization(final Object bean, final String name) throws BeansException {
if (bean instanceof AbstractController) {
String controllerName = bean.getClass().getSimpleName();
if(controllerName.endsWith("Controller")) {
String validatorName = controllerName.replaceFirst("Controller$", "Validator");
try {
Class<?> validatorClass = Class.forName(validatorName);
Validator validator = (Validator)validatorClass.newInstance();
((AbstractController)bean).setValidator(validator);
} catch(Exception e) {
throw new FatalBeanException("Cannot instantiate validator", e);
}
}
}
return bean;
}
Alternatively, if the validators are registered as Spring beans because they need dependency injection or whatever, you could create a BeanFactoryPostProcessor (not a BeanPostProcessor) that finds all the controller bean definitions by type or name, then looks up matching validator bean definitions by type or name, and adds the matching validator to the property list of each controller bean. I don't have sample code for that, but hopefully you get the idea.
Couldn't you use something like this in your configuration:
<bean id="abstractControllerTemplate" abstract="true">
<property name="validator" ref="myFormValidator"/>
</bean>
...
<bean id="someOtherConcreteController" class="com.myproj.controllers.SomeOtherConcreteController" parent="abstractControllerTemplate">
<!-- other properties specific to this controller -->
</bean>

Categories