spring Bean的full模式和lite模式(@Configuration与@Component的异同)

前言

我们都知道本质上spring中都是bean,但是在实际中却使用不同的注解,这是为什么呢

常见的标记配置类bean注解有@Configuration@Component @ComponentScan @Import @ImportResource 等标注的类都是配置类。

与其他注解不同的是

  • @Configuration注解标记的类是配置类,其中Bean定义信息被标记为full 类型
  • @Component @ComponentScan @Import @ImportResource 标注的类是配置类,其中Bean定义信息被标记为lite类型
  • 类中的方法被@Bean注解标记的类也是配置类,Bean定义信息被标记为lite 类型

查看@Configuration源码可知,相对于其他注解==@Configuration多出了proxyBeanMethods()==属性,这个属性默认为true,代表使用CGLIB增强(生成代理对象)。

lite模式:@Component 、@ComponentScan 、@Import @ImportResource、@Configuration(proxyBeanMethods=false)等修饰

  1. 该模式下,配置类本身不会被CGLIB增强,放进IoC容器内的就是类本身
  2. 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式
  3. 该模式下,配置类内部不能通过方法调用来处理依赖,否则每次生成的都是一个新实例而并非IoC容器内的单例
  4. 该模式下,配置类就是一普通类,所以@Bean方法可以使用private/final等进行修饰

full模式:@Configuration修饰

full模式的方法调用总是返回容器注入的Bean是通过BeanMethodInterceptor拦截器实现的。

  1. 该模式下,配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理
  2. 该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式
  3. 该模式下,配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例
  4. 该模式下,@Bean方法不能被private/final等进行修饰,因为代理类需要重写这个方法

举例说明

1、lite模式

配置类

@Component
// 或者@Configuration(proxyBeanMethods = false)
@Slf4j
public class LogConfig {

    @Bean
    public TeacherBean teacherBean(){
        log.info("生成TeacherBean");
        //这个地方在idea中会有红色下划线,但是依然可以编译运行
        return new TeacherBean(studentBean());
    }
    @Bean
    public StudentBean studentBean() {
        log.info("生成StudentBean");
        return new StudentBean();
    }

    public static class TeacherBean {
        public TeacherBean(StudentBean studentBean) {
        }
    }
    public static class StudentBean {
    }

}

运行结果

@Component
public class Test {
    public static void main(String[] args) {
        final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("annotation");
        final Object test = context.getBean("test");
        final Object test2 = context.getBean("logConfig");

        System.out.println(test);
        System.out.println(test2);
    }
}

在这里插入图片描述

结论

从日志中我们可以发现studentBean()被调用了两次。

2、full模式

配置类

@Configuration
@Slf4j
public class LogConfig {

    @Bean
    public TeacherBean teacherBean(){
        log.info("生成TeacherBean");
        //红色下划线消失
        return new TeacherBean(studentBean());
    }
    @Bean
    public StudentBean studentBean() {
        log.info("生成StudentBean");
        return new StudentBean();
    }

    public static class TeacherBean {
        public TeacherBean(StudentBean studentBean) {
        }
    }
    public static class StudentBean {
    }

}

运行结果

@Component
public class Test {
    public static void main(String[] args) {
        final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("annotation");
        final Object test = context.getBean("test");
        final Object test2 = context.getBean("logConfig");

        System.out.println(test);
        System.out.println(test2);
    }
}

在这里插入图片描述

结论

从日志中我们可以发现studentBean()被调用了一次。
按照正常的思维studentBean()应该是要被调用两次的,日志的输出也证明了只调用了一次,这么做的好处是我们可以声明bean间的依赖关系。
在常见场景中,加了@Bean的方法要声明在加了@Configuration的类中,确保始终都是full模式,因此跨方法引用就会被重定向到容器的生命周期管理,spring帮你干这件事情。这样做可以防止@Bean注解的方法通过常规J​​ava调用意外调用相同的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

L-960

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值