/* * Copyright 2002-2007 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.config; import org.springframework.beans.BeansException; import org.springframework.beans.factory.ObjectFactory; import org.springframework.util.Assert; /** * A {@link org.springframework.beans.factory.FactoryBean} implementation that * returns a value which is an {@link org.springframework.beans.factory.ObjectFactory} * that in turn returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}. * * <p>As such, this may be used to avoid having a client object directly calling * {@link org.springframework.beans.factory.BeanFactory#getBean(String)} to get * a (typically prototype) bean from a * {@link org.springframework.beans.factory.BeanFactory}, which would be a * violation of the inversion of control principle. Instead, with the use * of this class, the client object can be fed an * {@link org.springframework.beans.factory.ObjectFactory} instance as a * property which directly returns only the one target bean (again, which is * typically a prototype bean). * * <p>A sample config in an XML-based * {@link org.springframework.beans.factory.BeanFactory} might look as follows: * * <pre class="code"><beans> * * <!-- Prototype bean since we have state --> * <bean id="myService" class="a.b.c.MyService" singleton="false"/> * * <bean id="myServiceFactory" * class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"> * <property name="targetBeanName"><idref local="myService"/></property> * </bean> * * <bean id="clientBean" class="a.b.c.MyClientBean"> * <property name="myServiceFactory" ref="myServiceFactory"/> * </bean> * *</beans></pre> * * <p>The attendant <code>MyClientBean</code> class implementation might look * something like this: * * <pre class="code">package a.b.c; * * import org.springframework.beans.factory.ObjectFactory; * * public class MyClientBean { * * private ObjectFactory myServiceFactory; * * public void setMyServiceFactory(ObjectFactory myServiceFactory) { * this.myServiceFactory = myServiceFactory; * } * * public void someBusinessMethod() { * // get a 'fresh', brand new MyService instance * MyService service = this.myServiceFactory.getObject(); * // use the service object to effect the business logic... * } * }</pre> * * <p>An alternate approach to this application of an object creational pattern * would be to use the {@link ServiceLocatorFactoryBean} * to source (prototype) beans. The {@link ServiceLocatorFactoryBean} approach * has the advantage of the fact that one doesn't have to depend on any * Spring-specific interface such as {@link org.springframework.beans.factory.ObjectFactory}, * but has the disadvantage of requiring runtime class generation. Please do * consult the {@link ServiceLocatorFactoryBean ServiceLocatorFactoryBean JavaDoc} * for a fuller discussion of this issue. * * @author Colin Sampaleanu * @author Juergen Hoeller * @since 1.0.2 * @see org.springframework.beans.factory.ObjectFactory * @see ServiceLocatorFactoryBean */ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean { private String targetBeanName; /** * Set the name of the target bean. * <p>The target does not <i>have</> to be a prototype bean, but realisticially * always will be (because if the target bean were a singleton, then said * singleton bean could simply be injected straight into the dependent object, * thus obviating the need for the extra level of indirection afforded by * the approach encapsulated by this class). Please note that no exception * will be thrown if the supplied <code>targetBeanName</code> does not * reference a prototype bean. */ public void setTargetBeanName(String targetBeanName) { this.targetBeanName = targetBeanName; } public void afterPropertiesSet() throws Exception { Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required"); super.afterPropertiesSet(); } public Class getObjectType() { return ObjectFactory.class; } protected Object createInstance() { return new ObjectFactory() { public Object getObject() throws BeansException { return getTargetBean(targetBeanName); } }; } /** * Template method for obtaining a target bean instance. * Called by the exposed ObjectFactory's <code>getObject()</code> method. * @param targetBeanName the name of the target bean * @return the target bean instance */ protected Object getTargetBean(String targetBeanName) { return getBeanFactory().getBean(targetBeanName); } }