本文共 16390 字,大约阅读时间需要 54 分钟。
接下来,我们对 Bean 的扫描与注册进行探究,一个 Java 类是如何变成一个 Bean 的呢,它中间走过了怎样的历程,这就是我们本章所要讨论的问题。
在进行分析前,各位胖友可以先看一下思维导图,该思维导图详细记录了源码的每一步流程,并且每一步都有详细的注释,在在线地址可以看到注释,如下:
本次我们将对 refresh 方法进行分析,在这个方法里面有 12 个方法,分别做了不同的事,我们将一步一步进行揭秘。
1、prepareRefresh
这个方法包括准备工作,设置启动时间,是否激活标识位(容器是否可用),初始化属性源配置,不是很重要。
2、obtainFreshBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
准备工作,初始化Bean工厂,得到 beanFactory, DefaultListableBeanFactory 实现了 ConfigurableListableBeanFactory 严格来说,Bean 生命周期的开始。
3、prepareBeanFactory
prepareBeanFactory(beanFactory);
准备 Bean 工厂,Bean 声明周期的开始,下面是在这个方法里面做的一些重要的事。
//类加载器beanFactory.setBeanClassLoader(getClassLoader());//bean的表达式解释器beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//Property和String的转化beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.//Spring 添加一个后置处理器,能够在bean中获得各种Aware (重要)beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
在这里添加了一个后置处理器 new ApplicationContextAwareProcessor(this),如果一个类实现了各种 Aware,就会拥有相对应的功能,这是对 Spring 进行扩展的方式。我们可以看一下,这个后置处理器中的一个非常重要的方法。
比如这个代码 instanceof ApplicationContextAware,一个 Bean 实现了 ApplicationContextAware这个接口,提供setter 方法,就能得到 applicationContext ,这就是真个Spring 环境,我们就可以在代码中动态注册和改变一个 Bean 的属性。
private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } //当一个对象实现了ApplicationContextAware对象只需要提供setter就能得到applicationContext if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } }
4、postProcessBeanFactory
这是一个空方法,Spring 后期可能会做扩展。
5、invokeBeanFactoryPostProcessors
重要的方法,实现了 Bean 的扫描与注册。
我们可以跟进这个方法,首先定义了两个 集合,具体作用注释给出了。
//存放程序员自己添加的实现了BeanFactoryPostProcessor的ListregularPostProcessors = new ArrayList<>();//存放程序员自己添加的实现了BeanDefinitionRegistryPostProcessor的List registryProcessors = new ArrayList<>();
注意一个关键词,程序员自己添加的,何为自己添加,也就是自己定义一个类,然后实现 BeanFactoryPostProcessor 或者 BeanDefinitionRegistryPostProcessor 这两个接口,然后调用下面方法添加进去,加@Component 不算。
//自定义的后置处理器//applicationContext.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
紧接着,就会处理 实现了 BeanDefinitionRegistryPostProcessor 的类,调用 postProcessBeanDefinitionRegistry 这个方法,然后把 实现了 BeanFactoryPostProcessor 的类放到一个集合里面去。这里并没有处理。
PS: BeanFactoryPostProcessor 是 BeanDefinitionRegistryPostProcessor 的父类。for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; //处理 registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } }
然后又定义了一个集合,存放Spring自己定义的 BeanDefinitionRegistryPostProcessor。
//currentRegistryProcessors Spring内部自己实现这个接口的对象ListcurrentRegistryProcessors = new ArrayList<>();
通过类型的到自己定义的 BeanDefinitionRegistryPostProcessor,然后放到 currentRegistryProcessors 里面去。
我们可以知道这里只有一个类,也就是 ConfigurationClassPostProcessor ,前面一章我们讲到的创世纪的类,是在最开始的时候注册到 BeanDefinition 里面去的。
String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //在这里注册了 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } }
然后执行所有实现了 BeanDefinitionRegistryPostProcessor 的类。
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
我们点进去,他会执行 ConfigurationClassPostProcessor 这个类的 postProcessBeanDefinitionRegistry 这个方法。具体我们可以看一下思维导图。
首先会得到容器中已经注册的 BeanDefinition ,然后进行判断是否为以下三个条件。String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } //判断是不是5种类型类,添加到list中 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } }
1)isFullConfigurationClass
判断 BeanDefinition 的属性是不是 FULL。
2)isLiteConfigurationClass
判断 BeanDefinition 的属性是不是 LITE。
3)checkConfigurationClassCandidate
判断类是否有相关注解,并设置相关的属性 FULL 或 LITE,如果是 加了 @Configuration 注解就设置为 FULL,否则就看看看是不是以下四个注解,如果是就设置为 LITE,并放到集合中去。
static { candidateIndicators.add(Component.class.getName()); candidateIndicators.add(ComponentScan.class.getName()); candidateIndicators.add(Import.class.getName()); candidateIndicators.add(ImportResource.class.getName());}
//可能有多个配置类重复了Setcandidates = new LinkedHashSet<>(configCandidates);//alreadyParsed处理过就放到里面Set alreadyParsed = new HashSet<>(configCandidates.size());
把符合条件的类放到 candidates 里面去重后,然后进行解析,解析代码如下,可以根据思维导图看。
parser.parse(candidates);
首先,比较重要的一点,就是把加了 @ComponentScans 注解的类拿出来,进行解析,解析后,会对加了 @ComponentScans 的类进行扫描,在这里,当吧所有的类进行扫描后,还会递归调用 checkConfigurationClassCandidate 方法判断一下是不是上面所提的5种类型。
//处理所有@ComSetcomponentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately //扫描普通类,componentScan = com.javahly.xxx //扫描@Component Set scannedBeanDefinitions = //解析,真正解析扫描包 this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // 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(); } //检查扫描出的类是否有@Configuration并设置FULL和LITE if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } }
进入上面代码中的 parse 方法,我们可以看到,这里 new 了一个 ClassPathBeanDefinitionScanner 对包进行扫描,也就是实际扫描的是这里的ClassPathBeanDefinitionScanner ,而不是上一章的初始化时的 ClassPathBeanDefinitionScanner。
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
然后调用 doScan 方法进行扫描包
protected SetdoScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { //扫描basePackage路径下的java文件 //并把它转成BeanDefinition Set candidates = findCandidateComponents(basePackage); //拿出对象 for (BeanDefinition candidate : candidates) { //解析scope属性 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { //ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);(findCandidateComponents) //如果这个类是AbstractBeanDefinition的子类 //则为他设置默认值,如lazy,init,destroy postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } //检查并且处理常用注解 //这里的处理主要是把常用注解的值设置到AnnotatedBeanDefinition当中 //当前这个类必须是AnnotatedBeanDefinition类型,也就是加了注解的类 if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); //put到Map registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions;}
最后,把扫描出来的类转化为 BeanDefinition 后,设置属性后,就放到了一个 Map 里面。
this.beanDefinitionMap.put(beanName, beanDefinition);
至此,普通的已经完成注册了,紧接着,就会处理加了 @Import 注解的类
processImports(configClass, sourceClass, getImports(sourceClass), true);
for (SourceClass candidate : importCandidates) { //是不是ImportSelector if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports //得到这个类 Class candidateClass = candidate.loadClass(); //反射一个对象 ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { //回调 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); CollectionimportSourceClasses = asSourceClasses(importClassNames); //递归,Import的类本身有没有被Import //看返回的这个数组中的类是不是有@Import,有就处理,没有就放到Map里面 //importSourceClasses 判断这个类是哪一种Import processImports(configClass, currentSourceClass, importSourceClasses, false); } } //是不是ImportBeanDefinitionRegistrar else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class //Import普通类 //否则,加入importStack,调用processConfigurationClass处理 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); }}
@import 的类型可能有三种,处理方式如下
ImportSelector 先把这个类放到 configurationClasses中 ,然后再注册
ImportBeanDefinitionRegistrar 放到 importBeanDefinitionRegistrars, 然后再注册
Import普通类 先把这个类放到 configurationClasses中,然后再注册
当扫描完成后,就会进行一些验证
parser.validate();
然后,就会调用以下方法注册,@Bean,Xml,Import 的 Bean,至此,所有的 Bean 就完成了注册。
this.reader.loadBeanDefinitions(configClasses);
至此,就解析完成了 实现 BeanDefinitionRegisterPostProcessor 的类,然后就会执行实现了 BeanFactoryPostProcessors 的类,也就是 BeanDefinitionRegisterPostProcessor 的父类 。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
点进去,这是也是执行 ConfigurationClassPostProcessor 类的 postProcessBeanFactory 方法,里面执行这么一个方法,产生 CGLIB 代理。
enhanceConfigurationClasses(beanFactory);
得到所有的 BeanDefinition 看看有没有全注解类,也就是前面设置了 FULL 的类,加了 @Configuration 的类,如果有,就给这个类添加 CGLIB 动态代理,并添加属性 添加属性 &&beanFactory。
for (String beanName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName); //判断是否是一个全注解类 //full和lite if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) { if (!(beanDef instanceof AbstractBeanDefinition)) { throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" + beanName + "' since it is not stored in an AbstractBeanDefinition subclass"); } else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) { logger.warn("Cannot enhance @Configuration bean definition '" + beanName + "' since its singleton instance has been created too early. The typical cause " + "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " + "return type: Consider declaring such methods as 'static'."); } configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef); }}if (configBeanDefs.isEmpty()) { // nothing to enhance -> return immediately return;}
//不加@Configuration不会进这个方法 ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer(); for (Map.Entryentry : 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); try { // Set enhanced subclass of the user-specified bean class Class configClass = beanDef.resolveBeanClass(this.beanClassLoader); if (configClass != null) { //完成cglib动态代理 Class enhancedClass = enhancer.enhance(configClass, this.beanClassLoader); if (configClass != enhancedClass) { if (logger.isDebugEnabled()) { logger.debug(String.format("Replacing bean definition '%s' existing class '%s' with " + "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName())); } beanDef.setBeanClass(enhancedClass); } } } catch (Throwable ex) { throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex); } }
private static final String BEAN_FACTORY_FIELD = "$$beanFactory";
为什么要添加动态代理,因为如果不加动态带来,当我们使用 @Bean 声明一个 Bean时,如果在一个@Bean方法里面调用另一个 @Bean 方法,就会产生两个实例,违背了单例原则,添加了代理类后,首先会进行判断,如果容器里面有这个 Bean,他就会调用 $$beanFactory 去直接 get,而不是又 new 一个。
最后我们来总结一下比较重要的流程:
首先我们进入 refresh 方法里面,会调用 12 个方法(这里先讲前 5 个)
第一个 prepareRefresh 方法,这里进行一些准备工作;第二个 obtainFreshBeanFactory 这里得到之前实例化的工厂;
第三个 prepareBeanFactory,这里对 beanFactory 进行一些简单的初始化工作;
第四个 postProcessBeanFactory 空方法;
第五个 invokeBeanFactoryPostProcessors,也是最重要的方法之一,在这个方法里面,会对实现了 BeanDefinitionRegistryPostProcessors 和 BeanFactoryPostProcessors 的类进行解析,其中包括我们自己定义的,也包括 Spring 内置的。
解析的顺序是先解析 BeanDefinitionRegistryPostProcessors ,再解析BeanFactoryPostProcessors。
这里会解析 Spring 内置的非常很重要的一个类,ConfigurationClassPostProcessor ,
首先会执行 postProcessBeanDefinitionRegistry 方法,在这里,会判断已经注册的类是不是加了@Configuration,如果是,就设置一个值为 FULL,不是就判断是不是其余四种,并设置为 LITE,并对加了 @ComponentScan 的类进行扫描,然后还会递归判断扫描出来的类是不是加了 @Configuration,以及还会判断扫描出来的类是普通类(加了 @Component的),还是加了@Import,的,然后进行相对应的注册。
然后会执行 BeanFactoryPostProcess 的 postProcessBeanFactory 方法,这里会判断有没有 FULL 类型的类,如果有,就添加 CGLIB 动态代理,作用是,当我们使用 @Bean 声明一个 Bean时,如果在一个@Bean方法里面调用另一个 @Bean 方法,就会产生两个实例,违背了单例原则,添加了代理类后,首先会进行判断,如果容器里面有这个 Bean,他就会调用 $$beanFactory 去直接 get,而不是又 new 一个。
为了更加直观的展现源码的调用过程,我绘制了一张思维导图!
为了更加直观的展现源码的调用过程,我绘制了一张思维导图! 为了更加直观的展现源码的调用过程,我绘制了一张思维导图!公众号:【星尘Pro】
github:
推荐阅读
转载地址:http://qdfsi.baihongyu.com/