概述
AutoProxyRegistrar
是一个ImportBeanDefinitionRegistrar
,它会检测导入者类上的某个注解是否带有属性mode
和proxyTargetClass
,如果检测到这些属性,在mode
为PROXY
时,它会向容器注册一个自动代理创建器auto proxy creator
。
AutoProxyRegistrar
可以被某个配置类这么使用 :
@Import(AutoProxyRegistrar.class)
// 同时该配置类还应该使用带有 mode/proxyTargetClass 属性的另外一个注解
或者类似Spring
框架自身这么使用AutoProxyRegistrar
:
// 1. 定义一个 AdviceModeImportSelector, 它使用到了 AutoProxyRegistrar
public class TransactionManagementConfigurationSelector extends
AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),...};
...
}
}
...
}
// 2. 上面所定义的 TransactionManagementConfigurationSelector 被另外一个注解类所使用
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// ...
}
// 3. 注解类 @EnableTransactionManagement 被某个配置类所使用
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
// ...
public static class CglibAutoProxyConfiguration {
}
AutoProxyRegistrar
核心的逻辑在于其方法registerBeanDefinitions
,该方法会遍历导入者类上使用的所有注解,找到第一个带有属性mode/proxyTargetClass
属性的注解,如果这些属性不为空,并且mode/proxyTargetClass
属性的类型为AdviceMode/Boolean
,则会在mode
属性值为PROXY
时,调用AopConfigUtils#registerAutoProxyCreatorIfNecessary
向容器注册一个自动代理创建器auto proxy creator
(可以使用缩写APC
表示),实现类使用InfrastructureAdvisorAutoProxyCreator
。
如果AutoProxyRegistrar#registerBeanDefinitions
在导入者类上的注解中找不到符合条件的mode/proxyTargetClass
属性,则会输出日志 :
AutoProxyRegistrar was imported but no annotations were found having both ‘mode’ and ‘proxyTargetClass’ attributes of type AdviceMode and boolean respectively. This means that auto proxy creator registration and configuration may not have occurred as intended, and components may not be proxied as expected. Check to ensure that AutoProxyRegistrar has been @Import’ed on the same class where these annotations are declared; otherwise remove the import of AutoProxyRegistrar altogether.
源代码
源代码版本 : spring-context-5.1.5.RELEASE
package org.springframework.context.annotation;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
/**
* Registers an auto proxy creator against the current BeanDefinitionRegistry
* as appropriate based on an @Enable* annotation having mode and
* proxyTargetClass attributes set to the correct values.
*
* @author Chris Beams
* @since 3.1
* @see EnableAspectJAutoProxy
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
/**
* Register, escalate, and configure the standard auto proxy creator (APC) against the
* given registry. Works by finding the nearest annotation declared on the importing
* @Configuration class that has both mode and proxyTargetClass
* attributes. If mode is set to PROXY, the APC is registered; if
* proxyTargetClass is set to true, then the APC is forced to use
* subclass (CGLIB) proxying.
*
* Several @Enable* annotations expose both mode and
* proxyTargetClass attributes. It is important to note that most of these
* capabilities end up sharing a AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
* single APC. For this reason, this implementation doesn't "care" exactly which
* annotation it finds -- as long as it exposes the right mode and
* proxyTargetClass attributes, the APC can be registered and configured all
* the same.
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate =
AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}