001/*
002 * Copyright 2002-2016 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.support;
018
019import java.lang.reflect.AnnotatedElement;
020import java.lang.reflect.Member;
021import java.lang.reflect.Method;
022import java.util.HashSet;
023import java.util.Set;
024
025import org.springframework.beans.MutablePropertyValues;
026import org.springframework.beans.factory.config.BeanDefinition;
027import org.springframework.beans.factory.config.BeanDefinitionHolder;
028import org.springframework.beans.factory.config.ConstructorArgumentValues;
029import org.springframework.core.ResolvableType;
030import org.springframework.util.Assert;
031
032/**
033 * A root bean definition represents the merged bean definition that backs
034 * a specific bean in a Spring BeanFactory at runtime. It might have been created
035 * from multiple original bean definitions that inherit from each other,
036 * typically registered as {@link GenericBeanDefinition GenericBeanDefinitions}.
037 * A root bean definition is essentially the 'unified' bean definition view at runtime.
038 *
039 * <p>Root bean definitions may also be used for registering individual bean definitions
040 * in the configuration phase. However, since Spring 2.5, the preferred way to register
041 * bean definitions programmatically is the {@link GenericBeanDefinition} class.
042 * GenericBeanDefinition has the advantage that it allows to dynamically define
043 * parent dependencies, not 'hard-coding' the role as a root bean definition.
044 *
045 * @author Rod Johnson
046 * @author Juergen Hoeller
047 * @see GenericBeanDefinition
048 * @see ChildBeanDefinition
049 */
050@SuppressWarnings("serial")
051public class RootBeanDefinition extends AbstractBeanDefinition {
052
053        private BeanDefinitionHolder decoratedDefinition;
054
055        private AnnotatedElement qualifiedElement;
056
057        boolean allowCaching = true;
058
059        boolean isFactoryMethodUnique = false;
060
061        volatile ResolvableType targetType;
062
063        /** Package-visible field for caching the determined Class of a given bean definition */
064        volatile Class<?> resolvedTargetType;
065
066        /** Package-visible field for caching the return type of a generically typed factory method */
067        volatile ResolvableType factoryMethodReturnType;
068
069        /** Common lock for the four constructor fields below */
070        final Object constructorArgumentLock = new Object();
071
072        /** Package-visible field for caching the resolved constructor or factory method */
073        Object resolvedConstructorOrFactoryMethod;
074
075        /** Package-visible field that marks the constructor arguments as resolved */
076        boolean constructorArgumentsResolved = false;
077
078        /** Package-visible field for caching fully resolved constructor arguments */
079        Object[] resolvedConstructorArguments;
080
081        /** Package-visible field for caching partly prepared constructor arguments */
082        Object[] preparedConstructorArguments;
083
084        /** Common lock for the two post-processing fields below */
085        final Object postProcessingLock = new Object();
086
087        /** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied */
088        boolean postProcessed = false;
089
090        /** Package-visible field that indicates a before-instantiation post-processor having kicked in */
091        volatile Boolean beforeInstantiationResolved;
092
093        private Set<Member> externallyManagedConfigMembers;
094
095        private Set<String> externallyManagedInitMethods;
096
097        private Set<String> externallyManagedDestroyMethods;
098
099
100        /**
101         * Create a new RootBeanDefinition, to be configured through its bean
102         * properties and configuration methods.
103         * @see #setBeanClass
104         * @see #setScope
105         * @see #setConstructorArgumentValues
106         * @see #setPropertyValues
107         */
108        public RootBeanDefinition() {
109                super();
110        }
111
112        /**
113         * Create a new RootBeanDefinition for a singleton.
114         * @param beanClass the class of the bean to instantiate
115         * @see #setBeanClass
116         */
117        public RootBeanDefinition(Class<?> beanClass) {
118                super();
119                setBeanClass(beanClass);
120        }
121
122        /**
123         * Create a new RootBeanDefinition for a singleton,
124         * using the given autowire mode.
125         * @param beanClass the class of the bean to instantiate
126         * @param autowireMode by name or type, using the constants in this interface
127         * @param dependencyCheck whether to perform a dependency check for objects
128         * (not applicable to autowiring a constructor, thus ignored there)
129         */
130        public RootBeanDefinition(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
131                super();
132                setBeanClass(beanClass);
133                setAutowireMode(autowireMode);
134                if (dependencyCheck && getResolvedAutowireMode() != AUTOWIRE_CONSTRUCTOR) {
135                        setDependencyCheck(DEPENDENCY_CHECK_OBJECTS);
136                }
137        }
138
139        /**
140         * Create a new RootBeanDefinition for a singleton,
141         * providing constructor arguments and property values.
142         * @param beanClass the class of the bean to instantiate
143         * @param cargs the constructor argument values to apply
144         * @param pvs the property values to apply
145         */
146        public RootBeanDefinition(Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
147                super(cargs, pvs);
148                setBeanClass(beanClass);
149        }
150
151        /**
152         * Create a new RootBeanDefinition for a singleton,
153         * providing constructor arguments and property values.
154         * <p>Takes a bean class name to avoid eager loading of the bean class.
155         * @param beanClassName the name of the class to instantiate
156         */
157        public RootBeanDefinition(String beanClassName) {
158                setBeanClassName(beanClassName);
159        }
160
161        /**
162         * Create a new RootBeanDefinition for a singleton,
163         * providing constructor arguments and property values.
164         * <p>Takes a bean class name to avoid eager loading of the bean class.
165         * @param beanClassName the name of the class to instantiate
166         * @param cargs the constructor argument values to apply
167         * @param pvs the property values to apply
168         */
169        public RootBeanDefinition(String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
170                super(cargs, pvs);
171                setBeanClassName(beanClassName);
172        }
173
174        /**
175         * Create a new RootBeanDefinition as deep copy of the given
176         * bean definition.
177         * @param original the original bean definition to copy from
178         */
179        public RootBeanDefinition(RootBeanDefinition original) {
180                super(original);
181                this.decoratedDefinition = original.decoratedDefinition;
182                this.qualifiedElement = original.qualifiedElement;
183                this.allowCaching = original.allowCaching;
184                this.isFactoryMethodUnique = original.isFactoryMethodUnique;
185                this.targetType = original.targetType;
186        }
187
188        /**
189         * Create a new RootBeanDefinition as deep copy of the given
190         * bean definition.
191         * @param original the original bean definition to copy from
192         */
193        RootBeanDefinition(BeanDefinition original) {
194                super(original);
195        }
196
197
198        @Override
199        public String getParentName() {
200                return null;
201        }
202
203        @Override
204        public void setParentName(String parentName) {
205                if (parentName != null) {
206                        throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
207                }
208        }
209
210        /**
211         * Register a target definition that is being decorated by this bean definition.
212         */
213        public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
214                this.decoratedDefinition = decoratedDefinition;
215        }
216
217        /**
218         * Return the target definition that is being decorated by this bean definition, if any.
219         */
220        public BeanDefinitionHolder getDecoratedDefinition() {
221                return this.decoratedDefinition;
222        }
223
224        /**
225         * Specify the {@link AnnotatedElement} defining qualifiers,
226         * to be used instead of the target class or factory method.
227         * @since 4.3.3
228         * @see #setTargetType(ResolvableType)
229         * @see #getResolvedFactoryMethod()
230         */
231        public void setQualifiedElement(AnnotatedElement qualifiedElement) {
232                this.qualifiedElement = qualifiedElement;
233        }
234
235        /**
236         * Return the {@link AnnotatedElement} defining qualifiers, if any.
237         * Otherwise, the factory method and target class will be checked.
238         * @since 4.3.3
239         */
240        public AnnotatedElement getQualifiedElement() {
241                return this.qualifiedElement;
242        }
243
244        /**
245         * Specify a generics-containing target type of this bean definition, if known in advance.
246         * @since 4.3.3
247         */
248        public void setTargetType(ResolvableType targetType) {
249                this.targetType = targetType;
250        }
251
252        /**
253         * Specify the target type of this bean definition, if known in advance.
254         * @since 3.2.2
255         */
256        public void setTargetType(Class<?> targetType) {
257                this.targetType = (targetType != null ? ResolvableType.forClass(targetType) : null);
258        }
259
260        /**
261         * Return the target type of this bean definition, if known
262         * (either specified in advance or resolved on first instantiation).
263         * @since 3.2.2
264         */
265        public Class<?> getTargetType() {
266                if (this.resolvedTargetType != null) {
267                        return this.resolvedTargetType;
268                }
269                return (this.targetType != null ? this.targetType.resolve() : null);
270        }
271
272        /**
273         * Specify a factory method name that refers to a non-overloaded method.
274         */
275        public void setUniqueFactoryMethodName(String name) {
276                Assert.hasText(name, "Factory method name must not be empty");
277                setFactoryMethodName(name);
278                this.isFactoryMethodUnique = true;
279        }
280
281        /**
282         * Check whether the given candidate qualifies as a factory method.
283         */
284        public boolean isFactoryMethod(Method candidate) {
285                return (candidate != null && candidate.getName().equals(getFactoryMethodName()));
286        }
287
288        /**
289         * Return the resolved factory method as a Java Method object, if available.
290         * @return the factory method, or {@code null} if not found or not resolved yet
291         */
292        public Method getResolvedFactoryMethod() {
293                synchronized (this.constructorArgumentLock) {
294                        Object candidate = this.resolvedConstructorOrFactoryMethod;
295                        return (candidate instanceof Method ? (Method) candidate : null);
296                }
297        }
298
299        public void registerExternallyManagedConfigMember(Member configMember) {
300                synchronized (this.postProcessingLock) {
301                        if (this.externallyManagedConfigMembers == null) {
302                                this.externallyManagedConfigMembers = new HashSet<Member>(1);
303                        }
304                        this.externallyManagedConfigMembers.add(configMember);
305                }
306        }
307
308        public boolean isExternallyManagedConfigMember(Member configMember) {
309                synchronized (this.postProcessingLock) {
310                        return (this.externallyManagedConfigMembers != null &&
311                                        this.externallyManagedConfigMembers.contains(configMember));
312                }
313        }
314
315        public void registerExternallyManagedInitMethod(String initMethod) {
316                synchronized (this.postProcessingLock) {
317                        if (this.externallyManagedInitMethods == null) {
318                                this.externallyManagedInitMethods = new HashSet<String>(1);
319                        }
320                        this.externallyManagedInitMethods.add(initMethod);
321                }
322        }
323
324        public boolean isExternallyManagedInitMethod(String initMethod) {
325                synchronized (this.postProcessingLock) {
326                        return (this.externallyManagedInitMethods != null &&
327                                        this.externallyManagedInitMethods.contains(initMethod));
328                }
329        }
330
331        public void registerExternallyManagedDestroyMethod(String destroyMethod) {
332                synchronized (this.postProcessingLock) {
333                        if (this.externallyManagedDestroyMethods == null) {
334                                this.externallyManagedDestroyMethods = new HashSet<String>(1);
335                        }
336                        this.externallyManagedDestroyMethods.add(destroyMethod);
337                }
338        }
339
340        public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
341                synchronized (this.postProcessingLock) {
342                        return (this.externallyManagedDestroyMethods != null &&
343                                        this.externallyManagedDestroyMethods.contains(destroyMethod));
344                }
345        }
346
347
348        @Override
349        public RootBeanDefinition cloneBeanDefinition() {
350                return new RootBeanDefinition(this);
351        }
352
353        @Override
354        public boolean equals(Object other) {
355                return (this == other || (other instanceof RootBeanDefinition && super.equals(other)));
356        }
357
358        @Override
359        public String toString() {
360                return "Root bean: " + super.toString();
361        }
362
363}