spring源码学习(二)——ConfigurationClassPostProcessor(BeanFactory后置处理器的执行)

spring源码学习(一)——ioc初始化
spring源码学习(三)——初始化bean
spring源码学习(四)——aop

1.2.2 ConfigurationClassPostProcessor(BeanFactory后置处理器的执行)

在获取到BeanFactory后,就会执行invokeBeanFactoryPostProcessors(beanFactory)方法,执行BeanFactoryPostProcessor相应的方法。BeanFactoryPostProcessor中有一个非常重要的实现就是ConfigurationClassPostProcessor。它的主要功能是参与BeanFactory的建造,在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import、@Bean等注解。在执行过程中,会先执行postProcessBeanDefinitionRegistry(),然后执行postProcessBeanFactory().

在看代码之前,先思考下我的两个疑问在@Configuration配置类里,1.@Bean方法的形参为什么自动会去容器中找到对应的bean注入,2.在@Bean方法中调用其他@Bean方法为什么返回的也是容器中的单例对象?这是我很好奇的,那接下来就看看在代码中,能不能解决我的疑惑吧。首先,我们来看看postProcessBeanDefinitionRegistry()方法

@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);

		processConfigBeanDefinitions(registry);
	}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			// checkConfigurationClassCandidate()会判断一个是否是一个配置类,并为BeanDefinition设置属性为lite或者full。
			// 在这儿为BeanDefinition设置lite和full属性值是为了后面在使用
			// 如果加了@Configuration,那么对应的BeanDefinition为full;
			// 如果加了@Bean,@Component,@ComponentScan,@Import,@ImportResource这些注解,则为lite。
			//lite和full均表示这个BeanDefinition对应的类是一个配置类
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		//解析@configuration注解的类
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			// 解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
			// 注意:这一步只会将加了@Configuration注解以及通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap中
			// 通过其他注解(例如@Import、@Bean)的方式,在parse()方法这一步并不会将其解析为BeanDefinition放入到BeanDefinitionMap中,而是先解析成ConfigurationClass类
			// 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的
			parser.parse(candidates);
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			// 将上一步parser解析出的ConfigurationClass类加载成BeanDefinition
			// 实际上经过上一步的parse()后,解析出来的bean已经放入到BeanDefinition中了,但是由于这些bean可能会引入新的bean,
			// 例如实现了ImportBeanDefinitionRegistrar或者ImportSelector接口的bean,或者bean中存在被@Bean注解的方法
			// 因此需要执行一次loadBeanDefinition(),这样就会执行ImportBeanDefinitionRegistrar或者ImportSelector接口的方法或者@Bean方法
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		//将ImportRegistry注册为Bean,以支持ImportAware @Configuration类
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}
	}

因为这个方法太长,所以就留了一些比较重要的代码。可以看到核心是parser.parse(candidates)和this.reader.loadBeanDefinitions(configClasses)这两个方法。parser.parse(candidates)方法最终会调用ConfigurationClassParser#doProcessConfigurationClass方法

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		//处理Component
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}

		//处理PropertySource
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
		}

		//处理任何@ComponentScan
		//先找出类上的@ComponentScan和@ComponentScans注解的所有属性(例如basePackages等属性值)
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// 解析@ComponentScan和@ComponentScans配置的扫描的包所包含的类
				// (BeanDefinition可以理解为等价于BeanDefinitionHolder)
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				//通过上一步扫描包下的类,有可能扫描出来的bean中可能也添加了ComponentScan或者ComponentScans注解.
				//所以这里需要循环遍历一次,进行递归(parse),继续解析,直到解析出的类上没有ComponentScan和ComponentScans
				// (这时这一步解析出componentScans为空列表,不会进入到if语句,递归终止)
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 同样,这里会调用ConfigurationClassUtils.checkConfigurationClassCandidate()方法来判断类是否是一个配置类
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		//处理@Import 这一步只会将import注册的bean变为ConfigurationClass
		processImports(configClass, sourceClass, getImports(sourceClass), true);
		
		//处理@ImportResource注解引入的配置文件
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}
		//处理@bean
		//获取类中所有@bean的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);
	}

这里只有@Configuration注解以及通过@ComponentScan注解扫描的类才会加入到BeanDefinitionMap,其他的则会解析成ConfigurationClass对象。然后再调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions方法将ConfigurationClass类加载成BeanDefinition。

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}
private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

		//是否需要跳过
		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}
		// 如果一个bean是通过@Import(ImportSelector)的方式添加到容器中的,那么此时configClass.isImported()返回的是true
		// 而且configClass的importedBy属性里面存储的是ConfigurationClass就是将bean导入的类
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		//处理@bean的方法
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		// 如果bean上存在@Import注解,且import的是一个实现了ImportBeanDefinitionRegistrar接口,则执行ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

我们重点关注下@Bean的处理方法,看看能不能解决我的两个疑惑。可以看到这里遍历所有的@Bean的方法,调用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod方法

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
		// 获取配置类以及注解方法的相关信息
		ConfigurationClass configClass = beanMethod.getConfigurationClass();
		MethodMetadata metadata = beanMethod.getMetadata();
		String methodName = metadata.getMethodName();
		// 判断是否需要跳过这个类
		...
		// 提取@Bean注解的属性
		AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
		// 获取@Bean注册的别名
		List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
		String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
		// 注册所有的别名
		for (String alias : names) {
			this.registry.registerAlias(beanName, alias);
		}
		// 是否允许覆盖已存在的定义(判断依据来自isOverriddenByExistingDefinition方法,这里不做展开)
		if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
		...
		}

		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
		beanDef.setResource(configClass.getResource());
		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

		//是否是静态方法
		if (metadata.isStatic()) {
			// static @Bean method
			if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
				beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
			} else {
				beanDef.setBeanClassName(configClass.getMetadata().getClassName());
			}
			beanDef.setUniqueFactoryMethodName(methodName);
		} else {
			//设置FactoryBeanName,FactoryMethodName
			beanDef.setFactoryBeanName(configClass.getBeanName());
			beanDef.setUniqueFactoryMethodName(methodName);
		}

		if (metadata instanceof StandardMethodMetadata) {
			beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
		}

		//设置AutowireMode属性,之后@bean创建实例,形参会去getBean,容器中获取
		beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
				SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

		AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

		Autowire autowire = bean.getEnum("autowire");
		if (autowire.isAutowire()) {
			beanDef.setAutowireMode(autowire.value());
		}
		//设置各种参数如:autowireCandidate  initMethod destroyMethod
		...
		// Scope的代理信息获取
		ScopedProxyMode proxyMode = ScopedProxyMode.NO;
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
		if (attributes != null) {
			beanDef.setScope(attributes.getString("value"));
			proxyMode = attributes.getEnum("proxyMode");
			if (proxyMode == ScopedProxyMode.DEFAULT) {
				proxyMode = ScopedProxyMode.NO;
			}
		}

		BeanDefinition beanDefToRegister = beanDef;
		// 如果存在Scope代理,则使用代理类定义覆盖原有的类定义
		if (proxyMode != ScopedProxyMode.NO) {
			BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
					new BeanDefinitionHolder(beanDef, beanName), this.registry,
					proxyMode == ScopedProxyMode.TARGET_CLASS);
			beanDefToRegister = new ConfigurationClassBeanDefinition(
					(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
		}
		this.registry.registerBeanDefinition(beanName, beanDefToRegister);
	}

这里主要关注BeanDefinition的AutowireMode属性被设置成AUTOWIRE_CONSTRUCTOR,并设置了FactoryBeanName,FactoryMethodName。这关系到后面创建bean实例的时候,解决形参注入的问题。现在先不继续讨论,到这里postProcessBeanDefinitionRegistry已经结束了。接来下看看postProcessBeanFactory方法,这个方法主要做了两件事:

		// 对加了@Configuration注解的配置类进行Cglib代理
		enhanceConfigurationClasses(beanFactory);
		// 添加一个BeanPostProcessor后置处理器
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));

先来看看enhanceConfigurationClasses方法

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
			beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
			// Set enhanced subclass of the user-specified bean class
			Class<?> configClass = beanDef.getBeanClass();
			//设置代理
			Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
			if (configClass != enhancedClass) {
				if (logger.isTraceEnabled()) {
					logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
							"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
				}
				//改变beanDefiniton的beanClass
				beanDef.setBeanClass(enhancedClass);
			}
		}

先将类设置代理,然后将返回的代理类的class属性设置到BeanDefinition中,完成代理。ConfigurationClassEnhancer#enhance中完成了cglib动态代理的创建

public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
		//如果已经被代理过直接返回
		if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
			return configClass;
		}
		//否则创建代理,核心代码为 newEnhancer()
		Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
		if (logger.isTraceEnabled()) {
			logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
					configClass.getName(), enhancedClass.getName()));
		}
		return enhancedClass;
	}
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
		Enhancer enhancer = new Enhancer();
		//将配置类设置成父类,cglib基于继承
		enhancer.setSuperclass(configSuperClass);
		enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
		enhancer.setUseFactory(false);
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
		enhancer.setCallbackFilter(CALLBACK_FILTER);
		enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
		return enhancer;
	}

这里设置的回调过滤CALLBACK_FILTER对应三种:

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

	private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);

NoOp.INSTANCE就是什么都不做,BeanFactoryAwareMethodInterceptor为代理对象的beanFactory属性进行增强,负责拦截 BeanFactoryAware#setBeanFactory方法的调用,用于获取BeanFactory对象,因为增强的配置类实现了EnhancedConfiguration接口(也就是实现了BeanFactoryAwar接口)。BeanMethodInterceptor对加了@Bean注解的方法进行增强。我的第二个疑惑在这里就找到了答案。在BeanMethodInterceptor中,如果不是Object并且有@Bean注解,则执行intercept

public boolean isMatch(Method candidateMethod) {
			return (candidateMethod.getDeclaringClass() != Object.class &&
					!BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
					BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
		}
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
					MethodProxy cglibMethodProxy) throws Throwable {

			ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
			//拿到beanName
			String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
			//判断当前线程调用的方法名称和动态代理调用的方法名称是否一致,比较名称和参数,一致的说明是初次实例化调用,invoke父类方法
			//不一致说明不是初次实例化调用(在其他方法中调用),此时不在进行实例化,而是直接从BeanFactory中获取
			if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
				//调用方法
				return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
			}
			//不一致调用getBean
			return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
		}

执行@configuration类中的方法时,执行第一个@bean方法,会先走intercept方法,因为是初次实例化,则直接进行@Bean方法中的逻辑,在方法中,如果调用了其他的@Bean方法,则会比较两个bean方法名称与参数,如果不一致,就会去容器中获取。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值