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.context.annotation; 018 019import java.util.Set; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.aop.config.AopConfigUtils; 025import org.springframework.beans.factory.support.BeanDefinitionRegistry; 026import org.springframework.core.annotation.AnnotationAttributes; 027import org.springframework.core.type.AnnotationMetadata; 028 029/** 030 * Registers an auto proxy creator against the current {@link BeanDefinitionRegistry} 031 * as appropriate based on an {@code @Enable*} annotation having {@code mode} and 032 * {@code proxyTargetClass} attributes set to the correct values. 033 * 034 * @author Chris Beams 035 * @since 3.1 036 * @see org.springframework.cache.annotation.EnableCaching 037 * @see org.springframework.transaction.annotation.EnableTransactionManagement 038 */ 039public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { 040 041 private final Log logger = LogFactory.getLog(getClass()); 042 043 /** 044 * Register, escalate, and configure the standard auto proxy creator (APC) against the 045 * given registry. Works by finding the nearest annotation declared on the importing 046 * {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass} 047 * attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if 048 * {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use 049 * subclass (CGLIB) proxying. 050 * <p>Several {@code @Enable*} annotations expose both {@code mode} and 051 * {@code proxyTargetClass} attributes. It is important to note that most of these 052 * capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME 053 * single APC}. For this reason, this implementation doesn't "care" exactly which 054 * annotation it finds -- as long as it exposes the right {@code mode} and 055 * {@code proxyTargetClass} attributes, the APC can be registered and configured all 056 * the same. 057 */ 058 @Override 059 public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 060 boolean candidateFound = false; 061 Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); 062 for (String annType : annTypes) { 063 AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); 064 if (candidate == null) { 065 continue; 066 } 067 Object mode = candidate.get("mode"); 068 Object proxyTargetClass = candidate.get("proxyTargetClass"); 069 if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && 070 Boolean.class == proxyTargetClass.getClass()) { 071 candidateFound = true; 072 if (mode == AdviceMode.PROXY) { 073 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); 074 if ((Boolean) proxyTargetClass) { 075 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); 076 return; 077 } 078 } 079 } 080 } 081 if (!candidateFound && logger.isWarnEnabled()) { 082 String name = getClass().getSimpleName(); 083 logger.warn(String.format("%s was imported but no annotations were found " + 084 "having both 'mode' and 'proxyTargetClass' attributes of type " + 085 "AdviceMode and boolean respectively. This means that auto proxy " + 086 "creator registration and configuration may not have occurred as " + 087 "intended, and components may not be proxied as expected. Check to " + 088 "ensure that %s has been @Import'ed on the same class where these " + 089 "annotations are declared; otherwise remove the import of %s " + 090 "altogether.", name, name, name)); 091 } 092 } 093 094}