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