本文为博主原创,转载请注明出处:

@Configuration 注解对我们来说并不陌生,以javaConfig的方式定义spring IOC容器的配置类使用的就是这个@Configuration.

spring boot 社区推荐使用基于JavaConfig 的配置方式来定义Bean,其可以认为是一个spring IOC 容器的配置类。

指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class TestConfiguration {
     * 初始化spring -restTemplate
     * @return restTemplate
    @Bean
    public RestTemplate getRestTemplate(){
        System.out.println("获取bean ing");
        return new RestTemplate();
    public TestConfiguration() {
        System.out.println("TestConfiguration容器启动初始化。。。");

  @Configuration 注解的工作过程与 ClassXmlPathApplicationContext  的工作过程相同,@Configuration 是通过注解的方式将 bean 注入到spring IOC容器。

ClassXmlPathApplicationContext 是通过xml配置文件,在项目启动加载xml 配置文件时,将其中的bean 标签解析为bena 并注入到 IOC 容器中。

  通过 @Configuration 注解的配置类会通过 AnnotationConfigApplicationContext  类进行扫描,并构建扫描 bean ,并注册到spring IoC容器中。

可以通过以下测试方法,看到上面代码中的bean 初始化并调用相关过程的打印:

import com.example.test.config.TestConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.client.RestTemplate;
public class ConfigurationBeanTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);
        RestTemplate restTemplate = (RestTemplate) context.getBean("getRestTemplate");
        String url = "https://www.baidu.com/?tn=62095104_19_oem_dg";
        String result = restTemplate.getForObject(url,String.class);
        System.out.println(result);

上面test运行并进行正常的 http 请求,可以打印出相关的控制台日志如下:

 可以查看下 AnnotationConfigApplicationContext  类的相关实现,该类的继承结构通过idea 查看如下:

 其中主要涉及到的类和接口如下:

  • GenericApplicationContext——通用应用上下文,内部持有一个DefaultListableBeanFactory实例,这个类实现了BeanDefinitionRegistry接口,可以在它身上使用任意的bean definition读取器。典型的使用案例是:通过BeanFactoryRegistry接口注册bean definitions,然后调用refresh()方法来初始化那些带有应用上下文语义(org.springframework.context.ApplicationContextAware)的bean,自动探测org.springframework.beans.factory.config.BeanFactoryPostProcessor等。关于这两个接口,在介绍bean的生命周期时进行详细讲解。
  • BeanDefinitionRegistry——用于持有像RootBeanDefinition和 ChildBeanDefinition实例的bean definitions的注册表接口。DefaultListableBeanFactory实现了这个接口,因此可以通过相应的方法向beanFactory里面注册bean。GenericApplicationContext内置一个DefaultListableBeanFactory实例,它对这个接口的实现实际上是通过调用这个实例的相应方法实现的。
  • AbstractApplicationContext——ApplicationContext接口的抽象实现,没有强制规定配置的存储类型,仅仅实现了通用的上下文功能。这个实现用到了模板方法设计模式,需要具体的子类来实现其抽象方法。自动通过registerBeanPostProcessors()方法注册BeanFactoryPostProcessorBeanPostProcessorApplicationListener的实例用来探测bean factory里的特殊bean——对比1分析
  • AnnotationConfigRegistry——注解配置注册表。用于注解配置应用上下文的通用接口,拥有一个注册配置类和扫描配置类的方法。
  •  AnnotationConfigApplicationContext  类的源码如下:

    // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) package org.springframework.context.annotation; import java.util.Arrays; import java.util.function.Supplier; import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.metrics.StartupStep; import org.springframework.lang.Nullable; import org.springframework.util.Assert; public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner;

      // 无参数的构造器,在application 启动的时候初始化一个读取器与扫描器
    public AnnotationConfigApplicationContext() { StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); this.reader = new AnnotatedBeanDefinitionReader(this); createAnnotatedBeanDefReader.end(); this.scanner = new ClassPathBeanDefinitionScanner(this);   // 构造一个 bean 工厂的有参构造,并包含了读取器和扫描器 public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) { super(beanFactory); this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this);   
      
      // 手动指定注解类
    public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); this.register(componentClasses); this.refresh();   

       // 通过指定的包名进行自动的扫描并刷新
    public AnnotationConfigApplicationContext(String... basePackages) { this(); this.scan(basePackages); this.refresh(); public void setEnvironment(ConfigurableEnvironment environment) { super.setEnvironment(environment); this.reader.setEnvironment(environment); this.scanner.setEnvironment(environment); public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { this.reader.setBeanNameGenerator(beanNameGenerator); this.scanner.setBeanNameGenerator(beanNameGenerator); this.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", beanNameGenerator); public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { this.reader.setScopeMetadataResolver(scopeMetadataResolver); this.scanner.setScopeMetadataResolver(scopeMetadataResolver); public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register").tag("classes", () -> { return Arrays.toString(componentClasses); this.reader.register(componentClasses); registerComponentClass.end(); public void scan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan").tag("packages", () -> { return Arrays.toString(basePackages); this.scanner.scan(basePackages); scanPackages.end(); public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { this.reader.registerBean(beanClass, beanName, supplier, customizers);

       Spring将被@Configuration注解的配置类定义为full configuration, 而将没有被@Configuration注解的配置类定义为lite configuration。full configuration能重定向从跨方法的引用,

    从而保证上述代码中的b bean是一个单例.

      调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 会将 AppConfig 的配置 类属性标注为full。其调用的流程图如下:

     其判断是否full的代码如下:

       Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
                if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
                    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "full");
                } else {
                    if (config == null && !isConfigurationCandidate(metadata)) {
                        return false;
                    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "lite");
    

    跟踪 AnnotationConfigApplicationContext.refresh() 方法:

        public void refresh() throws BeansException, IllegalStateException {
            synchronized(this.startupShutdownMonitor) {
                StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            // Prepare this context for refreshing.
    this.prepareRefresh();
            // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory
    = this.obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.
    this.prepareBeanFactory(beanFactory); try {
              // Allows post-processing of the bean factory in context subclasses.
              //供上下文(Context)子类继承,允许在这里后置处理bean factory
    this.postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
              // Invoke factory processors registered as beans in the context.
              //按顺序调用BeanFactoryPostProcessor,这里的按顺序仅实现了PriorityOrdered和Ordered的语意,未实现@Order注解的语意
              //通过调用ConfigurationConfigPostProcessor#postProcessBeanDefinitionRegistry
              //解析@Configuration配置类,将自定义的BeanFactoryPostProcessor、BeanPostProcessor注册到beanDefinitionMap
              //接着实例化所有(包括开天辟地)的BeanFactoryPostProcessor,然后再调用BeanFactoryPostProcessor#postProcessBeanFactory
    this.invokeBeanFactoryPostProcessors(beanFactory);
              // Register bean processors that intercept bean creation.
              //按顺序将BeanPostProcessor实例化成bean并注册到beanFactory的beanPostProcessors,
              //这里的按顺序仅实现了PriorityOrdered和Ordered的语意,未实现@Order注解的语意
              //因为BeanPostProcessor要在普通bean初始化()前后被调用,所以需要提前完成实例化并注册到beanFactory的beanPostProcessors
    this.registerBeanPostProcessors(beanFactory); beanPostProcess.end();
              // Initialize message source for this context.
              //注册国际化相关的Bean
    this.initMessageSource();
              // Initialize event multicaster for this context.
              //为上下文注册应用事件广播器(用于ApplicationEvent的广播),如果有自定义则使用自定义的,如果没有则内部实例化一个
    this.initApplicationEventMulticaster();
              // Initialize other special beans in specific context subclasses.
    this.onRefresh();
              // Check for listener beans and register them.
              //注册所有(静态、动态)的listener,并广播earlyApplicationEvents
    this.registerListeners();
              // Instantiate all remaining (non-lazy-init) singletons.
              //实例化用户自定义的普通单例Bean(非开天辟地的、非后置处理器)
    this.finishBeanFactoryInitialization(beanFactory);
              // Last step: publish corresponding event.
    this.finishRefresh(); } catch (BeansException var10) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10); this.destroyBeans(); this.cancelRefresh(var10); throw var10; } finally { this.resetCommonCaches(); contextRefresh.end();

    跟踪invokeBeanFactoryPostProcessors(beanFactory)

      protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
            PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
         // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
         // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));

    跟踪invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    public static void invokeBeanFactoryPostProcessors(
                ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
            // Invoke BeanDefinitionRegistryPostProcessors first, if any.
            Set<String> processedBeans = new HashSet<>();
            if (beanFactory instanceof BeanDefinitionRegistry) {
                BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
                List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
                List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
                for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                    if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                        BeanDefinitionRegistryPostProcessor registryProcessor =
                                (BeanDefinitionRegistryPostProcessor) postProcessor;
                        registryProcessor.postProcessBeanDefinitionRegistry(registry);
                        registryProcessors.add(registryProcessor);
                    else {
                        regularPostProcessors.add(postProcessor);
                // Do not initialize FactoryBeans here: We need to leave all regular beans
                // uninitialized to let the bean factory post-processors apply to them!
                // Separate between BeanDefinitionRegistryPostProcessors that implement
                // PriorityOrdered, Ordered, and the rest.
                List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
                // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
                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);
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                //此处调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry,
                //解析配置类,为配置中的bean定义生成对应beanDefinition,并注入到registry的beanDefinitionMap
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
                // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
                // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
                boolean reiterate = true;
                while (reiterate) {
                    reiterate = false;
                    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                    for (String ppName : postProcessorNames) {
                        if (!processedBeans.contains(ppName)) {
                            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                            processedBeans.add(ppName);
                            reiterate = true;
                    sortPostProcessors(currentRegistryProcessors, beanFactory);
                    registryProcessors.addAll(currentRegistryProcessors);
                    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                    currentRegistryProcessors.clear();
                // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
                //调用ConfigurationClassPostProcessor#postProcessBeanFactory增强配置类(通过cglib生成增强类,load到jvm内存,
                //设置beanDefinition的beanClass为增强类)
                //为什么要增强配置类?主要是为了让@Bean生成的bean是单例,
                invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
                invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
            else {
                // Invoke factory processors registered with the context instance.
                invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
            // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
            // Ordered, and the rest.
            List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
            List<String> orderedPostProcessorNames = new ArrayList<>();
            List<String> nonOrderedPostProcessorNames = new ArrayList<>();
            for (String ppName : postProcessorNames) {
                if (processedBeans.contains(ppName)) {
                    // skip - already processed in first phase above
                else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
                else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    orderedPostProcessorNames.add(ppName);
                else {
                    nonOrderedPostProcessorNames.add(ppName);
            // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
            sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
            // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
            List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
            for (String postProcessorName : orderedPostProcessorNames) {
                orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
            sortPostProcessors(orderedPostProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
            // Finally, invoke all other BeanFactoryPostProcessors.
            List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
            for (String postProcessorName : nonOrderedPostProcessorNames) {
                nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
            invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
            // Clear cached merged bean definitions since the post-processors might have
            // modified the original metadata, e.g. replacing placeholders in values...
            beanFactory.clearMetadataCache();
    
    跟踪invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
    private static void invokeBeanFactoryPostProcessors(
          Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
       for (BeanFactoryPostProcessor postProcessor : postProcessors) {
          postProcessor.postProcessBeanFactory(beanFactory);
    

    跟踪ConfigurationClassPostProcessor#postProcessBeanFactory

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       int factoryId = System.identityHashCode(beanFactory);
       if (this.factoriesPostProcessed.contains(factoryId)) {
          throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + 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);
       //为@Configuration注解的类生成增强类(如果有必要),并替换bd中的beanClass属性,
       enhanceConfigurationClasses(beanFactory);
       beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    

    到了这一步谜底几乎已经揭晓了,@Configuration class是通过增强来实现它的语义的。通过增强把跨方法的引用调用重定向到Spring生命周期管理.我们近一步探索下这个enhanceConfigurationClasses方法

    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);
          MethodMetadata methodMetadata = null;
          if (beanDef instanceof AnnotatedBeanDefinition) {
             methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
          if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
             // Configuration class (full or lite) or a configuration-derived @Bean method
             // -> resolve bean class at this point...
             AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
             if (!abd.hasBeanClass()) {
                try {
                   abd.resolveBeanClass(this.beanClassLoader);
                catch (Throwable ex) {
                   throw new IllegalStateException(
                         "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
          //在ConfigurationClassUtils.checkConfigurationClassCandidate方法中会标记Configuration is full or lite
          if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
             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.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                logger.info("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;
       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();
          //为@Configuration注解的类生成增强类
          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()));
             beanDef.setBeanClass(enhancedClass);
    

    看到有那么一句话 

    Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);

      很明显了,使用cglib技术为config class生成一个enhancedClass,再通过beanDef.setBeanClass(enhancedClass);修改beanDefinition的BeanClass属性,在bean实例化阶段,会利用反射技术将beanClass属性对应的类实例化出来,所以最终实例化出来的@Configuration bean是一个代理类的实例。这里稍微提一下为什么要使用cglib,而不是jdk动态代理,主要是因为jdk动态代理是基于接口的,而这里AppConfig并没有实现任何接口,所以必须用cglib技术。

    被@Configuration 注解的类,是 full configuration class,该类会被增强(通过cglib),从而实现跨方法引用调用被重定向到Spring 生命周期管理,最终保证@Bean method生成的bean是一个单例。

    参考博客:热心市民小陈  https://www.cnblogs.com/think-in-java/p/11876997.html