View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.beans.factory.support;
18  
19  import java.lang.reflect.Member;
20  import java.lang.reflect.Method;
21  import java.util.HashSet;
22  import java.util.Set;
23  
24  import org.springframework.beans.MutablePropertyValues;
25  import org.springframework.beans.factory.config.BeanDefinition;
26  import org.springframework.beans.factory.config.BeanDefinitionHolder;
27  import org.springframework.beans.factory.config.ConstructorArgumentValues;
28  import org.springframework.util.Assert;
29  
30  /**
31   * A root bean definition represents the merged bean definition that backs
32   * a specific bean in a Spring BeanFactory at runtime. It might have been created
33   * from multiple original bean definitions that inherit from each other,
34   * typically registered as {@link GenericBeanDefinition GenericBeanDefinitions}.
35   * A root bean definition is essentially the 'unified' bean definition view at runtime.
36   *
37   * <p>Root bean definitions may also be used for registering individual bean definitions
38   * in the configuration phase. However, since Spring 2.5, the preferred way to register
39   * bean definitions programmatically is the {@link GenericBeanDefinition} class.
40   * GenericBeanDefinition has the advantage that it allows to dynamically define
41   * parent dependencies, not 'hard-coding' the role as a root bean definition.
42   *
43   * @author Rod Johnson
44   * @author Juergen Hoeller
45   * @see GenericBeanDefinition
46   * @see ChildBeanDefinition
47   */
48  @SuppressWarnings("serial")
49  public class RootBeanDefinition extends AbstractBeanDefinition {
50  
51  	boolean allowCaching = true;
52  
53  	private BeanDefinitionHolder decoratedDefinition;
54  
55  	private volatile Class<?> targetType;
56  
57  	boolean isFactoryMethodUnique = false;
58  
59  	final Object constructorArgumentLock = new Object();
60  
61  	/** Package-visible field for caching the resolved constructor or factory method */
62  	Object resolvedConstructorOrFactoryMethod;
63  
64  	/** Package-visible field for caching the return type of a generically typed factory method */
65  	volatile Class<?> resolvedFactoryMethodReturnType;
66  
67  	/** Package-visible field that marks the constructor arguments as resolved */
68  	boolean constructorArgumentsResolved = false;
69  
70  	/** Package-visible field for caching fully resolved constructor arguments */
71  	Object[] resolvedConstructorArguments;
72  
73  	/** Package-visible field for caching partly prepared constructor arguments */
74  	Object[] preparedConstructorArguments;
75  
76  	final Object postProcessingLock = new Object();
77  
78  	/** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied */
79  	boolean postProcessed = false;
80  
81  	/** Package-visible field that indicates a before-instantiation post-processor having kicked in */
82  	volatile Boolean beforeInstantiationResolved;
83  
84  	private Set<Member> externallyManagedConfigMembers;
85  
86  	private Set<String> externallyManagedInitMethods;
87  
88  	private Set<String> externallyManagedDestroyMethods;
89  
90  
91  	/**
92  	 * Create a new RootBeanDefinition, to be configured through its bean
93  	 * properties and configuration methods.
94  	 * @see #setBeanClass
95  	 * @see #setBeanClassName
96  	 * @see #setScope
97  	 * @see #setAutowireMode
98  	 * @see #setDependencyCheck
99  	 * @see #setConstructorArgumentValues
100 	 * @see #setPropertyValues
101 	 */
102 	public RootBeanDefinition() {
103 		super();
104 	}
105 
106 	/**
107 	 * Create a new RootBeanDefinition for a singleton.
108 	 * @param beanClass the class of the bean to instantiate
109 	 */
110 	public RootBeanDefinition(Class<?> beanClass) {
111 		super();
112 		setBeanClass(beanClass);
113 	}
114 
115 	/**
116 	 * Create a new RootBeanDefinition for a singleton,
117 	 * using the given autowire mode.
118 	 * @param beanClass the class of the bean to instantiate
119 	 * @param autowireMode by name or type, using the constants in this interface
120 	 * @param dependencyCheck whether to perform a dependency check for objects
121 	 * (not applicable to autowiring a constructor, thus ignored there)
122 	 */
123 	public RootBeanDefinition(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
124 		super();
125 		setBeanClass(beanClass);
126 		setAutowireMode(autowireMode);
127 		if (dependencyCheck && getResolvedAutowireMode() != AUTOWIRE_CONSTRUCTOR) {
128 			setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
129 		}
130 	}
131 
132 	/**
133 	 * Create a new RootBeanDefinition for a singleton,
134 	 * providing constructor arguments and property values.
135 	 * @param beanClass the class of the bean to instantiate
136 	 * @param cargs the constructor argument values to apply
137 	 * @param pvs the property values to apply
138 	 */
139 	public RootBeanDefinition(Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
140 		super(cargs, pvs);
141 		setBeanClass(beanClass);
142 	}
143 
144 	/**
145 	 * Create a new RootBeanDefinition for a singleton,
146 	 * providing constructor arguments and property values.
147 	 * <p>Takes a bean class name to avoid eager loading of the bean class.
148 	 * @param beanClassName the name of the class to instantiate
149 	 */
150 	public RootBeanDefinition(String beanClassName) {
151 		setBeanClassName(beanClassName);
152 	}
153 
154 	/**
155 	 * Create a new RootBeanDefinition for a singleton,
156 	 * providing constructor arguments and property values.
157 	 * <p>Takes a bean class name to avoid eager loading of the bean class.
158 	 * @param beanClassName the name of the class to instantiate
159 	 * @param cargs the constructor argument values to apply
160 	 * @param pvs the property values to apply
161 	 */
162 	public RootBeanDefinition(String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
163 		super(cargs, pvs);
164 		setBeanClassName(beanClassName);
165 	}
166 
167 	/**
168 	 * Create a new RootBeanDefinition as deep copy of the given
169 	 * bean definition.
170 	 * @param original the original bean definition to copy from
171 	 */
172 	public RootBeanDefinition(RootBeanDefinition original) {
173 		super(original);
174 		this.allowCaching = original.allowCaching;
175 		this.decoratedDefinition = original.decoratedDefinition;
176 		this.targetType = original.targetType;
177 		this.isFactoryMethodUnique = original.isFactoryMethodUnique;
178 	}
179 
180 	/**
181 	 * Create a new RootBeanDefinition as deep copy of the given
182 	 * bean definition.
183 	 * @param original the original bean definition to copy from
184 	 */
185 	RootBeanDefinition(BeanDefinition original) {
186 		super(original);
187 	}
188 
189 
190 	@Override
191 	public String getParentName() {
192 		return null;
193 	}
194 
195 	@Override
196 	public void setParentName(String parentName) {
197 		if (parentName != null) {
198 			throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
199 		}
200 	}
201 
202 	/**
203 	 * Register a target definition that is being decorated by this bean definition.
204 	 */
205 	public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
206 		this.decoratedDefinition = decoratedDefinition;
207 	}
208 
209 	/**
210 	 * Return the target definition that is being decorated by this bean definition, if any.
211 	 */
212 	public BeanDefinitionHolder getDecoratedDefinition() {
213 		return this.decoratedDefinition;
214 	}
215 
216 	/**
217 	 * Specify the target type of this bean definition, if known in advance.
218 	 */
219 	public void setTargetType(Class<?> targetType) {
220 		this.targetType = targetType;
221 	}
222 
223 	/**
224 	 * Return the target type of this bean definition, if known
225 	 * (either specified in advance or resolved on first instantiation).
226 	 */
227 	public Class<?> getTargetType() {
228 		return this.targetType;
229 	}
230 
231 	/**
232 	 * Specify a factory method name that refers to a non-overloaded method.
233 	 */
234 	public void setUniqueFactoryMethodName(String name) {
235 		Assert.hasText(name, "Factory method name must not be empty");
236 		setFactoryMethodName(name);
237 		this.isFactoryMethodUnique = true;
238 	}
239 
240 	/**
241 	 * Check whether the given candidate qualifies as a factory method.
242 	 */
243 	public boolean isFactoryMethod(Method candidate) {
244 		return (candidate != null && candidate.getName().equals(getFactoryMethodName()));
245 	}
246 
247 	/**
248 	 * Return the resolved factory method as a Java Method object, if available.
249 	 * @return the factory method, or {@code null} if not found or not resolved yet
250 	 */
251 	public Method getResolvedFactoryMethod() {
252 		synchronized (this.constructorArgumentLock) {
253 			Object candidate = this.resolvedConstructorOrFactoryMethod;
254 			return (candidate instanceof Method ? (Method) candidate : null);
255 		}
256 	}
257 
258 	public void registerExternallyManagedConfigMember(Member configMember) {
259 		synchronized (this.postProcessingLock) {
260 			if (this.externallyManagedConfigMembers == null) {
261 				this.externallyManagedConfigMembers = new HashSet<Member>(1);
262 			}
263 			this.externallyManagedConfigMembers.add(configMember);
264 		}
265 	}
266 
267 	public boolean isExternallyManagedConfigMember(Member configMember) {
268 		synchronized (this.postProcessingLock) {
269 			return (this.externallyManagedConfigMembers != null &&
270 					this.externallyManagedConfigMembers.contains(configMember));
271 		}
272 	}
273 
274 	public void registerExternallyManagedInitMethod(String initMethod) {
275 		synchronized (this.postProcessingLock) {
276 			if (this.externallyManagedInitMethods == null) {
277 				this.externallyManagedInitMethods = new HashSet<String>(1);
278 			}
279 			this.externallyManagedInitMethods.add(initMethod);
280 		}
281 	}
282 
283 	public boolean isExternallyManagedInitMethod(String initMethod) {
284 		synchronized (this.postProcessingLock) {
285 			return (this.externallyManagedInitMethods != null &&
286 					this.externallyManagedInitMethods.contains(initMethod));
287 		}
288 	}
289 
290 	public void registerExternallyManagedDestroyMethod(String destroyMethod) {
291 		synchronized (this.postProcessingLock) {
292 			if (this.externallyManagedDestroyMethods == null) {
293 				this.externallyManagedDestroyMethods = new HashSet<String>(1);
294 			}
295 			this.externallyManagedDestroyMethods.add(destroyMethod);
296 		}
297 	}
298 
299 	public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
300 		synchronized (this.postProcessingLock) {
301 			return (this.externallyManagedDestroyMethods != null &&
302 					this.externallyManagedDestroyMethods.contains(destroyMethod));
303 		}
304 	}
305 
306 
307 	@Override
308 	public RootBeanDefinition cloneBeanDefinition() {
309 		return new RootBeanDefinition(this);
310 	}
311 
312 	@Override
313 	public boolean equals(Object other) {
314 		return (this == other || (other instanceof RootBeanDefinition && super.equals(other)));
315 	}
316 
317 	@Override
318 	public String toString() {
319 		return "Root bean: " + super.toString();
320 	}
321 
322 }