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.util.List;
020
021import org.springframework.aop.Advisor;
022import org.springframework.aop.TargetSource;
023import org.springframework.aop.support.AopUtils;
024import org.springframework.beans.factory.BeanFactory;
025import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
026import org.springframework.core.annotation.AnnotationAwareOrderComparator;
027
028/**
029 * Generic auto proxy creator that builds AOP proxies for specific beans
030 * based on detected Advisors for each bean.
031 *
032 * <p>Subclasses may override the {@link #findCandidateAdvisors()} method to
033 * return a custom list of Advisors applying to any object. Subclasses can
034 * also override the inherited {@link #shouldSkip} method to exclude certain
035 * objects from auto-proxying.
036 *
037 * <p>Advisors or advices requiring ordering should implement the
038 * {@link org.springframework.core.Ordered} interface. This class sorts
039 * Advisors by Ordered order value. Advisors that don't implement the
040 * Ordered interface will be considered as unordered; they will appear
041 * at the end of the advisor chain in undefined order.
042 *
043 * @author Rod Johnson
044 * @author Juergen Hoeller
045 * @see #findCandidateAdvisors
046 */
047@SuppressWarnings("serial")
048public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
049
050        private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;
051
052
053        @Override
054        public void setBeanFactory(BeanFactory beanFactory) {
055                super.setBeanFactory(beanFactory);
056                if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
057                        throw new IllegalArgumentException(
058                                        "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
059                }
060                initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
061        }
062
063        protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
064                this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
065        }
066
067
068        @Override
069        protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
070                List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
071                if (advisors.isEmpty()) {
072                        return DO_NOT_PROXY;
073                }
074                return advisors.toArray();
075        }
076
077        /**
078         * Find all eligible Advisors for auto-proxying this class.
079         * @param beanClass the clazz to find advisors for
080         * @param beanName the name of the currently proxied bean
081         * @return the empty List, not {@code null},
082         * if there are no pointcuts or interceptors
083         * @see #findCandidateAdvisors
084         * @see #sortAdvisors
085         * @see #extendAdvisors
086         */
087        protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
088                List<Advisor> candidateAdvisors = findCandidateAdvisors();
089                List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
090                extendAdvisors(eligibleAdvisors);
091                if (!eligibleAdvisors.isEmpty()) {
092                        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
093                }
094                return eligibleAdvisors;
095        }
096
097        /**
098         * Find all candidate Advisors to use in auto-proxying.
099         * @return the List of candidate Advisors
100         */
101        protected List<Advisor> findCandidateAdvisors() {
102                return this.advisorRetrievalHelper.findAdvisorBeans();
103        }
104
105        /**
106         * Search the given candidate Advisors to find all Advisors that
107         * can apply to the specified bean.
108         * @param candidateAdvisors the candidate Advisors
109         * @param beanClass the target's bean class
110         * @param beanName the target's bean name
111         * @return the List of applicable Advisors
112         * @see ProxyCreationContext#getCurrentProxiedBeanName()
113         */
114        protected List<Advisor> findAdvisorsThatCanApply(
115                        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
116
117                ProxyCreationContext.setCurrentProxiedBeanName(beanName);
118                try {
119                        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
120                }
121                finally {
122                        ProxyCreationContext.setCurrentProxiedBeanName(null);
123                }
124        }
125
126        /**
127         * Return whether the Advisor bean with the given name is eligible
128         * for proxying in the first place.
129         * @param beanName the name of the Advisor bean
130         * @return whether the bean is eligible
131         */
132        protected boolean isEligibleAdvisorBean(String beanName) {
133                return true;
134        }
135
136        /**
137         * Sort advisors based on ordering. Subclasses may choose to override this
138         * method to customize the sorting strategy.
139         * @param advisors the source List of Advisors
140         * @return the sorted List of Advisors
141         * @see org.springframework.core.Ordered
142         * @see org.springframework.core.annotation.Order
143         * @see org.springframework.core.annotation.AnnotationAwareOrderComparator
144         */
145        protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
146                AnnotationAwareOrderComparator.sort(advisors);
147                return advisors;
148        }
149
150        /**
151         * Extension hook that subclasses can override to register additional Advisors,
152         * given the sorted Advisors obtained to date.
153         * <p>The default implementation is empty.
154         * <p>Typically used to add Advisors that expose contextual information
155         * required by some of the later advisors.
156         * @param candidateAdvisors the Advisors that have already been identified as
157         * applying to a given bean
158         */
159        protected void extendAdvisors(List<Advisor> candidateAdvisors) {
160        }
161
162        /**
163         * This auto-proxy creator always returns pre-filtered Advisors.
164         */
165        @Override
166        protected boolean advisorsPreFiltered() {
167                return true;
168        }
169
170
171        /**
172         * Subclass of BeanFactoryAdvisorRetrievalHelper that delegates to
173         * surrounding AbstractAdvisorAutoProxyCreator facilities.
174         */
175        private class BeanFactoryAdvisorRetrievalHelperAdapter extends BeanFactoryAdvisorRetrievalHelper {
176
177                public BeanFactoryAdvisorRetrievalHelperAdapter(ConfigurableListableBeanFactory beanFactory) {
178                        super(beanFactory);
179                }
180
181                @Override
182                protected boolean isEligibleBean(String beanName) {
183                        return AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
184                }
185        }
186
187}