KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > support > DefaultListableBeanFactory


1 /*
2  * Copyright 2002-2007 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.util.ArrayList JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.springframework.beans.BeansException;
26 import org.springframework.beans.factory.BeanCreationException;
27 import org.springframework.beans.factory.BeanCurrentlyInCreationException;
28 import org.springframework.beans.factory.BeanDefinitionStoreException;
29 import org.springframework.beans.factory.BeanFactory;
30 import org.springframework.beans.factory.BeanFactoryUtils;
31 import org.springframework.beans.factory.CannotLoadBeanClassException;
32 import org.springframework.beans.factory.FactoryBean;
33 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
34 import org.springframework.beans.factory.config.BeanDefinition;
35 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
36 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
37 import org.springframework.core.CollectionFactory;
38 import org.springframework.util.Assert;
39 import org.springframework.util.ObjectUtils;
40 import org.springframework.util.StringUtils;
41
42 /**
43  * Default implementation of the
44  * {@link org.springframework.beans.factory.ListableBeanFactory} and
45  * {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
46  * based on bean definition objects.
47  *
48  * <p>Typical usage is registering all bean definitions first (possibly read
49  * from a bean definition file), before accessing beans. Bean definition lookup
50  * is therefore an inexpensive operation in a local bean definition table,
51  * operating on pre-built bean definition metadata objects.
52  *
53  * <p>Can be used as a standalone bean factory, or as a superclass for custom
54  * bean factories. Note that readers for specific bean definition formats are
55  * typically implemented separately rather than as bean factory subclasses:
56  * see for example {@link PropertiesBeanDefinitionReader} and
57  * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
58  *
59  * <p>For an alternative implementation of the
60  * {@link org.springframework.beans.factory.ListableBeanFactory} interface,
61  * have a look at {@link StaticListableBeanFactory}, which manages existing
62  * bean instances rather than creating new ones based on bean definitions.
63  *
64  * @author Rod Johnson
65  * @author Juergen Hoeller
66  * @since 16 April 2001
67  * @see org.springframework.beans.factory.ListableBeanFactory
68  * @see StaticListableBeanFactory
69  * @see PropertiesBeanDefinitionReader
70  * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
71  */

72 public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
73     implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
74
75     /** Whether to allow re-registration of a different definition with the same name */
76     private boolean allowBeanDefinitionOverriding = true;
77
78     /** Whether to allow eager class loading even for lazy-init beans */
79     private boolean allowEagerClassLoading = true;
80
81     /** Map of bean definition objects, keyed by bean name */
82     private final Map JavaDoc beanDefinitionMap = new HashMap JavaDoc();
83
84     /** List of bean definition names, in registration order */
85     private final List JavaDoc beanDefinitionNames = new ArrayList JavaDoc();
86
87
88     /**
89      * Create a new DefaultListableBeanFactory.
90      */

91     public DefaultListableBeanFactory() {
92         super();
93     }
94
95     /**
96      * Create a new DefaultListableBeanFactory with the given parent.
97      * @param parentBeanFactory the parent BeanFactory
98      */

99     public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {
100         super(parentBeanFactory);
101     }
102
103
104     /**
105      * Set whether it should be allowed to override bean definitions by registering
106      * a different definition with the same name, automatically replacing the former.
107      * If not, an exception will be thrown. Default is "true".
108      */

109     public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
110         this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
111     }
112
113     /**
114      * Set whether the factory is allowed to eagerly load bean classes
115      * even for bean definitions that are marked as "lazy-init".
116      * <p>Default is "true". Turn this flag off to suppress class loading
117      * for lazy-init beans unless such a bean is explicitly requested.
118      * In particular, by-type lookups will then simply ignore bean definitions
119      * without resolved class name, instead of loading the bean classes on
120      * demand just to perform a type check.
121      * @see AbstractBeanDefinition#setLazyInit
122      */

123     public void setAllowEagerClassLoading(boolean allowEagerClassLoading) {
124         this.allowEagerClassLoading = allowEagerClassLoading;
125     }
126
127
128     public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
129         super.copyConfigurationFrom(otherFactory);
130         if (otherFactory instanceof DefaultListableBeanFactory) {
131             DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory;
132             this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
133             this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
134         }
135     }
136
137
138     //---------------------------------------------------------------------
139
// Implementation of ListableBeanFactory interface
140
//---------------------------------------------------------------------
141

142     public boolean containsBeanDefinition(String JavaDoc beanName) {
143         return this.beanDefinitionMap.containsKey(beanName);
144     }
145
146     public int getBeanDefinitionCount() {
147         return this.beanDefinitionMap.size();
148     }
149
150     public String JavaDoc[] getBeanDefinitionNames() {
151         return StringUtils.toStringArray(this.beanDefinitionNames);
152     }
153
154     public String JavaDoc[] getBeanNamesForType(Class JavaDoc type) {
155         return getBeanNamesForType(type, true, true);
156     }
157
158     public String JavaDoc[] getBeanNamesForType(Class JavaDoc type, boolean includePrototypes, boolean allowEagerInit) {
159         List JavaDoc result = new ArrayList JavaDoc();
160
161         // Check all bean definitions.
162
for (Iterator JavaDoc it = this.beanDefinitionNames.iterator(); it.hasNext();) {
163             String JavaDoc beanName = (String JavaDoc) it.next();
164             // Only consider bean as eligible if the bean name
165
// is not defined as alias for some other bean.
166
if (!isAlias(beanName)) {
167                 RootBeanDefinition mbd = getMergedBeanDefinition(beanName, false);
168                 // Only check bean definition if it is complete.
169
if (!mbd.isAbstract() &&
170                         (allowEagerInit || mbd.hasBeanClass() || !mbd.isLazyInit() || this.allowEagerClassLoading)) {
171                     // In case of FactoryBean, match object created by FactoryBean.
172
try {
173                         boolean isFactoryBean = isBeanClassMatch(beanName, mbd, FactoryBean.class);
174                         if (isFactoryBean || mbd.getFactoryBeanName() != null) {
175                             if (allowEagerInit && (includePrototypes || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
176                                 result.add(beanName);
177                                 // Match found for this bean: do not match FactoryBean itself anymore.
178
continue;
179                             }
180                             // We're done for anything but a full FactoryBean.
181
if (!isFactoryBean) {
182                                 continue;
183                             }
184                             // In case of FactoryBean, try to match FactoryBean itself next.
185
beanName = FACTORY_BEAN_PREFIX + beanName;
186                         }
187                         // Match raw bean instance (might be raw FactoryBean).
188
if ((includePrototypes || mbd.isSingleton()) && isTypeMatch(beanName, type)) {
189                             result.add(beanName);
190                         }
191                     }
192                     catch (CannotLoadBeanClassException ex) {
193                         if (mbd.isLazyInit()) {
194                             if (logger.isDebugEnabled()) {
195                                 logger.debug("Ignoring bean class loading failure for lazy-init bean '" + beanName + "'", ex);
196                             }
197                         }
198                         else {
199                             throw ex;
200                         }
201                     }
202                 }
203             }
204         }
205
206         // Check singletons too, to catch manually registered singletons.
207
String JavaDoc[] singletonNames = getSingletonNames();
208         for (int i = 0; i < singletonNames.length; i++) {
209             String JavaDoc beanName = singletonNames[i];
210             // Only check if manually registered.
211
if (!containsBeanDefinition(beanName)) {
212                 // In case of FactoryBean, match object created by FactoryBean.
213
if (isFactoryBean(beanName)) {
214                     if ((includePrototypes || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
215                         result.add(beanName);
216                         // Match found for this bean: do not match FactoryBean itself anymore.
217
continue;
218                     }
219                     // In case of FactoryBean, try to match FactoryBean itself next.
220
beanName = FACTORY_BEAN_PREFIX + beanName;
221                 }
222                 // Match raw bean instance (might be raw FactoryBean).
223
if (isTypeMatch(beanName, type)) {
224                     result.add(beanName);
225                 }
226             }
227         }
228
229         return StringUtils.toStringArray(result);
230     }
231
232     public Map JavaDoc getBeansOfType(Class JavaDoc type) throws BeansException {
233         return getBeansOfType(type, true, true);
234     }
235
236     public Map JavaDoc getBeansOfType(Class JavaDoc type, boolean includePrototypes, boolean allowEagerInit)
237             throws BeansException {
238
239         String JavaDoc[] beanNames = getBeanNamesForType(type, includePrototypes, allowEagerInit);
240         Map JavaDoc result = CollectionFactory.createLinkedMapIfPossible(beanNames.length);
241         for (int i = 0; i < beanNames.length; i++) {
242             String JavaDoc beanName = beanNames[i];
243             try {
244                 result.put(beanName, getBean(beanName));
245             }
246             catch (BeanCreationException ex) {
247                 Throwable JavaDoc rootCause = ex.getMostSpecificCause();
248                 if (rootCause instanceof BeanCurrentlyInCreationException) {
249                     BeanCreationException bce = (BeanCreationException) rootCause;
250                     if (isCurrentlyInCreation(bce.getBeanName())) {
251                         if (logger.isDebugEnabled()) {
252                             logger.debug("Ignoring match to currently created bean '" + beanName + "': " + ex.getMessage());
253                         }
254                         // Ignore: indicates a circular reference when autowiring constructors.
255
// We want to find matches other than the currently created bean itself.
256
continue;
257                     }
258                 }
259                 throw ex;
260             }
261         }
262         return result;
263     }
264
265
266     //---------------------------------------------------------------------
267
// Implementation of ConfigurableListableBeanFactory interface
268
//---------------------------------------------------------------------
269

270     public void preInstantiateSingletons() throws BeansException {
271         if (logger.isInfoEnabled()) {
272             logger.info("Pre-instantiating singletons in " + this);
273         }
274         for (Iterator JavaDoc it = this.beanDefinitionNames.iterator(); it.hasNext();) {
275             String JavaDoc beanName = (String JavaDoc) it.next();
276             if (!containsSingleton(beanName) && containsBeanDefinition(beanName)) {
277                 RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
278                 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
279                     Class JavaDoc beanClass = resolveBeanClass(bd, beanName);
280                     if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
281                         getBean(FACTORY_BEAN_PREFIX + beanName);
282                     }
283                     else {
284                         getBean(beanName);
285                     }
286                 }
287             }
288         }
289     }
290
291
292     //---------------------------------------------------------------------
293
// Implementation of BeanDefinitionRegistry interface
294
//---------------------------------------------------------------------
295

296     public void registerBeanDefinition(String JavaDoc beanName, BeanDefinition beanDefinition)
297             throws BeanDefinitionStoreException {
298
299         Assert.hasText(beanName, "'beanName' must not be empty");
300         Assert.notNull(beanDefinition, "BeanDefinition must not be null");
301
302         if (beanDefinition instanceof AbstractBeanDefinition) {
303             try {
304                 ((AbstractBeanDefinition) beanDefinition).validate();
305             }
306             catch (BeanDefinitionValidationException ex) {
307                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
308                         "Validation of bean definition failed", ex);
309             }
310         }
311
312         Object JavaDoc oldBeanDefinition = this.beanDefinitionMap.get(beanName);
313         if (oldBeanDefinition != null) {
314             if (!this.allowBeanDefinitionOverriding) {
315                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
316                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
317                         "': There is already [" + oldBeanDefinition + "] bound.");
318             }
319             else {
320                 if (logger.isInfoEnabled()) {
321                     logger.info("Overriding bean definition for bean '" + beanName +
322                             "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
323                 }
324             }
325         }
326         else {
327             this.beanDefinitionNames.add(beanName);
328         }
329         this.beanDefinitionMap.put(beanName, beanDefinition);
330
331         // Remove corresponding bean from singleton cache, if any. Shouldn't usually
332
// be necessary, rather just meant for overriding a context's default beans
333
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
334
synchronized (getSingletonMutex()) {
335             removeSingleton(beanName);
336         }
337     }
338
339
340     //---------------------------------------------------------------------
341
// Implementation of superclass abstract methods
342
//---------------------------------------------------------------------
343

344     public BeanDefinition getBeanDefinition(String JavaDoc beanName) throws NoSuchBeanDefinitionException {
345         BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(beanName);
346         if (bd == null) {
347             if (logger.isTraceEnabled()) {
348                 logger.trace("No bean named '" + beanName + "' found in " + this);
349             }
350             throw new NoSuchBeanDefinitionException(beanName);
351         }
352         return bd;
353     }
354
355     protected Map JavaDoc findAutowireCandidates(String JavaDoc beanName, Class JavaDoc requiredType) {
356         String JavaDoc[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType);
357         Map JavaDoc result = CollectionFactory.createLinkedMapIfPossible(candidateNames.length);
358         for (int i = 0; i < candidateNames.length; i++) {
359             String JavaDoc candidateName = candidateNames[i];
360             if (!candidateName.equals(beanName) &&
361                     (!containsBeanDefinition(candidateName) || getMergedBeanDefinition(candidateName).isAutowireCandidate())) {
362                 result.put(candidateName, getBean(candidateName));
363             }
364         }
365         return result;
366     }
367
368
369     public String JavaDoc toString() {
370         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(ObjectUtils.identityToString(this));
371         sb.append(": defining beans [");
372         sb.append(StringUtils.arrayToCommaDelimitedString(getBeanDefinitionNames()));
373         sb.append("]; ");
374         BeanFactory parent = getParentBeanFactory();
375         if (parent == null) {
376             sb.append("root of factory hierarchy");
377         }
378         else {
379             sb.append("parent: " + ObjectUtils.identityToString(parent));
380         }
381         return sb.toString();
382     }
383
384 }
385
Popular Tags