# 一,问题描述

在项目中,通常都会配置一个或者多个加了 @Configuration 注解的配置类,那么 @Configuration 这个注解到底有神马作用勒?看下面案例

Config 类

@ComponentScan("com")
public class SpringMVCConfig {
   // 该方法返回是一个 bean 所以需要加上 @Bean 注解
    @Bean
    public BookDao getBookDao(){
        return new BookDao();
    }
}

Dao 类

public class BookDao {
    public BookDao(){
        System.out.println("bookDao constructor runing...");
    }
}

test 测试代码

public class SpringTest {
    @Test
    public void test(){
       // 获取 IoC 容器
        AnnotationConfigApplicationContext a = new AnnotationConfigApplicationContext(SpringMVCConfig.class);
    }
}
//--------------------------Result--------------------------
bookDao constructor runing...

执行上面的代码,我们会发现当我们不加 @Configuration 这个注解的时候我们的 BookDao 这个类还是还是会被实例化,也会打印 bookDao constructor runing...。我们的 spring 环境也可以正常运行。

再看下面案例:

config 类

public class SpringMVCConfig {
    @Bean
    public BookDao getBookDao(){
        return new BookDao();
    }
    @Bean
    public BookDao1 getBookDao1(){
        getBookDao();
        return new BookDao1();
    }
}

Dao 和 Dao1 类

//BookDao
public class BookDao {
    public BookDao(){
        System.out.println("bookDao constructor runing...");
    }
}
//BookDao1
public class BookDao1 {
    public BookDao1(){
        System.out.println("BookDao1 constructor runing...");
    }
}

test 测试代码

public class SpringTest {
    @Test
    public void test(){
        AnnotationConfigApplicationContext a = new AnnotationConfigApplicationContext(SpringMVCConfig.class);
    }
}
//-------------------------Result-------------------------
bookDao constructor runing...
bookDao constructor runing...
BookDao1 constructor runing...

不加 @Configuration 打印的结果 bookDao 打印了两次,那我们加上 @Configuration 看情况

@Configuration
public class SpringMVCConfig {
    @Bean
    public BookDao getBookDao(){
        return new BookDao();
    }
    @Bean
    public BookDao1 getBookDao1(){
        getBookDao();
        return new BookDao1();
    }
}
//----------------------------Result----------------------------
bookDao constructor runing...
BookDao1 constructor runing...

加上 @Configuration 后 bookDao 只打印了一次

# 分析

从表面来看,当我们不加 @Configuration 注解的时候,我们的 BookDao 会被实例化两次,这违背了我们 spring 默认单例的设计原则,当加上我们的 @Configuration 注解的时候,BookDao 只被实例化了一次。那么其底层到底做了什么,让我们来深追一下 spring 源码吧。
当我们解析 beanAppcofig 的时候,会给它的一个属性标识为 Full,表明它是一个全注解类。
在这里插入图片描述

在这里插入图片描述

然后在我们调用 ConfigurationClassPostProcessor.postProcessBeanFactory () 方法的时候会去判断我们的 bean 工厂当中是否有 bean 需要进行 cglib 代理。

在这里插入图片描述

在这里插入图片描述

然后遍历 configBeanDefs 这个 map

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

cglib 代理主要是对我们的方法进行拦截增强;当我们执行 AppConfig 中的方法的时候会去执行 cglib 代理类中的代理方法,主要就是 callBacks 中的方法。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

isCurrentlyInvokedFactoryMethod (beanMethod)) 会判断我们的执行方法和我们的调用方法是否是同一个;如果是同一个就调用父类的方法进行 new;如果不是就调用 $$beanFactory.getBean () 获取。

在这里插入图片描述

# 总结

加上 @Configuration 注解主要是给我们的类加上了 cglib 代理。在执行我们的配置类的方法时,会执行 cglib 代理类中的方法,其中有一个非常重要的判断,当我们的执行方法和我们的调用方法是同一个方法时,会执行父类的方法 new(cglib 代理基于继承);当执行方法和调用方法不是同一个方法时会调用 beanFactory.getBean 获取。
在这里插入图片描述

在这里插入图片描述