Configuration涉及的Full&Lite模式

前提:使用注解@Configuration是为了提前初始化一批特性,不要将其作为@Component注解特性使用。

Full 模式最大的特点是会给配置类通过 CGLIB 生成一个代理,所有被 @Bean 注解标记的方法将来都是通过代理方法进行调用,所以@Bean 注解标记的方法不能被关键字Final、Private修饰。

Lite模式:去除配置类上的 @Configuration 注解,或者去除之后添加 @Component 注解,又或者使用 @ComponentScan、@ImportResource、@Import 等注解标记类、声明在普通(plain old class)类中的@Bean 注解标记的方法。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
	@AliasFor(annotation = Component.class)
	String value() default "";

	/**
	 * 指定内部注解@Bean指定的bean是否需要代理处理
	 */
	boolean proxyBeanMethods() default true;

}
class ConfigurationClassParser {
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass){
		...
		// 处理注解 @ComponentScan,即启动类@ComponentScan存在的所有属性
		AnnotationMetadata am = sourceClass.getMetadata();
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
												am, ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(am, ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				String className = sourceClass.getMetadata().getClassName();
				//通过启动类获取到扫描路径,即启动类所在的路径以及该路径下所有的子路径
				Set<BeanDefinitionHolder> scannedBeanDefinitions = componentScanParser.parse(componentScan, className);
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 确定候选类的模式Full or Lite
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		...
		return null;
	}
}

1、获取@Configuration候选类

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
	protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {//basePackages就是启动类所在的路径以及其子路径
			// 利用类加载器获取路径basePackage下所有候选类的资源URL~Resource
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata sm = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(sm.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {// 确保容器注册表中只能存在当前bean唯一的BeanDefinition
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(sm, definitionHolder, registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}
}

每个候选类初始被封装成ScannedGenericBeanDefinition,核心属性就是候选类的资源URL~Resource。但是在添加容器注册表之前为啥进一步封住成BeanDefinitionHolder?

2、容器注册表注册候选类的BeanDefinition

public abstract class BeanDefinitionReaderUtils {
	//registry:DefaultListableBeanFactory
	public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry){
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
}

3、确定候选类的模式之Full or Lite

abstract class ConfigurationClassUtils {
	public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory msf) {
		...
		AnnotationMetadata metadata;
		String className = (AnnotatedBeanDefinition) beanDef).getMetadata().getClassName();
		if (beanDef instanceof AnnotatedBeanDefinition && className.equals(className)) {
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
					EventListenerFactory.class.isAssignableFrom(beanClass)) {
				return false;
			}
			metadata = AnnotationMetadata.introspect(beanClass);
		}else {
			MetadataReader metadataReader = msf.getMetadataReader(className);
			metadata = metadataReader.getAnnotationMetadata();
		}
	
		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		//查看候选类中属性proxyBeanMethods,默认值为true
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			// 如果proxyBeanMethods = true则为Full默认
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}else if (config != null || isConfigurationCandidate(metadata)) {
			//否则为Lite模式
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}else {
			return false;
		}
		...
		return true;
	}
}

4、候选类尝试Cglib代理处理

final class PostProcessorRegistrationDelegate {
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> bp) {

			...
			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			...
			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(bp, beanFactory);
		}
		...
	}
	
	private static void invokeBeanFactoryPostProcessors(
		Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			// ConfigurationClassPostProcessor
			postProcessor.postProcessBeanFactory(beanFactory);
		}
	}
}
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
		
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		int factoryId = System.identityHashCode(beanFactory);
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}
		enhanceConfigurationClasses(beanFactory);
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}
	
	public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
			...
			if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {// Full模式
				...
				configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
			}
		}
		if (configBeanDefs.isEmpty()) {
			return;
		}

		ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
		for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
			AbstractBeanDefinition beanDef = entry.getValue();
			// If a @Configuration class gets proxied, always proxy the target class
			// org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass
			beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			// Set enhanced subclass of the user-specified bean class
			Class<?> configClass = beanDef.getBeanClass();
			//候选类生成最终Cglib代理类
			Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
			if (configClass != enhancedClass) {
				beanDef.setBeanClass(enhancedClass);
			}
		}
	}
}

5.目标类@Bean注解方法的代理

class ConfigurationClassEnhancer {
	private static final Callback[] CALLBACKS = new Callback[] {
			new BeanMethodInterceptor(),
			new BeanFactoryAwareMethodInterceptor(),
			NoOp.INSTANCE
	};
	
	private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {

		@Override
		@Nullable
		public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
					MethodProxy cglibMethodProxy) throws Throwable {

			ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
			String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
			...
			if (factoryContainsBean(beanFactory, "&" + beanName) &&
					factoryContainsBean(beanFactory, beanName)) {
				Object factoryBean = beanFactory.getBean("&"  + beanName);
				if (factoryBean instanceof ScopedProxyFactoryBean) {
				}else {
					return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
				}
			}
			//如果目标类目标方法之间互相调用,则不满足以下条件
			if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
				return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
			}
			//尝试从IOC容器中获取当前需要的bean实例
			return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
		}

		private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
				ConfigurableBeanFactory beanFactory, String beanName) {
				Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
						beanFactory.getBean(beanName));
				...
				Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
				if (currentlyInvoked != null) {
					String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
					beanFactory.registerDependentBean(beanName, outerBeanName);
				}
				return beanInstance;
		}
	}
}

BeanMethodInterceptor拦截器主要针对目标类中@Bean注解方法的调用,此时调用包含两种类型:

  • 目标类代理类调用目标方法。
  • 目标方法内部存在彼此之间的调用。
@Configuration//Full模式
public class LtsConfig {

    @Bean
    LtsClient ltsClient(){
        return new LtsClient();
    }

    @Bean
    public Lts lts(){
        return new Lts();
    }

    @Bean
    public Log log(){
        Log log = new Log();
        log.setLts(lts());// 尝试从IOC容器中获取当前需要的bean实例
        return log;
    }
}

在 Full 模式下,log 中的 Lts 对象和 lts 方法注册到 Spring 容器的 Lts 对象是同一个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值