001/*
002 * Copyright 2002-2018 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.config;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
023import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator;
024import org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator;
025import org.springframework.beans.factory.config.BeanDefinition;
026import org.springframework.beans.factory.support.BeanDefinitionRegistry;
027import org.springframework.beans.factory.support.RootBeanDefinition;
028import org.springframework.core.Ordered;
029import org.springframework.lang.Nullable;
030import org.springframework.util.Assert;
031
032/**
033 * Utility class for handling registration of AOP auto-proxy creators.
034 *
035 * <p>Only a single auto-proxy creator should be registered yet multiple concrete
036 * implementations are available. This class provides a simple escalation protocol,
037 * allowing a caller to request a particular auto-proxy creator and know that creator,
038 * <i>or a more capable variant thereof</i>, will be registered as a post-processor.
039 *
040 * @author Rob Harrop
041 * @author Juergen Hoeller
042 * @author Mark Fisher
043 * @since 2.5
044 * @see AopNamespaceUtils
045 */
046public abstract class AopConfigUtils {
047
048        /**
049         * The bean name of the internally managed auto-proxy creator.
050         */
051        public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
052                        "org.springframework.aop.config.internalAutoProxyCreator";
053
054        /**
055         * Stores the auto proxy creator classes in escalation order.
056         */
057        private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
058
059        static {
060                // Set up the escalation list...
061                APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
062                APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
063                APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
064        }
065
066
067        @Nullable
068        public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
069                return registerAutoProxyCreatorIfNecessary(registry, null);
070        }
071
072        @Nullable
073        public static BeanDefinition registerAutoProxyCreatorIfNecessary(
074                        BeanDefinitionRegistry registry, @Nullable Object source) {
075
076                return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
077        }
078
079        @Nullable
080        public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
081                return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
082        }
083
084        @Nullable
085        public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
086                        BeanDefinitionRegistry registry, @Nullable Object source) {
087
088                return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
089        }
090
091        @Nullable
092        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
093                return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
094        }
095
096        @Nullable
097        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
098                        BeanDefinitionRegistry registry, @Nullable Object source) {
099
100                return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
101        }
102
103        public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
104                if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
105                        BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
106                        definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
107                }
108        }
109
110        public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
111                if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
112                        BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
113                        definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
114                }
115        }
116
117        @Nullable
118        private static BeanDefinition registerOrEscalateApcAsRequired(
119                        Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
120
121                Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
122
123                if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
124                        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
125                        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
126                                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
127                                int requiredPriority = findPriorityForClass(cls);
128                                if (currentPriority < requiredPriority) {
129                                        apcDefinition.setBeanClassName(cls.getName());
130                                }
131                        }
132                        return null;
133                }
134
135                RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
136                beanDefinition.setSource(source);
137                beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
138                beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
139                registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
140                return beanDefinition;
141        }
142
143        private static int findPriorityForClass(Class<?> clazz) {
144                return APC_PRIORITY_LIST.indexOf(clazz);
145        }
146
147        private static int findPriorityForClass(@Nullable String className) {
148                for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
149                        Class<?> clazz = APC_PRIORITY_LIST.get(i);
150                        if (clazz.getName().equals(className)) {
151                                return i;
152                        }
153                }
154                throw new IllegalArgumentException(
155                                "Class name [" + className + "] is not a known auto-proxy creator class");
156        }
157
158}