KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > aop > framework > autoproxy > AbstractAutoProxyCreator


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.aop.framework.autoproxy;
18
19 import java.beans.PropertyDescriptor JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.aopalliance.aop.Advice;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.springframework.aop.Advisor;
32 import org.springframework.aop.TargetSource;
33 import org.springframework.aop.framework.AopInfrastructureBean;
34 import org.springframework.aop.framework.ProxyConfig;
35 import org.springframework.aop.framework.ProxyFactory;
36 import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
37 import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
38 import org.springframework.aop.target.SingletonTargetSource;
39 import org.springframework.beans.BeansException;
40 import org.springframework.beans.PropertyValues;
41 import org.springframework.beans.factory.BeanClassLoaderAware;
42 import org.springframework.beans.factory.BeanFactory;
43 import org.springframework.beans.factory.BeanFactoryAware;
44 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
45 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
46 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
47 import org.springframework.core.Ordered;
48 import org.springframework.util.ClassUtils;
49
50 /**
51  * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
52  * that wraps each eligible bean with an AOP proxy, delegating to specified interceptors
53  * before invoking the bean itself.
54  *
55  * <p>This class distinguishes between "common" interceptors: shared for all proxies it
56  * creates, and "specific" interceptors: unique per bean instance. There need not
57  * be any common interceptors. If there are, they are set using the interceptorNames
58  * property. As with ProxyFactoryBean, interceptors names in the current factory
59  * are used rather than bean references to allow correct handling of prototype
60  * advisors and interceptors: for example, to support stateful mixins.
61  * Any advice type is supported for "interceptorNames" entries.
62  *
63  * <p>Such auto-proxying is particularly useful if there's a large number of beans that
64  * need to be wrapped with similar proxies, i.e. delegating to the same interceptors.
65  * Instead of x repetitive proxy definitions for x target beans, you can register
66  * one single such post processor with the bean factory to achieve the same effect.
67  *
68  * <p>Subclasses can apply any strategy to decide if a bean is to be proxied,
69  * e.g. by type, by name, by definition details, etc. They can also return
70  * additional interceptors that should just be applied to the specific bean
71  * instance. The default concrete implementation is BeanNameAutoProxyCreator,
72  * identifying the beans to be proxied via a list of bean names.
73  *
74  * <p>Any number of {@link TargetSourceCreator} implementations can be used to create
75  * a custom target source - for example, to pool prototype objects. Auto-proxying will
76  * occur even if there is no advice, as long as a TargetSourceCreator specifies a custom
77  * {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,
78  * or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}
79  * will be used by default to wrap the target bean instance.
80  *
81  * @author Juergen Hoeller
82  * @author Rod Johnson
83  * @author Rob Harrop
84  * @since 13.10.2003
85  * @see #setInterceptorNames
86  * @see #getAdvicesAndAdvisorsForBean
87  * @see BeanNameAutoProxyCreator
88  * @see DefaultAdvisorAutoProxyCreator
89  */

90 public abstract class AbstractAutoProxyCreator extends ProxyConfig
91         implements InstantiationAwareBeanPostProcessor, BeanClassLoaderAware, BeanFactoryAware,
92         Ordered, AopInfrastructureBean {
93
94     /**
95      * Convenience constant for subclasses: Return value for "do not proxy".
96      * @see #getAdvicesAndAdvisorsForBean
97      */

98     protected static final Object JavaDoc[] DO_NOT_PROXY = null;
99
100     /**
101      * Convenience constant for subclasses: Return value for
102      * "proxy without additional interceptors, just the common ones".
103      * @see #getAdvicesAndAdvisorsForBean
104      */

105     protected static final Object JavaDoc[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object JavaDoc[0];
106
107
108     /** Logger available to subclasses */
109     protected final Log logger = LogFactory.getLog(getClass());
110
111     /** Default value is same as non-ordered */
112     private int order = Integer.MAX_VALUE;
113
114     /** Default is global AdvisorAdapterRegistry */
115     private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
116
117     /**
118      * Indicates whether or not the proxy should be frozen. Overridden from super
119      * to prevent the configuration from becoming frozen too early.
120      */

121     private boolean freezeProxy = false;
122
123     /** Default is no common interceptors */
124     private String JavaDoc[] interceptorNames = new String JavaDoc[0];
125
126     private boolean applyCommonInterceptorsFirst = true;
127
128     private TargetSourceCreator[] customTargetSourceCreators;
129
130     private ClassLoader JavaDoc beanClassLoader = ClassUtils.getDefaultClassLoader();
131
132     private BeanFactory beanFactory;
133
134     /**
135      * Set of bean name Strings, referring to all beans that this auto-proxy creator
136      * created a custom TargetSource for. Used to detect own pre-built proxies (from
137      * "postProcessBeforeInstantiation") in the "postProcessAfterInitialization" method.
138      */

139     private final Set JavaDoc targetSourcedBeanNames = Collections.synchronizedSet(new HashSet JavaDoc());
140
141
142     /**
143      * Set the ordering which will apply to this class's implementation
144      * of Ordered, used when applying multiple BeanPostProcessors.
145      * Default value is Integer.MAX_VALUE, meaning that it's non-ordered.
146      * @param order ordering value
147      */

148     public final void setOrder(int order) {
149       this.order = order;
150     }
151
152     public final int getOrder() {
153       return this.order;
154     }
155
156     /**
157      * Set whether or not the proxy should be frozen, preventing advice
158      * from being added to it once it is created.
159      * <p>Overridden from the super class to prevent the proxy configuration
160      * from being frozen before the proxy is created.
161      */

162     public void setFrozen(boolean frozen) {
163         this.freezeProxy = frozen;
164     }
165
166     public boolean isFrozen() {
167         return this.freezeProxy;
168     }
169
170     /**
171      * Specify the AdvisorAdapterRegistry to use.
172      * Default is the global AdvisorAdapterRegistry.
173      * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
174      */

175     public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
176         this.advisorAdapterRegistry = advisorAdapterRegistry;
177     }
178
179     /**
180      * Set custom TargetSourceCreators to be applied in this order.
181      * If the list is empty, or they all return null, a SingletonTargetSource
182      * will be created for each bean.
183      * <p>Note that TargetSourceCreators will kick in even for target beans
184      * where no advices or advisors have been found. If a TargetSourceCreator
185      * returns a TargetSource for a specific bean, that bean will be proxied
186      * in any case.
187      * <p>TargetSourceCreators can only be invoked if this post processor is used
188      * in a BeanFactory, and its BeanFactoryAware callback is used.
189      * @param targetSourceCreators list of TargetSourceCreator.
190      * Ordering is significant: The TargetSource returned from the first matching
191      * TargetSourceCreator (that is, the first that returns non-null) will be used.
192      */

193     public void setCustomTargetSourceCreators(TargetSourceCreator[] targetSourceCreators) {
194         this.customTargetSourceCreators = targetSourceCreators;
195     }
196
197     /**
198      * Set the common interceptors. These must be bean names in the current factory.
199      * They can be of any advice or advisor type Spring supports.
200      * <p>If this property isn't set, there will be zero common interceptors.
201      * This is perfectly valid, if "specific" interceptors such as matching
202      * Advisors are all we want.
203      */

204     public void setInterceptorNames(String JavaDoc[] interceptorNames) {
205         this.interceptorNames = interceptorNames;
206     }
207
208     /**
209      * Set whether the common interceptors should be applied before bean-specific ones.
210      * Default is "true"; else, bean-specific interceptors will get applied first.
211      */

212     public void setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) {
213         this.applyCommonInterceptorsFirst = applyCommonInterceptorsFirst;
214     }
215
216     public void setBeanClassLoader(ClassLoader JavaDoc classLoader) {
217         this.beanClassLoader = classLoader;
218     }
219
220     public void setBeanFactory(BeanFactory beanFactory) {
221         this.beanFactory = beanFactory;
222     }
223
224     /**
225      * Return the owning BeanFactory
226      * May be <code>null</code>, as this object doesn't need to belong to a bean factory.
227      */

228     protected BeanFactory getBeanFactory() {
229         return this.beanFactory;
230     }
231
232
233     public Object JavaDoc postProcessBeforeInstantiation(Class JavaDoc beanClass, String JavaDoc beanName) throws BeansException {
234         if (isInfrastructureClass(beanClass, beanName) || shouldSkip(beanClass, beanName)) {
235             return null;
236         }
237
238         // Create proxy here if we have a custom TargetSource.
239
// Suppresses unnecessary default instantiation of the target bean:
240
// The TargetSource will handle target instances in a custom fashion.
241
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
242         if (targetSource != null) {
243             this.targetSourcedBeanNames.add(beanName);
244             Object JavaDoc[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
245             return createProxy(beanClass, beanName, specificInterceptors, targetSource);
246         }
247
248         return null;
249     }
250
251     public boolean postProcessAfterInstantiation(Object JavaDoc bean, String JavaDoc beanName) {
252         return true;
253     }
254
255     public PropertyValues postProcessPropertyValues(
256             PropertyValues pvs, PropertyDescriptor JavaDoc[] pds, Object JavaDoc bean, String JavaDoc beanName) {
257
258         return pvs;
259     }
260
261     public Object JavaDoc postProcessBeforeInitialization(Object JavaDoc bean, String JavaDoc beanName) {
262         return bean;
263     }
264
265     /**
266      * Create a proxy with the configured interceptors if the bean is
267      * identified as one to proxy by the subclass.
268      * @see #getAdvicesAndAdvisorsForBean
269      */

270     public Object JavaDoc postProcessAfterInitialization(Object JavaDoc bean, String JavaDoc beanName) throws BeansException {
271         if (this.targetSourcedBeanNames.contains(beanName) ||
272                 isInfrastructureClass(bean.getClass(), beanName) || shouldSkip(bean.getClass(), beanName)) {
273             return bean;
274         }
275
276         // Create proxy if we have advice.
277
Object JavaDoc[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
278         if (specificInterceptors != DO_NOT_PROXY) {
279             return createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
280         }
281
282         return bean;
283     }
284
285
286     /**
287      * Return whether the given bean class and bean name represents an
288      * infrastructure class that should never be proxied.
289      * @deprecated in favor of <code>isInfrastructureClass(beanClass)</code>
290      * @see #isInfrastructureClass(Class)
291      */

292     protected boolean isInfrastructureClass(Class JavaDoc beanClass, String JavaDoc beanName) {
293         return isInfrastructureClass(beanClass);
294     }
295
296     /**
297      * Return whether the given bean class represents an infrastructure class
298      * that should never be proxied.
299      * <p>Default implementation considers Advisors, Advices and
300      * AbstractAutoProxyCreators as infrastructure classes.
301      * @param beanClass the class of the bean
302      * @return whether the bean represents an infrastructure class
303      * @see org.springframework.aop.Advisor
304      * @see org.aopalliance.intercept.MethodInterceptor
305      * @see #shouldSkip
306      */

307     protected boolean isInfrastructureClass(Class JavaDoc beanClass) {
308         boolean retVal = Advisor.class.isAssignableFrom(beanClass) ||
309                 Advice.class.isAssignableFrom(beanClass) ||
310                 AopInfrastructureBean.class.isAssignableFrom(beanClass);
311         if (retVal && logger.isTraceEnabled()) {
312             logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
313         }
314         return retVal;
315     }
316
317     /**
318      * Subclasses should override this method to return <code>true</code> if the
319      * given bean should not be considered for auto-proxying by this post-processor.
320      * <p>Sometimes we need to be able to avoid this happening if it will lead to
321      * a circular reference. This implementation returns <code>false</code>.
322      * @param beanClass the class of the bean
323      * @param beanName the name of the bean
324      */

325     protected boolean shouldSkip(Class JavaDoc beanClass, String JavaDoc beanName) {
326         return false;
327     }
328
329     /**
330      * Create a target source for bean instances. Uses any TargetSourceCreators if set.
331      * Returns <code>null</code> if no custom TargetSource should be used.
332      * <p>This implementation uses the "customTargetSourceCreators" property.
333      * Subclasses can override this method to use a different mechanism.
334      * @param beanClass the class of the bean to create a TargetSource for
335      * @param beanName the name of the bean
336      * @return a TargetSource for this bean
337      * @see #setCustomTargetSourceCreators
338      */

339     protected TargetSource getCustomTargetSource(Class JavaDoc beanClass, String JavaDoc beanName) {
340         // We can't create fancy target sources for directly registered singletons.
341
if (this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
342             if (logger.isTraceEnabled()) {
343                 logger.trace("Checking for custom TargetSource for bean with name '" + beanName + "'");
344             }
345             if (this.customTargetSourceCreators != null) {
346                 for (int i = 0; i < this.customTargetSourceCreators.length; i++) {
347                     TargetSourceCreator tsc = this.customTargetSourceCreators[i];
348                     TargetSource ts = tsc.getTargetSource(beanClass, beanName);
349                     if (ts != null) {
350                         // Found a matching TargetSource.
351
if (logger.isDebugEnabled()) {
352                             logger.debug("TargetSourceCreator [" + tsc +
353                                     " found custom TargetSource for bean with name '" + beanName + "'");
354                         }
355                         return ts;
356                     }
357                 }
358             }
359         }
360
361         // No custom TargetSource found.
362
return null;
363     }
364
365     /**
366      * Create an AOP proxy for the given bean.
367      * @param beanClass the class of the bean
368      * @param beanName the name of the bean
369      * @param specificInterceptors the set of interceptors that is
370      * specific to this bean (may be empty, but not null)
371      * @param targetSource the TargetSource for the proxy,
372      * already pre-configured to access the bean
373      * @return the AOP proxy for the bean
374      * @see #buildAdvisors
375      */

376     protected Object JavaDoc createProxy(
377             Class JavaDoc beanClass, String JavaDoc beanName, Object JavaDoc[] specificInterceptors, TargetSource targetSource) {
378
379         ProxyFactory proxyFactory = new ProxyFactory();
380         // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
381
proxyFactory.copyFrom(this);
382
383         if (!shouldProxyTargetClass(beanClass, beanName)) {
384             // Must allow for introductions; can't just set interfaces to
385
// the target's interfaces only.
386
Class JavaDoc[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass);
387             for (int i = 0; i < targetInterfaces.length; i++) {
388                 proxyFactory.addInterface(targetInterfaces[i]);
389             }
390         }
391
392         Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
393         for (int i = 0; i < advisors.length; i++) {
394             proxyFactory.addAdvisor(advisors[i]);
395         }
396
397         proxyFactory.setTargetSource(targetSource);
398         customizeProxyFactory(proxyFactory);
399
400         proxyFactory.setFrozen(this.freezeProxy);
401         return proxyFactory.getProxy(this.beanClassLoader);
402     }
403
404     /**
405      * Determine whether the given bean should be proxied with its target
406      * class rather than its interfaces. Checks the
407      * {@link #setProxyTargetClass "proxyTargetClass" setting} as well as the
408      * {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
409      * of the corresponding bean definition.
410      * @param beanClass the class of the bean
411      * @param beanName the name of the bean
412      * @return whether the given bean should be proxied with its target class
413      * @see AutoProxyUtils#shouldProxyTargetClass
414      */

415     protected boolean shouldProxyTargetClass(Class JavaDoc beanClass, String JavaDoc beanName) {
416         return (isProxyTargetClass() ||
417                 (this.beanFactory instanceof ConfigurableListableBeanFactory &&
418                         AutoProxyUtils.shouldProxyTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName)));
419     }
420
421     /**
422      * Determine the advisors for the given bean, including the specific interceptors
423      * as well as the common interceptor, all adapted to the Advisor interface.
424      * @param beanName the name of the bean
425      * @param specificInterceptors the set of interceptors that is
426      * specific to this bean (may be empty, but not null)
427      * @return the list of Advisors for the given bean
428      */

429     protected Advisor[] buildAdvisors(String JavaDoc beanName, Object JavaDoc[] specificInterceptors) {
430         // Handle prototypes correctly...
431
Advisor[] commonInterceptors = resolveInterceptorNames();
432
433         List JavaDoc allInterceptors = new ArrayList JavaDoc();
434         if (specificInterceptors != null) {
435             allInterceptors.addAll(Arrays.asList(specificInterceptors));
436             if (commonInterceptors != null) {
437                 if (this.applyCommonInterceptorsFirst) {
438                     allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
439                 }
440                 else {
441                     allInterceptors.addAll(Arrays.asList(commonInterceptors));
442                 }
443             }
444         }
445         if (logger.isDebugEnabled()) {
446             int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
447             int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
448             logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
449                     " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
450         }
451
452         Advisor[] advisors = new Advisor[allInterceptors.size()];
453         for (int i = 0; i < allInterceptors.size(); i++) {
454             advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
455         }
456         return advisors;
457     }
458
459     /**
460      * Resolves the specified interceptor names to Advisor objects.
461      * @see #setInterceptorNames
462      */

463     private Advisor[] resolveInterceptorNames() {
464         ConfigurableBeanFactory cbf =
465                 (this.beanFactory instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) this.beanFactory : null);
466         List JavaDoc advisors = new ArrayList JavaDoc();
467         for (int i = 0; i < this.interceptorNames.length; i++) {
468             String JavaDoc beanName = this.interceptorNames[i];
469             if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
470                 Object JavaDoc next = this.beanFactory.getBean(beanName);
471                 advisors.add(this.advisorAdapterRegistry.wrap(next));
472             }
473         }
474         return (Advisor[]) advisors.toArray(new Advisor[advisors.size()]);
475     }
476
477     /**
478      * Subclasses may choose to implement this: for example,
479      * to change the interfaces exposed.
480      * <p>The default implementation is empty.
481      * @param proxyFactory ProxyFactory that is already configured with
482      * TargetSource and interfaces and will be used to create the proxy
483      * immediably after this method returns
484      */

485     protected void customizeProxyFactory(ProxyFactory proxyFactory) {
486     }
487
488
489     /**
490      * Return whether the given bean is to be proxied, what additional
491      * advices (e.g. AOP Alliance interceptors) and advisors to apply.
492      * @param beanClass the class of the bean to advise
493      * @param beanName the name of the bean
494      * @param customTargetSource the TargetSource returned by the
495      * {@link #getCustomTargetSource} method: may be ignored.
496      * Will be <code>null</code> if no custom target source is in use.
497      * @return an array of additional interceptors for the particular bean;
498      * or an empty array if no additional interceptors but just the common ones;
499      * or <code>null</code> if no proxy at all, not even with the common interceptors.
500      * See constants DO_NOT_PROXY and PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS.
501      * @throws BeansException in case of errors
502      * @see #DO_NOT_PROXY
503      * @see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
504      */

505     protected abstract Object JavaDoc[] getAdvicesAndAdvisorsForBean(
506             Class JavaDoc beanClass, String JavaDoc beanName, TargetSource customTargetSource) throws BeansException;
507
508 }
509
Popular Tags