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