likes
comments
collection
share

12.postProcessBeanDefinitionRegistry源码(上)

作者站长头像
站长
· 阅读数 13

鉴于ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry(registry)的源码太长和掘金的字数限制分为2部分去讲。

第一部分主要是讲遍历候选的BeanDefinition,然后根据BeanDefinition的属性configClass判断是否是配置类,如果是配置类加入候选配置类集合,第二部分对候选配置类集合进行解析。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 一个工厂的后置处理器只会执行一次
        // 具体逻辑是根据对象的hashCode判断是否被调用过
        int registryId = System.identityHashCode(registry);
        //如果被调用过 那么抛出异常
        if (this.registriesPostProcessed.contains(registryId)) {
           throw new Exception("postProcessBeanDefinitionRegistry already called");
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
            throw new Exception("postProcessBeanDefinitionRegistry already called");
        }
        this.registriesPostProcessed.add(registryId);
        //重点代码跟进去!!!
        //重点代码跟进去!!
        //重点代码跟进去!
        processConfigBeanDefinitions(registry);
    }

ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry(registry)

核心逻辑在processConfigBeanDefinition()方法中。

processConfigBeanDefinitions源码

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    /**
     * registry就是DefaultListableBeanFactory
     * DefaultListableBeanFactory是bean工厂
     * 步骤1.获取所有已经注册的beanName放入候选数组candidateNames
     */
    String[] candidateNames = registry.getBeanDefinitionNames();

    /**
     * 步骤2.遍历候选数组candidateNames对应的BeanDefinition,判断BeanDefinition是否是配置类
     * 如果是配置类将BeanDefinition加入configCandidates
     * 比如下面配置类。
     *  @ComponentScan("com")
     *  public class Config { 
     *  }
     * 找到配置类后spring就知道从哪里开始扫描啦
     */
    for (String beanName : candidateNames) {
        // 根据beanName获得BeanDefinition
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        /***  
        BeanDefinition中有这么一个变量attributes,类型为LinkedHashMap用来存储属性值
        后面处理BeanDefinition时会给bd设置一个属性key为configurationClass,value为full或者lite
        如果attributes中存在key=configurationClass的属性且对应的值是full或者lite
        意味着已经处理过了,直接跳过。
        ***/
        //如果是 FULL 或者 LITE  那么跳过
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
           //啥也不做 说明被处理过了
        }
        /**** 
         checkConfigurationClassCandidate方法会判断是否是配置类
         并为BeanDefinition设置属性configurationClass为lite或者full或者false
         如果加了@Configuration的类,那么对应的BeanDefinition为full。
         如果加了@Component,@ComponentScan,@Import,@ImportResource这些注解的类
         或者是带有@Bean方法的类,则为lite。
         如果不是lite和full 返回的是false
         lite和full均表示这个BeanDefinition对应的类是一个配置类
         为BeanDefinition设置lite和full属性值是为了后面在使用
         具体可看代码 1.checkConfigurationClassCandidate
        ****/ 
        else if(ConfigurationClassUtils.checkConfigurationClassCandidate
                                      (beanDef, this.metadataReaderFactory)){
            //添加到候选配置集合中,后面统一处理
           //BeanDefinitionHolder对BeanDefinition和名字做了简单封装
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    //configCandidates放的是候选配置类
    //即带有如下注解的类
    //@Configuration @Component @ComponentScan @Import @ImportResource
    //或者是带有@Bean方法的类                        
    //如果没有候选配置类,就直接返回,啥也不执行
    if (configCandidates.isEmpty()) {
        return;
    }

    //步骤3
    //将配置类进行排序
    //我们可以提供多个配置类,然后在配置类上添加@Order注解决定配置类的先后调用顺序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    /**
     * 判断是否有自定义的beanName生成器,没有话就用默认的BeanNameGenerator
     * 因为后面会扫描出所有加入到spring容器中calss类
     * 然后把这些class解析成BeanDefinition类
     * 此时需要利用BeanNameGenerator为这些BeanDefinition生成beanName
     * 默认的BeanNameGenerator是类名首字母小写
     */
    SingletonBeanRegistry sbr = null;
    
  // DefaultListableBeanFactory是SingletonBeanRegistry类型
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        //localBeanNameGeneratorSet = false
        if (!this.localBeanNameGeneratorSet) {
            //步骤4
            //获取internalConfigurationBeanNameGenerator,返回的是null
            BeanNameGenerator generator = (BeanNameGenerator) 
                        sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    /**
     * 实例化ConfigurationClassParser是为了解析各个配置类即带@Configuration注解的类
     * 初始化ConfigurationClassParser的一些属性
     */
    ConfigurationClassParser parser = new ConfigurationClassParser(
                                    this.metadataReaderFactory, 
                                    this.problemReporter, this.environment,
                                    this.resourceLoader, 
                                    this.componentScanBeanNameGenerator, 
                                    registry);
    /**
     * 实例化两个set
     * candidates用于保存候选配置类
     * alreadyParsed用于保存已经解析过的配置类
     */
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    
    //注意 doWhile是在遍历registry.getBeanDefinitionNames()的for循环里
    do {
        // 开始扫描并注册包下的类
        // 在此处会解析配置类上的注解
        // 这一步只会将加了@Configuration注解以及@ComponentScan注解扫描的类加入到BeanDefinitionMap
        // 通过其他注解(例如@Import、@Bean)的方式,在parse()方法并不会将其解析为                           // BeanDefinition放入到BeanDefinitionMap中
        // 真正放入到map中是在下面的this.reader.loadBeanDefinitions()方法中实现的
        parser.parse(candidates);
        parser.validate();
        //获取本次扫描到的所有configurationClasses
        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已经放入BeanDefinitionMap中
        // 但是由于这些bean可能会引入新的bean
        // 例如实现了ImportBeanDefinitionRegistrar或者ImportSelector接口的bean
        // 或者bean中存在被@Bean注解的方法
        // 因此需要执行一次loadBeanDefinition()去
        // 处理ImportBeanDefinitionRegistrar或者@Import或者@从ImportedResource
        // 或者@Bean修饰的方法 来加载bd
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
        candidates.clear();
        // 这里判断registry.getBeanDefinitionCount() > candidateNames.length
        // 目的是为了知道reader.loadBeanDefinitions(configClasses)
        // 这一步有没有向BeanDefinitionMap中添加新的BeanDefinition
        // 实际上就是看配置类(例如AppConfig类会向BeanDefinitionMap中添加bean)
        // 如果有,registry.getBeanDefinitionCount()就会大candidateNames.length
        // 这样就需要再次遍历新加入的BeanDefinition,并判断这些bean是否已经被解析过了
        // 如果未解析,需要重新进行解析
        // 这里的AppConfig类向容器中添加的bean
        // 实际上在parser.parse()这一步已经全部被解析了
        // 所以为什么还需要做这个判断,目前没看懂,似乎没有任何意义。
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = 
                            new HashSet<>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add
                        (configurationClass.getMetadata().getClassName());
            }
            // 如果有未解析的类,则将其添加到candidates中
            // 这样candidates不为空,就会进入到下一次的while的循环中
            for (String candidateName : newCandidateNames) {
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = 
                        registry.getBeanDefinition(candidateName);
                    if(ConfigurationClassUtils
                       .checkConfigurationClassCandidate
                            (bd, this.metadataReaderFactory) &&
                    !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        candidates.add
                            (new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }while (!candidates.isEmpty());


    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton
            (IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        ((CachingMetadataReaderFactory) 
            this.metadataReaderFactory).clearCache();
    }
}

步骤总结

步骤1:遍历所有的BeanDefinitionName

方法伊始,我们拿到容器中所有的BeanDefinition的名字,包括系统内置的5个后置处理器及我们提供的Config配置类。

12.postProcessBeanDefinitionRegistry源码(上)

紧接着,循环遍历这些BeanDefinition,过滤掉spring内置的后置处理器,留下我们提供的配置类,解析配置类,完成扫描和注册,这个配置类只能解析使用一次。

那么spring如何过滤出我们提供的配置类以及如何保证只解析使用一次呢?

保证使用一次很简单,只要第一次解析使用完成后添加一个标志即可。在BeanDefinition维护一个变量, Map<String, Object> attributes = new LinkedHashMap<>();用来存储属性值。

如果该attributes中存在configurationClass这个键,且对应的值是full或者lite意味着已经处理过了,直接跳过。

下面的源码就是判断是否有该键值的:

private static final String CONFIGURATION_CLASS_FULL = "full";
private static final String CONFIGURATION_CLASS_LITE = "lite";

/*
判断是否是full
*/
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
    return CONFIGURATION_CLASS_FULL
                .equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}

/*
判断是否是lite
*/
public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
    return CONFIGURATION_CLASS_LITE
                .equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
}

/*
如果是@Configuration 就是full
*/
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
    return metadata.isAnnotated(Configuration.class.getName());
}

/*
如果是下面这些注解修饰的类或者是带有@Bean的方法类就是lite
candidateIndicators.add(Component.class.getName());
candidateIndicators.add(ComponentScan.class.getName());
candidateIndicators.add(Import.class.getName());
candidateIndicators.add(ImportResource.class.getName());
*/
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {

    if (metadata.isInterface()) {
        return false;
    }
    
    //下面这些注解修饰的类
    for (String indicator : candidateIndicators) {
        if (metadata.isAnnotated(indicator)) {
            return true;
        }
    }
    
    //带有@Bean的方法类
    return metadata.hasAnnotatedMethods(Bean.class.getName());
}

最关键的是如何筛选出我们的配置类?答案就是根据类型。

文章开头,我们通过代码往spring中添加我们的配置类context.register(Config.class);

我们跟进这行代码看spring是如何把Config转成BeanDefinition的,一直跟到doRegisterBean方法:

//beanClass就是Config.class
//自定义的Config被转成了AnnotatedGenericBeanDefinition类型
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

//... 中间省略...
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

// 这个方法名称直译过来就是----应用Scoped中的ProxyMode属性 
// 这个属性有什么用呢? 
// ProxyMode属性一共有下面几种取值 
// 1.DEFAULT:默认值,默认情况下取no 
// 2.NO:不开启代理 
// 3.INTERFACES:使用jdk动态代理 
// 4.TARGET_CLASS:使用cglib代理 
// 假设我们有一个单例的对象A,其中有一个属性B,B的作用域是session,这个时候容器在启动时创建A的过程中
// 需要为A注入属性B,但是属性B的作用域为session,这种情况下注入必定会报错的 
// 但当我们将ProxyMode属性配置为INTERFACES/TARGET_CLASS时,它会暴露一个代理对象
// ProxyMode可以配置代理对象的生成策略是使用jdk动态代理还是生成cglib动态代理
// 那么当我们在创建A时,会先注入一个B的代理对象而不是直接报错
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

//Register the given bean definition with the given bean factory.
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

由此可见自定义的Config被转成了AnnotatedGenericBeanDefinition类型,还记得之前讲过的BeanDefinition继承图吗,笔者不厌其烦的再次祭出BeanDefinition的继承图:

12.postProcessBeanDefinitionRegistry源码(上)

AnnotatedGenericBeanDefinition在最底层右面第二个的位置。

上文中的"注册时机"我们能看到,spring内置的后置处理器都是RootBeanDefinition类型的。

由此可见AnnotatedGenericBeanDefinition和RootBeanDefinition没有半毛钱关系,我们自然可以通过instanceof类型匹配关键字过滤出我们的配置类了!

由于我们的配置类目前既不是full也不是lite,接下来分析else分支校验候选配置类的源码:

else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
        configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}

    public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

            String className = beanDef.getBeanClassName();
            if (className == null || beanDef.getFactoryMethodName() != null) {
                return false;
            }

            AnnotationMetadata metadata;
            if (beanDef instanceof AnnotatedBeanDefinition &&
                    className.equals(((AnnotatedBeanDefinition) 
                                        beanDef).getMetadata().getClassName())) {
                
                metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
            }else if (beanDef instanceof AbstractBeanDefinition && 
                                ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
                
                Class<?> beanClass = 
                        ((AbstractBeanDefinition) beanDef).getBeanClass();
                metadata = new StandardAnnotationMetadata(beanClass, true);
            }else {
                try {
                    MetadataReader metadataReader =     
                            metadataReaderFactory.getMetadataReader(className);
                    metadata = metadataReader.getAnnotationMetadata();
                }
                catch (IOException ex) {
                    return false;
                }
            }
            //判断是否存在@Configuration注解
            //设置为FULL
            if (isFullConfigurationCandidate(metadata)) {
                beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
            }
            //判断是否存在@Bean修饰的方法的类或者被以下注解修饰的类
            //设置为LITE
            /*
            candidateIndicators.add(Component.class.getName());
            candidateIndicators.add(ComponentScan.class.getName());
            candidateIndicators.add(Import.class.getName());
            candidateIndicators.add(ImportResource.class.getName());
            */
            else if (isLiteConfigurationCandidate(metadata)) {
                beanDef.setAttribute
                    (CONFIGURATION_CLASS_ATTRIBUTE,CONFIGURATION_CLASS_LITE);
            }
            else {
                return false;
            }

            //解析order的value值作为属性设置进去
            Integer order = getOrder(metadata);
            if (order != null) {
                beanDef.setAttribute(ORDER_ATTRIBUTE, order);
            }
            return true;
        }

步骤2:如果符合以下条件,那么加入集合

@Configuration = full

@Component = lite

@Service = lite

@Component
public @interface Service {}

@Controller = lite

@Component
public @interface Controller {}

@Repository = lite

public @interface Repository {}

@ComponentScan = lite

@ComponentScans = lite

@ComponentScans({@ComponentScan(""),@ComponentScan("")})

@Import = lite

@ImportResource = lite

带@Bean注解的方法 = lite

跟进checkConfigurationClassCandidate这行代码,这行代码的意思是找到我们的配置类并获取到他的注解信息。

如果注解包含了@Configuration,则设置属性键值对configurationClass=full,会加入候选集合。

否则判断注解是否包含@Component、@ComponentScan、@Import、@ImportResource、@Bean注解的方法。如果是则设置键值对configurationClass=lite,会加入候选集合。

如果都不是则返回false,说明Config不是配置类,不会加入候选集合中。

看源码:

    public static boolean checkConfigurationClassCandidate(
                BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
            //获取class名字,这里是com.config.Config
            String className = beanDef.getBeanClassName();

            if (className == null || beanDef.getFactoryMethodName() != null) {
                return false;
            }
            AnnotationMetadata metadata;
            //判断BeanDefinition是否是AnnotatedBeanDefinition类型, 
            //AnnotatedGenericBeanDefinition实现了AnnotatedBeanDefinition
            //我们的配置类Config对应的BeanDefinition确实就是AnnotatedBeanDefinition类型
            if (beanDef instanceof AnnotatedBeanDefinition &&
                    className.equals(((AnnotatedBeanDefinition) 
                                      beanDef).getMetadata().getClassName())) {
                //获取配置类的注解信息
                metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
            }
            //如果BeanDefinition是AbstractBeanDefinition并且包装了业务类,  
            //RootBeanDefinition继承了如果BeanDefinition是AbstractBeanDefinition
            //spring内置的后置处理器确实是AbstractBeanDefinition类型的
            else if (beanDef instanceof AbstractBeanDefinition && 
                     ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
                //beanClass  =  ConfigurationClassPostProcesso
                Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
                //拿到注解信息
                metadata = new StandardAnnotationMetadata(beanClass, true);
            }else {
                try {
                    //既不是AnnotatedBeanDefinition类型也不是AbstractBeanDefinition类型
                    //或者是AbstractBeanDefinition类型但没有包装业务类
                    MetadataReader metadataReader = 
                            metadataReaderFactory.getMetadataReader(className);
                    metadata = metadataReader.getAnnotationMetadata();
                }
                catch (IOException ex) {
                    return false;
                }
            }
            //判断注解中是否包含了@Configuration注解
            if (isFullConfigurationCandidate(metadata)) {
                //设置属性,相当于beanDef.setAttribute("configurationClass","full")
                beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, 
                                                    CONFIGURATION_CLASS_FULL);
            }
            //判断注解中是否包含了@Component、ComponentScan、Import、ImportResource其中之一
            //或者是否有@Bean注解的方法。
            else if (isLiteConfigurationCandidate(metadata)) {
                //设置属性,相当于beanDef.setAttribute("configurationClass","lite")
                beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, 
                                                    CONFIGURATION_CLASS_LITE);
            }else {
                //实际上,如果你打断点仔细运行,你会发现,spring内置后置处理器都没有上面那些注解
                return false;
            }

            //如果有@Order注解,拿到注解的value值,并将值设置到属性中,后面执行会根据这个属性值的大小进行先后调用
            Integer order = getOrder(metadata);
            if (order != null) {
                beanDef.setAttribute(ORDER_ATTRIBUTE, order);
            }
            return true;
        }

由此可知,所谓的配置类就是要么含有@Configuration注解,要么含有@Component、@ComponentScan、@Import、@ImportResource其中之一,要么类中含有@Bean注解的方法。

注意其中 @Component包括他的子注解@Service、@Controller、@Repository

spring后续根据这些注解完成扫描和注册。

实际上上面的代码运行结束后,只有我们的配置类Config对应的BeanDefinition完成了属性值的设置,且返回true,

最后添加到集合configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

spring内置的后置处理器都没有上面所说的注解所以返回false,自然不会添加到集合中。

//如果扫描完毕没有配置类就直接返回
if (configCandidates.isEmpty()) {
  return;
}

如果,我们没有提供配置类,直接返回,后续也不会扫描和注册。也就是我们自定义的bean不会被引入。

运行到这里的时候我们注册了自定义配置类对应的BeanDefinition, 并且BeanDefinition对应的属性configurationClass是full。

步骤3:对配置类进行排序

     configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });

上面checkConfigurationClassCandidate代码中的最后处理了@Order注解,将他的值放到了属性中,在这里,如果你有多个配置类,进行排序,后面会按照顺序进行处理。打个比方:

    @ComponentScan("com")
    @Order(1)
    public class Config {
    }

    @Service
    @Order(2)
    public class Config2 {
    }

    public class SpringTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(Config.class);
            context.register(Config2.class);
            context.refresh();
        }
    }

12.postProcessBeanDefinitionRegistry源码(上)

步骤4:获取BeanName生成器

    SingletonBeanRegistry sbr = null;
            /**
             * 由于当前传入的是DefaultListableBeanFactory是SingletonBeanRegistry的子类
             */
            if (registry instanceof SingletonBeanRegistry) {
                sbr = (SingletonBeanRegistry) registry;
                /**
                 * 判断是否有自定义的beanName生成器
                 */
                if (!this.localBeanNameGeneratorSet) {
                    BeanNameGenerator generator = (BeanNameGenerator) 
                                sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                    // 获取spring默认的beanName生成器,这里为空
                    if (generator != null) {
                        /**
                         * componentScanBeanNameGenerator与importBeanNameGenerator定义时                     * 就赋值了new AnnotationBeanNameGenerator()
                         * 如果spring有默认的beanName生成器,则重新赋值
                         */
                        this.componentScanBeanNameGenerator = generator;
                        this.importBeanNameGenerator = generator;
                    }
                }
            }

说实话,笔者不是很关心这几行源码,大概意思就是如果你提供了自定义的名字生成器那就用你的,否则spring用自己默认的名字生成器,我知道是Class类名首字母小写。读者可研究下名字生成器类AnnotationBeanNameGenerator,很简单。

它实现了BeanNameGenerator接口,这个接口只有一个String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);方法,你可以实现这个接口生成自定义名字生成器。打个比方:

    /自定义名字生成器
    public class MyNameGenerator implements BeanNameGenerator {
        @Override
        public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
            return definition.getBeanClassName()+"源码之路";
        }
    }

    public class SpringTest {

        public static void main(String[] args) {


            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(Config.class);
            //创建一个名字生成器类
            MyNameGenerator myNameGenerator = new MyNameGenerator();
    //通过上面的源码可知,必须以单例的方式注册的bean工厂中
            context.getBeanFactory()
                        .registerSingleton
                        (AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                        myNameGenerator);
            context.refresh();
            System.out.println();
        }
    }

12.postProcessBeanDefinitionRegistry源码(上)

如果你要生成一个自定义名字生成器你怎么做?spring源码很重要吗?

spring源码对你的整个职业生涯起着至关重要的作用。

继续往下看:

if (this.environment == null) {
    this.environment = new StandardEnvironment();
}

标准资源环境,以后专门写一篇博客讲解环境抽象。

上面我们拿到了配置类集合configCandidates,下一步就是解析处理这些配置类。鉴于解析篇幅太长所以放在下一篇文章。

下一篇文章可以带着问题去读。

思考问题

1.@Configuration作用?

2.如何解析@Configuration的类?

3.解析@ComponentScan时机?

4.解析@Import注解时机,如何解析的?

5.解析@Bean注解的时机?