文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Configuration源码,你了解多少?

2024-11-30 06:16

关注

proxyBeanMethods

首先这个是@Configuration注解中的一个参数,我们都知道,@Configuration是Spring中的配置类,一般用来申明Bean,在默认情况下proxyBeanMethods为true

含义

从源码中可以看到对该参数的描述如下:

Specify whether @Bean methods should get proxied in order to enforce bean lifecycle behavior, e.g. to return shared singleton bean instances even in case of direct @Bean method calls in user code. This feature requires method interception, implemented through a runtime-generated CGLIB subclass which comes with limitations such as the configuration class and its methods not being allowed to declare final.
The default is true, allowing for 'inter-bean references' via direct method calls within the configuration class as well as for external calls to this configuration's @Bean methods, e.g. from another configuration class. If this is not needed since each of this particular configuration's @Bean methods is self-contained and designed as a plain factory method for container use, switch this flag to false in order to avoid CGLIB subclass processing.
Turning off bean method interception effectively processes @Bean methods individually like when declared on non-@Configuration classes, a.k.a. "@Bean Lite Mode" (see @Bean's javadoc). It is therefore behaviorally equivalent to removing the @Configuration stereotype.
  1. 该属性的作用是指定标注了@Bean的方法在执行生命周期的时候是否应该被代理。比如在代码中直接调用@Bean标注的方法时要返回共享的单例Bean实例(关闭代理之后不会返回共享的Bean实例)。
  2. 该特性是通过运行时CGLIB子类 实现的方法拦截。该子类有一些限制,比如配置类和它的方法不允许声明为final类型。
  3. 默认为true,即允许 “inter-bean references” 通过配置类内部的直接方法调用,也可以通过外部调用该配置类的@Bean标注的方法。如果该配置类是一个特殊的配置类:每一个@Bean标注的方法 都是自包含的,并设计为供容器使用的普通工厂方法,可以设置该属性为false,以避免CGLIB子类处理。
  4. 关闭Bean方法拦截可以高效的单独处理@Bean方法,就像声明在一个non-@Configuration类上一样,@Bean Lite Mode。这种行为类似于删除@Configuration原型。

当直接在Configuration中直接通过方法,实现实例件的属性依赖时,IDEA会有这样一段提示:

Method annotated with @Bean is called directly in a @Configuration where proxyBeanMethods set to false. Set proxyBeanMethods to true or use dependency injection.

示例

先通过下面的示例看下现象:

两个配置类,写法差不多,区别在与proxyBeanMethods的配置以及AnimalCage属性的注入方法。

@Configuration(proxyBeanMethods = false)
public class GenericConfiguration {
    
    @Bean
    public DogCage dogCage(){
        return new DogCage();
    }

    @Bean
    public AnimalCage animalEden(){
        AnimalCage animalCage = new AnimalCage();
        animalCage.addCage(dogCage());
        return animalCage;
    }
}

@Configuration(proxyBeanMethods = true)
public class ProxyConfiguration {

    @Bean
    public DogCage dogCage(){
        return new DogCage();
    }

    @Bean
    public AnimalCage animalEden(@Autowired List cages){
        return new AnimalCage(cages);
    }
}

先看下GenericConfiguration配置的情况:

public class Tests {
    @Autowired
    private BeanFactory beanFactory;
    @Autowired
    private GenericConfiguration genericConfiguration;
    @Autowired
    private AnimalCage animalCage;
    @Autowired
    private DogCage dogCage;
    @Test
    public void runConfig() {
        log.info("configuration: {}", genericConfiguration); // 原始对象类型

        log.info("Configuration中的Bean: {}", genericConfiguration.dogCage() == genericConfiguration.dogCage()); // 两次结果不一样
        log.info("容器中的Bnea: {}", beanFactory.getBean(DogCage.class) == beanFactory.getBean(DogCage.class));// 从Spring容器中取值都是一样的
        animalCage.cages.forEach(cage -> {
            if (cage instanceof DogCage) {
                log.info("dogCage : {} ", cage == dogCage); // 和上面的对象不一致,非单例
            }
        });
    }
}

再看下ProxyConfiguration配置的情况:

public class Tests {
    @Test
    public void runConfig() {
        log.info("configuration: {}", proxyConfiguration); // 1、CGLIB代理的对象

        log.info("Configuration中的Bean: {}", proxyConfiguration.dogCage() == proxyConfiguration.dogCage()); // 2、两次结果相同
        log.info("容器中的Bnea: {}", beanFactory.getBean(DogCage.class) == beanFactory.getBean(DogCage.class));// 3、从Spring容器中取值都是一样的
        animalCage.cages.forEach(cage -> {
            if (cage instanceof DogCage) {
                log.info("dogCage : {} ", cage == dogCage); // 和上面的对象不一致,非单例
            }
        });
    }
}

会得到这样的现象:

  1. proxyBeanMethods = true时,从Spring容器中取出的Configuration是一个Cglib代理配置,否则是一个原始类型配置
  2. proxyBeanMethods = true时,多次调用Bean方法,每次都是一个新对象,否则都是同一个对象
  3. 从Spring容器中取出Bean,不管多少次,都是同一个对象,也就是单例的

Lite Full Mode

看到上面的现象后,我们有必要了解下Spring配置中的Lite和Full两种模式

lite模式包含:

full模式包含:

full模式使用特性:

lite模式使用特性:

结束语

@Configuration(proxyBeanMethods = false)的配置其实是Lite模式,这种模式下,配置类不会生成代理类,速度会更快,但是要注意,在配置类中的@Bean方法,不能用来实现单例级别的依赖。


来源:Java技术指北内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯