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