001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.aop.framework.autoproxy;
018:
019: import java.beans.PropertyDescriptor;
020: import java.util.ArrayList;
021: import java.util.Arrays;
022: import java.util.Collections;
023: import java.util.HashSet;
024: import java.util.List;
025: import java.util.Set;
026:
027: import org.aopalliance.aop.Advice;
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: import org.springframework.aop.Advisor;
032: import org.springframework.aop.TargetSource;
033: import org.springframework.aop.framework.AopInfrastructureBean;
034: import org.springframework.aop.framework.ProxyConfig;
035: import org.springframework.aop.framework.ProxyFactory;
036: import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
037: import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
038: import org.springframework.aop.target.SingletonTargetSource;
039: import org.springframework.beans.BeansException;
040: import org.springframework.beans.PropertyValues;
041: import org.springframework.beans.factory.BeanClassLoaderAware;
042: import org.springframework.beans.factory.BeanFactory;
043: import org.springframework.beans.factory.BeanFactoryAware;
044: import org.springframework.beans.factory.config.ConfigurableBeanFactory;
045: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
046: import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
047: import org.springframework.core.Ordered;
048: import org.springframework.util.ClassUtils;
049:
050: /**
051: * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
052: * that wraps each eligible bean with an AOP proxy, delegating to specified interceptors
053: * before invoking the bean itself.
054: *
055: * <p>This class distinguishes between "common" interceptors: shared for all proxies it
056: * creates, and "specific" interceptors: unique per bean instance. There need not
057: * be any common interceptors. If there are, they are set using the interceptorNames
058: * property. As with ProxyFactoryBean, interceptors names in the current factory
059: * are used rather than bean references to allow correct handling of prototype
060: * advisors and interceptors: for example, to support stateful mixins.
061: * Any advice type is supported for "interceptorNames" entries.
062: *
063: * <p>Such auto-proxying is particularly useful if there's a large number of beans that
064: * need to be wrapped with similar proxies, i.e. delegating to the same interceptors.
065: * Instead of x repetitive proxy definitions for x target beans, you can register
066: * one single such post processor with the bean factory to achieve the same effect.
067: *
068: * <p>Subclasses can apply any strategy to decide if a bean is to be proxied,
069: * e.g. by type, by name, by definition details, etc. They can also return
070: * additional interceptors that should just be applied to the specific bean
071: * instance. The default concrete implementation is BeanNameAutoProxyCreator,
072: * identifying the beans to be proxied via a list of bean names.
073: *
074: * <p>Any number of {@link TargetSourceCreator} implementations can be used to create
075: * a custom target source - for example, to pool prototype objects. Auto-proxying will
076: * occur even if there is no advice, as long as a TargetSourceCreator specifies a custom
077: * {@link org.springframework.aop.TargetSource}. If there are no TargetSourceCreators set,
078: * or if none matches, a {@link org.springframework.aop.target.SingletonTargetSource}
079: * will be used by default to wrap the target bean instance.
080: *
081: * @author Juergen Hoeller
082: * @author Rod Johnson
083: * @author Rob Harrop
084: * @since 13.10.2003
085: * @see #setInterceptorNames
086: * @see #getAdvicesAndAdvisorsForBean
087: * @see BeanNameAutoProxyCreator
088: * @see DefaultAdvisorAutoProxyCreator
089: */
090: public abstract class AbstractAutoProxyCreator extends ProxyConfig
091: implements InstantiationAwareBeanPostProcessor,
092: BeanClassLoaderAware, BeanFactoryAware, Ordered,
093: AopInfrastructureBean {
094:
095: /**
096: * Convenience constant for subclasses: Return value for "do not proxy".
097: * @see #getAdvicesAndAdvisorsForBean
098: */
099: protected static final Object[] DO_NOT_PROXY = null;
100:
101: /**
102: * Convenience constant for subclasses: Return value for
103: * "proxy without additional interceptors, just the common ones".
104: * @see #getAdvicesAndAdvisorsForBean
105: */
106: protected static final Object[] PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS = new Object[0];
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
116: .getInstance();
117:
118: /**
119: * Indicates whether or not the proxy should be frozen. Overridden from super
120: * to prevent the configuration from becoming frozen too early.
121: */
122: private boolean freezeProxy = false;
123:
124: /** Default is no common interceptors */
125: private String[] interceptorNames = new String[0];
126:
127: private boolean applyCommonInterceptorsFirst = true;
128:
129: private TargetSourceCreator[] customTargetSourceCreators;
130:
131: private ClassLoader beanClassLoader = ClassUtils
132: .getDefaultClassLoader();
133:
134: private BeanFactory beanFactory;
135:
136: /**
137: * Set of bean name Strings, referring to all beans that this auto-proxy creator
138: * created a custom TargetSource for. Used to detect own pre-built proxies (from
139: * "postProcessBeforeInstantiation") in the "postProcessAfterInitialization" method.
140: */
141: private final Set targetSourcedBeans = Collections
142: .synchronizedSet(new HashSet());
143:
144: private final Set advisedBeans = Collections
145: .synchronizedSet(new HashSet());
146:
147: private final Set nonAdvisedBeans = Collections
148: .synchronizedSet(new HashSet());
149:
150: /**
151: * Set the ordering which will apply to this class's implementation
152: * of Ordered, used when applying multiple BeanPostProcessors.
153: * <p>Default value is <code>Integer.MAX_VALUE</code>, meaning that it's non-ordered.
154: * @param order ordering value
155: */
156: public final void setOrder(int order) {
157: this .order = order;
158: }
159:
160: public final int getOrder() {
161: return this .order;
162: }
163:
164: /**
165: * Set whether or not the proxy should be frozen, preventing advice
166: * from being added to it once it is created.
167: * <p>Overridden from the super class to prevent the proxy configuration
168: * from being frozen before the proxy is created.
169: */
170: public void setFrozen(boolean frozen) {
171: this .freezeProxy = frozen;
172: }
173:
174: public boolean isFrozen() {
175: return this .freezeProxy;
176: }
177:
178: /**
179: * Specify the AdvisorAdapterRegistry to use.
180: * Default is the global AdvisorAdapterRegistry.
181: * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
182: */
183: public void setAdvisorAdapterRegistry(
184: AdvisorAdapterRegistry advisorAdapterRegistry) {
185: this .advisorAdapterRegistry = advisorAdapterRegistry;
186: }
187:
188: /**
189: * Set custom TargetSourceCreators to be applied in this order.
190: * If the list is empty, or they all return null, a SingletonTargetSource
191: * will be created for each bean.
192: * <p>Note that TargetSourceCreators will kick in even for target beans
193: * where no advices or advisors have been found. If a TargetSourceCreator
194: * returns a TargetSource for a specific bean, that bean will be proxied
195: * in any case.
196: * <p>TargetSourceCreators can only be invoked if this post processor is used
197: * in a BeanFactory, and its BeanFactoryAware callback is used.
198: * @param targetSourceCreators list of TargetSourceCreator.
199: * Ordering is significant: The TargetSource returned from the first matching
200: * TargetSourceCreator (that is, the first that returns non-null) will be used.
201: */
202: public void setCustomTargetSourceCreators(
203: TargetSourceCreator[] targetSourceCreators) {
204: this .customTargetSourceCreators = targetSourceCreators;
205: }
206:
207: /**
208: * Set the common interceptors. These must be bean names in the current factory.
209: * They can be of any advice or advisor type Spring supports.
210: * <p>If this property isn't set, there will be zero common interceptors.
211: * This is perfectly valid, if "specific" interceptors such as matching
212: * Advisors are all we want.
213: */
214: public void setInterceptorNames(String[] interceptorNames) {
215: this .interceptorNames = interceptorNames;
216: }
217:
218: /**
219: * Set whether the common interceptors should be applied before bean-specific ones.
220: * Default is "true"; else, bean-specific interceptors will get applied first.
221: */
222: public void setApplyCommonInterceptorsFirst(
223: boolean applyCommonInterceptorsFirst) {
224: this .applyCommonInterceptorsFirst = applyCommonInterceptorsFirst;
225: }
226:
227: public void setBeanClassLoader(ClassLoader classLoader) {
228: this .beanClassLoader = classLoader;
229: }
230:
231: public void setBeanFactory(BeanFactory beanFactory) {
232: this .beanFactory = beanFactory;
233: }
234:
235: /**
236: * Return the owning BeanFactory
237: * May be <code>null</code>, as this object doesn't need to belong to a bean factory.
238: */
239: protected BeanFactory getBeanFactory() {
240: return this .beanFactory;
241: }
242:
243: public Object postProcessBeforeInstantiation(Class beanClass,
244: String beanName) throws BeansException {
245: Object cacheKey = getCacheKey(beanClass, beanName);
246:
247: if (!this .targetSourcedBeans.contains(cacheKey)) {
248: if (this .advisedBeans.contains(cacheKey)
249: || this .nonAdvisedBeans.contains(cacheKey)) {
250: return null;
251: }
252: if (isInfrastructureClass(beanClass, beanName)
253: || shouldSkip(beanClass, beanName)) {
254: this .nonAdvisedBeans.add(cacheKey);
255: return null;
256: }
257: }
258:
259: // Create proxy here if we have a custom TargetSource.
260: // Suppresses unnecessary default instantiation of the target bean:
261: // The TargetSource will handle target instances in a custom fashion.
262: TargetSource targetSource = getCustomTargetSource(beanClass,
263: beanName);
264: if (targetSource != null) {
265: this .targetSourcedBeans.add(beanName);
266: Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
267: beanClass, beanName, targetSource);
268: return createProxy(beanClass, beanName,
269: specificInterceptors, targetSource);
270: }
271:
272: return null;
273: }
274:
275: public boolean postProcessAfterInstantiation(Object bean,
276: String beanName) {
277: return true;
278: }
279:
280: public PropertyValues postProcessPropertyValues(PropertyValues pvs,
281: PropertyDescriptor[] pds, Object bean, String beanName) {
282:
283: return pvs;
284: }
285:
286: public Object postProcessBeforeInitialization(Object bean,
287: String beanName) {
288: return bean;
289: }
290:
291: /**
292: * Create a proxy with the configured interceptors if the bean is
293: * identified as one to proxy by the subclass.
294: * @see #getAdvicesAndAdvisorsForBean
295: */
296: public Object postProcessAfterInitialization(Object bean,
297: String beanName) throws BeansException {
298: if (this .targetSourcedBeans.contains(beanName)) {
299: return bean;
300: }
301: Object cacheKey = getCacheKey(bean.getClass(), beanName);
302: if (this .nonAdvisedBeans.contains(cacheKey)) {
303: return bean;
304: }
305: if (isInfrastructureClass(bean.getClass(), beanName)
306: || shouldSkip(bean.getClass(), beanName)) {
307: this .nonAdvisedBeans.add(cacheKey);
308: return bean;
309: }
310:
311: // Create proxy if we have advice.
312: Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
313: bean.getClass(), beanName, null);
314: if (specificInterceptors != DO_NOT_PROXY) {
315: this .advisedBeans.add(cacheKey);
316: return createProxy(bean.getClass(), beanName,
317: specificInterceptors, new SingletonTargetSource(
318: bean));
319: }
320:
321: this .nonAdvisedBeans.add(cacheKey);
322: return bean;
323: }
324:
325: /**
326: * Build a cache key for the given bean class and bean name.
327: * @param beanClass the bean class
328: * @param beanName the bean name
329: * @return the cache key for the given class and name
330: */
331: protected Object getCacheKey(Class beanClass, String beanName) {
332: return beanClass.getName() + "_" + beanName;
333: }
334:
335: /**
336: * Return whether the given bean class and bean name represents an
337: * infrastructure class that should never be proxied.
338: * @deprecated in favor of <code>isInfrastructureClass(beanClass)</code>
339: * @see #isInfrastructureClass(Class)
340: */
341: protected boolean isInfrastructureClass(Class beanClass,
342: String beanName) {
343: return isInfrastructureClass(beanClass);
344: }
345:
346: /**
347: * Return whether the given bean class represents an infrastructure class
348: * that should never be proxied.
349: * <p>Default implementation considers Advisors, Advices and
350: * AbstractAutoProxyCreators as infrastructure classes.
351: * @param beanClass the class of the bean
352: * @return whether the bean represents an infrastructure class
353: * @see org.springframework.aop.Advisor
354: * @see org.aopalliance.intercept.MethodInterceptor
355: * @see #shouldSkip
356: */
357: protected boolean isInfrastructureClass(Class beanClass) {
358: boolean retVal = Advisor.class.isAssignableFrom(beanClass)
359: || Advice.class.isAssignableFrom(beanClass)
360: || AopInfrastructureBean.class
361: .isAssignableFrom(beanClass);
362: if (retVal && logger.isTraceEnabled()) {
363: logger
364: .trace("Did not attempt to auto-proxy infrastructure class ["
365: + beanClass.getName() + "]");
366: }
367: return retVal;
368: }
369:
370: /**
371: * Subclasses should override this method to return <code>true</code> if the
372: * given bean should not be considered for auto-proxying by this post-processor.
373: * <p>Sometimes we need to be able to avoid this happening if it will lead to
374: * a circular reference. This implementation returns <code>false</code>.
375: * @param beanClass the class of the bean
376: * @param beanName the name of the bean
377: * @return whether to skip the given bean
378: */
379: protected boolean shouldSkip(Class beanClass, String beanName) {
380: return false;
381: }
382:
383: /**
384: * Create a target source for bean instances. Uses any TargetSourceCreators if set.
385: * Returns <code>null</code> if no custom TargetSource should be used.
386: * <p>This implementation uses the "customTargetSourceCreators" property.
387: * Subclasses can override this method to use a different mechanism.
388: * @param beanClass the class of the bean to create a TargetSource for
389: * @param beanName the name of the bean
390: * @return a TargetSource for this bean
391: * @see #setCustomTargetSourceCreators
392: */
393: protected TargetSource getCustomTargetSource(Class beanClass,
394: String beanName) {
395: // We can't create fancy target sources for directly registered singletons.
396: if (this .customTargetSourceCreators != null
397: && this .beanFactory != null
398: && this .beanFactory.containsBean(beanName)) {
399: for (int i = 0; i < this .customTargetSourceCreators.length; i++) {
400: TargetSourceCreator tsc = this .customTargetSourceCreators[i];
401: TargetSource ts = tsc.getTargetSource(beanClass,
402: beanName);
403: if (ts != null) {
404: // Found a matching TargetSource.
405: if (logger.isDebugEnabled()) {
406: logger
407: .debug("TargetSourceCreator ["
408: + tsc
409: + " found custom TargetSource for bean with name '"
410: + beanName + "'");
411: }
412: return ts;
413: }
414: }
415: }
416:
417: // No custom TargetSource found.
418: return null;
419: }
420:
421: /**
422: * Create an AOP proxy for the given bean.
423: * @param beanClass the class of the bean
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: * @param targetSource the TargetSource for the proxy,
428: * already pre-configured to access the bean
429: * @return the AOP proxy for the bean
430: * @see #buildAdvisors
431: */
432: protected Object createProxy(Class beanClass, String beanName,
433: Object[] specificInterceptors, TargetSource targetSource) {
434:
435: ProxyFactory proxyFactory = new ProxyFactory();
436: // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
437: proxyFactory.copyFrom(this );
438:
439: if (!shouldProxyTargetClass(beanClass, beanName)) {
440: // Must allow for introductions; can't just set interfaces to
441: // the target's interfaces only.
442: Class[] targetInterfaces = ClassUtils
443: .getAllInterfacesForClass(beanClass);
444: for (int i = 0; i < targetInterfaces.length; i++) {
445: proxyFactory.addInterface(targetInterfaces[i]);
446: }
447: }
448:
449: Advisor[] advisors = buildAdvisors(beanName,
450: specificInterceptors);
451: for (int i = 0; i < advisors.length; i++) {
452: proxyFactory.addAdvisor(advisors[i]);
453: }
454:
455: proxyFactory.setTargetSource(targetSource);
456: customizeProxyFactory(proxyFactory);
457:
458: proxyFactory.setFrozen(this .freezeProxy);
459: if (advisorsPreFiltered()) {
460: proxyFactory.setPreFiltered(true);
461: }
462:
463: return proxyFactory.getProxy(this .beanClassLoader);
464: }
465:
466: /**
467: * Determine whether the given bean should be proxied with its target
468: * class rather than its interfaces. Checks the
469: * {@link #setProxyTargetClass "proxyTargetClass" setting} as well as the
470: * {@link AutoProxyUtils#PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
471: * of the corresponding bean definition.
472: * @param beanClass the class of the bean
473: * @param beanName the name of the bean
474: * @return whether the given bean should be proxied with its target class
475: * @see AutoProxyUtils#shouldProxyTargetClass
476: */
477: protected boolean shouldProxyTargetClass(Class beanClass,
478: String beanName) {
479: return (isProxyTargetClass() || (this .beanFactory instanceof ConfigurableListableBeanFactory && AutoProxyUtils
480: .shouldProxyTargetClass(
481: (ConfigurableListableBeanFactory) this .beanFactory,
482: beanName)));
483: }
484:
485: /**
486: * Return whether the Advisors returned by the subclass are pre-filtered
487: * to match the bean's target class already, allowing the ClassFilter check
488: * to be skipped when building advisors chains for AOP invocations.
489: * <p>Default is <code>false</code>. Subclasses may override this if they
490: * will always return pre-filtered Advisors.
491: * @return whether the Advisors are pre-filtered
492: * @see #getAdvicesAndAdvisorsForBean
493: * @see org.springframework.aop.framework.Advised#setPreFiltered
494: */
495: protected boolean advisorsPreFiltered() {
496: return false;
497: }
498:
499: /**
500: * Determine the advisors for the given bean, including the specific interceptors
501: * as well as the common interceptor, all adapted to the Advisor interface.
502: * @param beanName the name of the bean
503: * @param specificInterceptors the set of interceptors that is
504: * specific to this bean (may be empty, but not null)
505: * @return the list of Advisors for the given bean
506: */
507: protected Advisor[] buildAdvisors(String beanName,
508: Object[] specificInterceptors) {
509: // Handle prototypes correctly...
510: Advisor[] commonInterceptors = resolveInterceptorNames();
511:
512: List allInterceptors = new ArrayList();
513: if (specificInterceptors != null) {
514: allInterceptors.addAll(Arrays.asList(specificInterceptors));
515: if (commonInterceptors != null) {
516: if (this .applyCommonInterceptorsFirst) {
517: allInterceptors.addAll(0, Arrays
518: .asList(commonInterceptors));
519: } else {
520: allInterceptors.addAll(Arrays
521: .asList(commonInterceptors));
522: }
523: }
524: }
525: if (logger.isDebugEnabled()) {
526: int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length
527: : 0);
528: int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length
529: : 0);
530: logger.debug("Creating implicit proxy for bean '"
531: + beanName + "' with " + nrOfCommonInterceptors
532: + " common interceptors and "
533: + nrOfSpecificInterceptors
534: + " specific interceptors");
535: }
536:
537: Advisor[] advisors = new Advisor[allInterceptors.size()];
538: for (int i = 0; i < allInterceptors.size(); i++) {
539: advisors[i] = this .advisorAdapterRegistry
540: .wrap(allInterceptors.get(i));
541: }
542: return advisors;
543: }
544:
545: /**
546: * Resolves the specified interceptor names to Advisor objects.
547: * @see #setInterceptorNames
548: */
549: private Advisor[] resolveInterceptorNames() {
550: ConfigurableBeanFactory cbf = (this .beanFactory instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) this .beanFactory
551: : null);
552: List advisors = new ArrayList();
553: for (int i = 0; i < this .interceptorNames.length; i++) {
554: String beanName = this .interceptorNames[i];
555: if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
556: Object next = this .beanFactory.getBean(beanName);
557: advisors.add(this .advisorAdapterRegistry.wrap(next));
558: }
559: }
560: return (Advisor[]) advisors
561: .toArray(new Advisor[advisors.size()]);
562: }
563:
564: /**
565: * Subclasses may choose to implement this: for example,
566: * to change the interfaces exposed.
567: * <p>The default implementation is empty.
568: * @param proxyFactory ProxyFactory that is already configured with
569: * TargetSource and interfaces and will be used to create the proxy
570: * immediably after this method returns
571: */
572: protected void customizeProxyFactory(ProxyFactory proxyFactory) {
573: }
574:
575: /**
576: * Return whether the given bean is to be proxied, what additional
577: * advices (e.g. AOP Alliance interceptors) and advisors to apply.
578: * @param beanClass the class of the bean to advise
579: * @param beanName the name of the bean
580: * @param customTargetSource the TargetSource returned by the
581: * {@link #getCustomTargetSource} method: may be ignored.
582: * Will be <code>null</code> if no custom target source is in use.
583: * @return an array of additional interceptors for the particular bean;
584: * or an empty array if no additional interceptors but just the common ones;
585: * or <code>null</code> if no proxy at all, not even with the common interceptors.
586: * See constants DO_NOT_PROXY and PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS.
587: * @throws BeansException in case of errors
588: * @see #DO_NOT_PROXY
589: * @see #PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
590: */
591: protected abstract Object[] getAdvicesAndAdvisorsForBean(
592: Class beanClass, String beanName,
593: TargetSource customTargetSource) throws BeansException;
594:
595: }
|