001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.config;
018
019import java.io.Serializable;
020
021import org.springframework.beans.BeansException;
022import org.springframework.beans.factory.BeanFactory;
023import org.springframework.beans.factory.ObjectFactory;
024import org.springframework.util.Assert;
025
026/**
027 * A {@link org.springframework.beans.factory.FactoryBean} implementation that
028 * returns a value which is an {@link org.springframework.beans.factory.ObjectFactory}
029 * that in turn returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
030 *
031 * <p>As such, this may be used to avoid having a client object directly calling
032 * {@link org.springframework.beans.factory.BeanFactory#getBean(String)} to get
033 * a (typically prototype) bean from a
034 * {@link org.springframework.beans.factory.BeanFactory}, which would be a
035 * violation of the inversion of control principle. Instead, with the use
036 * of this class, the client object can be fed an
037 * {@link org.springframework.beans.factory.ObjectFactory} instance as a
038 * property which directly returns only the one target bean (again, which is
039 * typically a prototype bean).
040 *
041 * <p>A sample config in an XML-based
042 * {@link org.springframework.beans.factory.BeanFactory} might look as follows:
043 *
044 * <pre class="code">&lt;beans&gt;
045 *
046 *   &lt;!-- Prototype bean since we have state --&gt;
047 *   &lt;bean id="myService" class="a.b.c.MyService" scope="prototype"/&gt;
048 *
049 *   &lt;bean id="myServiceFactory"
050 *       class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"&gt;
051 *     &lt;property name="targetBeanName"&gt;&lt;idref local="myService"/&gt;&lt;/property&gt;
052 *   &lt;/bean&gt;
053 *
054 *   &lt;bean id="clientBean" class="a.b.c.MyClientBean"&gt;
055 *     &lt;property name="myServiceFactory" ref="myServiceFactory"/&gt;
056 *   &lt;/bean&gt;
057 *
058 *&lt;/beans&gt;</pre>
059 *
060 * <p>The attendant {@code MyClientBean} class implementation might look
061 * something like this:
062 *
063 * <pre class="code">package a.b.c;
064 *
065 * import org.springframework.beans.factory.ObjectFactory;
066 *
067 * public class MyClientBean {
068 *
069 *   private ObjectFactory&lt;MyService&gt; myServiceFactory;
070 *
071 *   public void setMyServiceFactory(ObjectFactory&lt;MyService&gt; myServiceFactory) {
072 *     this.myServiceFactory = myServiceFactory;
073 *   }
074 *
075 *   public void someBusinessMethod() {
076 *     // get a 'fresh', brand new MyService instance
077 *     MyService service = this.myServiceFactory.getObject();
078 *     // use the service object to effect the business logic...
079 *   }
080 * }</pre>
081 *
082 * <p>An alternate approach to this application of an object creational pattern
083 * would be to use the {@link ServiceLocatorFactoryBean}
084 * to source (prototype) beans. The {@link ServiceLocatorFactoryBean} approach
085 * has the advantage of the fact that one doesn't have to depend on any
086 * Spring-specific interface such as {@link org.springframework.beans.factory.ObjectFactory},
087 * but has the disadvantage of requiring runtime class generation. Please do
088 * consult the {@link ServiceLocatorFactoryBean ServiceLocatorFactoryBean JavaDoc}
089 * for a fuller discussion of this issue.
090 *
091 * @author Colin Sampaleanu
092 * @author Juergen Hoeller
093 * @since 1.0.2
094 * @see org.springframework.beans.factory.ObjectFactory
095 * @see ServiceLocatorFactoryBean
096 */
097public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean<ObjectFactory<Object>> {
098
099        private String targetBeanName;
100
101
102        /**
103         * Set the name of the target bean.
104         * <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
105         * always will be (because if the target bean were a singleton, then said singleton
106         * bean could simply be injected straight into the dependent object, thus obviating
107         * the need for the extra level of indirection afforded by this factory approach).
108         */
109        public void setTargetBeanName(String targetBeanName) {
110                this.targetBeanName = targetBeanName;
111        }
112
113        @Override
114        public void afterPropertiesSet() throws Exception {
115                Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
116                super.afterPropertiesSet();
117        }
118
119
120        @Override
121        public Class<?> getObjectType() {
122                return ObjectFactory.class;
123        }
124
125        @Override
126        protected ObjectFactory<Object> createInstance() {
127                return new TargetBeanObjectFactory(getBeanFactory(), this.targetBeanName);
128        }
129
130
131        /**
132         * Independent inner class - for serialization purposes.
133         */
134        @SuppressWarnings("serial")
135        private static class TargetBeanObjectFactory implements ObjectFactory<Object>, Serializable {
136
137                private final BeanFactory beanFactory;
138
139                private final String targetBeanName;
140
141                public TargetBeanObjectFactory(BeanFactory beanFactory, String targetBeanName) {
142                        this.beanFactory = beanFactory;
143                        this.targetBeanName = targetBeanName;
144                }
145
146                @Override
147                public Object getObject() throws BeansException {
148                        return this.beanFactory.getBean(this.targetBeanName);
149                }
150        }
151
152}