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.
Related
I have a piece of Spring AOP advice which is not triggering when the auth(..) method is called:
#AfterReturning(pointcut="execution(* auth(..))",
returning="result")
public void trigger(final Boolean result) {
System.out.println("I was triggered " + result);
}
This is because the Authenticator object with the Auth method is not a Spring bean, but it is created by a factory which is a Spring bean:
<bean id="passwordUserAuthFact" class="foo.bar.PasswordAuthFactory">
...
</bean>
<bean id="server" class="foo.bar.Server">
<property name="authFactory" ref="passwordUserAuthFact"/>
...
</bean>
So when the application does:
session.authenticator = server.getAuthFactory().create();
... session.authenticator is an unproxied plain PasswordAuthFactory, and AOP isn't going to happen on it.
It seems to me that it should be possible to tell Spring about beans which are factories, so that it can wrap the factory in a proxy, such that objects returned by create() are themselves wrapped in an AOP proxy.
That is, Spring would dynamically create a wrapper around my factory like this:
public Foo create() {
Foo instance = target.create();
return wrapWithAopProxy(instance);
}
But I can't see a ready-made way to do that.
I would prefer not to make my classes Spring-aware. The factory class itself is third-party, so I would prefer a solution in which I don't change its source.
Is there a common pattern to achieve this? Or a better approach to the problem?
You main alternative, would be to go with programmatic aspect definition since you cannot play with the sources.
Implement a new authentication factory decorator that wraps your old authentication factory. The former would mainly delegate authenticator creation to the latter, then wraps the returned object with a ProxyBean and register the needed advice(s).
Sprig enables these beans to be loosely coupled and the authenticator POJO a non-managed bean. In below samples, I only aim to provide a glance view on how this can be done leaving implementation details up to your application:
Here down a fake Authenticator:
public class Authenticator
{
private String name;
public Authenticator( String name )
{
this.name = name;
}
public void authenticate( Object subject )
{
System.out.println( subject + " is being authenticated by: " + name );
}
}
Supposing that your AuthFactory interface looks like below:
public interface AuthFactory
{
Authenticator create();
}
It's legacy implementation, the one providing non managed authentication is as follows:
public class AuthenticationFactory implements AuthFactory
{
#Override
public Authenticator create()
{
return new Authenticator("mocked-authenticator");
}
}
Create a new MethodInterceptor (note that you may need aopalliance dependency) that encapsulates your advice logic:
public class AuthenticationAdvise implements MethodInterceptor
{
#Override
public Object invoke( MethodInvocation methodInvocation ) throws Throwable
{
System.out.println("Before invocation..."); // Your advice logic goes here
return methodInvocation.proceed();
}
}
Create a new authentication provider decorator, which will be a Spring managed bean:
public class AuthenticationFactoryDecorator implements AuthFactory {
private AuthFactory authenticationFactoryDelegate;
private MethodInterceptor interceptor;
public AuthenticationFactoryDecorator( final AuthFactory authenticationFactoryDelegate, final MethodInterceptor interceptor )
{
this.authenticationFactoryDelegate = authenticationFactoryDelegate;
this.interceptor = interceptor;
}
#Override
public Authenticator create()
{
// Create the needed pointcut
NameMatchMethodPointcut pc = new NameMatchMethodPointcut();
pc.addMethodName("authenticate");
// Get an authenticator from your legacy class
Authenticator auth = authenticationFactoryDelegate.create();
// Create a new Proxy wrapping your authFactory with the needed pointcut and advice
ProxyFactory proxyFactory = new ProxyFactory(auth);
proxyFactory.addAdvice(interceptor);
return (Authenticator) proxyFactory.getProxy();
}
}
Register the new AuthFactory bean as a Spring component and wire it with your advice and legacy factory beans (e.g. beans.xml):
<?xml version="1.0" encoding="UTF-8"?>
<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="legacyAuthFactory" class="some.package.AuthenticationFactory"/>
<bean id="interceptor" class="some.package.AuthenticationFactoryAdvise"/>
<bean id="authFactory" class="some.package.AuthenticationFactoryDecorator">
<constructor-arg name="authenticationFactoryDelegate" ref="legacyAuthFactory"/>
<constructor-arg name="interceptor" ref="interceptor"/>
</bean>
</beans>
Now your are free to pull the authFactory bean from the Spring Application Context and use it to instantiate new authenticator objects:
public class MainAuthentication
{
public static void main( String[] args )
{
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:META-INF/beans.xml");
AuthFactory factory = applicationContext.getBean("authFactory", AuthFactory.class);
Authenticator authenticator = factory.create();
authenticator.authenticate(new MockSubject());
}
private static class MockSubject
{
#Override
public String toString() {
return "MockSubject";
}
}
}
Executing below main class, note that you are dealing with a new proxied authenticator instance which is wrapped with your advice logic, as the output shows:
Before invocation...
MockSubject is being authenticated!!!
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
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.