草庐IT

初识 @Configuration

阿飞的客栈 2023-04-16 原文

说说你对@Configuration的理解?

定义

@Configuration这个注解是一个类注解,加在类上,标识该类是一个配置类,让这个类的功能等同于一个bean xml配置文件。

@Configuration
public class SpringConfig {
    
}

上面代码类似于下面的xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
    
</beans>

一般 @Configuration 都是和 @Bean 注解结合使用的,上文代码块中使用 @Configuration 定义了一个配置类,相当于定义了一个空的 xml 配置文件,此时我们要在SpringBean 类中注册bean,那么我们就要用到@Bean注解了。

@Bean

这个注解是一个方法注解,用在方法上,表示通过方法来定义一个bean,默认将方法名称作为bean名称,将方法返回值作为bean对象,注册到spring容器中。类似于bean xml配置文件中的bean元素,用来在spring容器中注册一个bean。

@Confuguration
public class SpringConfig {
    // 导入自定义的bean:bean名称为方法默认值:user1
    @Bean
    public User user1() {
        return new User();
    }
    
    // bean名称通过value指定:user2Bean
    @Bean("user2Bean")
    public User user2() {
        return new User();
    }
    
    // 导入第三方bean
	@Bean
    public DataSource dataSource() {
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver"); 
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root"); 
        ds.setPassword("123"); 
        return ds;
    }
}

用法

@Configuration注解的使用步骤:

  • 定义一个类,在类上添加@Configuration注解;
  • 通过AnnotationConfigApplicationContext容器来加载@Configuration注解修饰的配置类,会将配置类中所有的bean注册到spring容器中。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

拓展

如果去掉 @Configuration,会怎样?

举个例子:

定义一个User类和Order类

public class User {

    public User() {
        System.out.println("无参创建User");
    }
}

public class Order {

    private User user;
    
    public Order(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return "Order{" +
                "user=" + user +
                '}';
    }
}

定义一个配置类

//@Configuration
public class SpringConfig {
    // bean名称为方法默认值:user1
    @Bean
    public User user() {
        return new User();
    }

    @Bean
    public Order order() {
        System.out.println("调用order()方法");

        return new Order(this.user());
    }
 
    @Bean()
    public Order order2() {
        System.out.println("调用order2()方法");
        return new Order(this.user());
    }
}

测试类

public class SpringTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        for (String beanName : ctx.getBeanDefinitionNames()) {
            System.out.printf("beanName: %s \t bean对象: %s\n", beanName, ctx.getBean(beanName));
        }
    }
}

加上 @Configuration 注解时输出的结果:

无参创建User
调用order()方法
调用order2()方法
(这里省略Spring容器创建时默认加载的bean)
beanName: springConfig 	 bean对象: cn.afei.config.SpringConfig$$EnhancerBySpringCGLIB$$f76b28e8@4ae3c1cd
beanName: user 	 bean对象: cn.afei.domain.User@29f69090
beanName: order 	 bean对象: Order{user=cn.afei.domain.User@29f69090}
beanName: order2 	 bean对象: Order{user=cn.afei.domain.User@29f69090}

加上 @Configuration,类中定义了3个Bean,Order中注入User对象时,会复用创建好的User对象,User的构造器只被调用了一次,保证了User对象单例。

被@Configuration修饰的bean最后输出的时候带有EnhancerBySpringCGLIB的字样,说明这个bean是被CGLIB处理过的,变成了一个代理对象。

去掉 @Configuration 注解时输出的结果:

无参创建User
调用order()方法
无参创建User
调用order2()方法
无参创建User
beanName: springConfig 	 bean对象: cn.afei.config.SpringConfig@543c6f6d
beanName: user 	 bean对象: cn.afei.domain.User@13eb8acf
beanName: order 	 bean对象: Order{user=cn.afei.domain.User@51c8530f}
beanName: order2 	 bean对象: Order{user=cn.afei.domain.User@7403c468}

去掉了 @Configuration,类中定义了3个Bean,每个Bean都会去创建一个User对象,User的构造器被调用了三次。

没有@Configuration注解的bean没有Cglib的字样。

被@Configuration修饰的类,spring容器中会通过cglib给这个类创建一个代理,代理会拦截所有被@Bean修饰的方法,默认情况(bean为单例)下确保这些方法只被调用一次,从而确保这些bean是同一个bean,即单例的

总结

  1. @Configuration注解修饰的类,会被spring通过cglib做增强处理,通过cglib会生成一个代理对象,代理会拦截所有被@Bean注解修饰的方法,可以确保这些bean是单例的
  2. 不管@Bean所在的类上是否有@Configuration注解,@Bean注解都会生效,都可以将@Bean修饰的方法作为一个bean注册到spring容器中

参考

https://www.bilibili.com/video/BV1Fi4y1S7ix/

http://itsoku.com/course/5/99

有关初识 @Configuration的更多相关文章

  1. ruby - 如何将 Puma::Configuration 传递给 Sinatra? - 2

    这是我的网络应用:classFront我是这样开始的(请不要建议使用Rack):Front.start!这是我的Puma配置对象,我不知道如何传递给它:require'puma/configuration'Puma::Configuration.new({log_requests:true,debug:true})说真的,怎么样? 最佳答案 配置与您运行的方式紧密相关puma服务器。运行的标准方式puma-pumaCLI命令。为了配置puma配置文件config/puma.rb或config/puma/.rb应该提供(参见examp

  2. 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) - 2

    前面一篇关于智能合约翻译文讲到了,是一种计算机程序,既然是程序,那就可以使用程序语言去编写智能合约了。而若想玩区块链上的项目,大部分区块链项目都是开源的,能看得懂智能合约代码,或找出其中的漏洞,那么,学习Solidity这门高级的智能合约语言是有必要的,当然,这都得在公链``````以太坊上,毕竟国内的联盟链有些是不兼容Solidity。Solidity是一种面向对象的高级语言,用于实现智能合约。智能合约是管理以太坊状态下的账户行为的程序。Solidity是运行在以太坊(Ethereum)虚拟机(EVM)上,其语法受到了c++、python、javascript影响。Solidity是静态类型

  3. ruby-on-rails - `method_missing':#<Rails::Application::Configuration:0x00> 的未定义方法 `action_mailer' - 2

    我正在构建一个Rails应用程序并且使用的是Rails4.0.1。我有一个错误,并注意到它在3个月前被称为rails上的一个错误,所以我决定:捆绑更新并获得rails4.0.3这样做之后,测试和服务器都不会启动,并且会抛出错误:gems/railties-4.0.3/lib/rails/railtie/configuration.rb:95:in`method_missing':undefinedmethod`action_mailer'for#(NoMethodError)目前我在config/environments/*中注释掉了action_mailer行,但最好能找到一个真正的

  4. 【Linux】初识Linux --指令Ⅰ - 2

    Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法,Linux…感兴趣就关注我吧!你定不会失望。目录1.ls显示当前目录下的文件内内容2.pwd-显示用户当前所在的目录3.cd-改变工作目录。将当前工作目录改变到指定的目录下1.cd-回到上一次待的工作空间2.cd..返回上一层目录1.相对路径:cd../aurora2.绝对路径:cd/home/aurora/lesson1/aurora3.cd~进入用户家目录4.cd/进入root目录4.mkdir-新建目录5.rmdir/rm-删除1.rmdir删除空文件夹2.rm删除1.rm-f2.rm-i3.rm-r1.ls显示当前目

  5. ruby-on-rails - rails : Could not load database configuration. 没有这样的文件 - - 2

    我从GitHub存储库克隆了一个应用程序文件夹,在捆绑安装gems之后,我尝试使用rakedb:setup和rakedb:migrate命令,但都没有用,这是我的错误消息:**arun997@promanager:~/workspace(master)$rakedb:setuprequire'rails/all'...2.470sBundler.require...7.590srakeaborted!Cannotload`Rails.application.database_configuration`:Couldnotloaddatabaseconfiguration.Nosuchf

  6. ruby-on-rails - 未初始化常量 > ActionCable::Server::Configuration::ApplicationCable - 2

    当我运行服务器时,它的抛出错误显示在下面的日志中。我在谷歌上搜索了很多,但没有找到背后的原因。有人请点亮它。gem文件source'https://rubygems.org'#BundleedgeRailsinstead:gem'rails',github:'rails/rails'gem'rails','>=5.0.0.beta1','0.10.0.rc1'group:development,:testdogem'byebug'endgem'puma'group:developmentdogem'spring'end日志:/home/pd/.rvm/gems/ruby-2.2.4/g

  7. ruby-on-rails - Capistrano::Configuration:Class 的未定义方法 `instance' - 2

    我正在尝试在Rails应用程序中首次启动并运行Capistrano。我有一台运行Ubuntu12.04、nginx、unicorn和rails的linux服务器,但是,我似乎遇到了一些问题。我还使用RVM使用Capistrano3.0.0、rails3.2.14、bundler1.4.0和ruby​​1.9.3p448。我只设置了一个生产阶段,此时我只关心Capistrano与我的服务器通信并从github推送我的代码(目前还没有迁移和捆绑等)。当我使用下面的设置尝试命令capproductiondeploy:check或capproductiondeploy:setup(这似乎已被弃

  8. gtest初识 - googletest(一) - 2

    gtest是Google开发的一个开源单元测试框架,代码提供丰富的注释和实例,参考实际用例可以很快上手基本单元测试,丰富的代码注释能够让有兴趣的开发者深入了解gtest的代码结构并做部分针对性的二次开发。gtest主要针对c/c++提供了针对函数接口和类方法丰富测试方法,针对单元测试特有的数据或者代码反复编写的这种特性做了集成和优化,满足当前绝大部分对于单元测试的需求。其有如下特点:自动收集测试用例,无需开发者再次组织提供强大的断言集,支持包括布尔、整型、浮点型、字符串等。提供断言方法自定义扩展提供死亡测试功能使用参数化自动生成多个相似的测试用例可以将公共的用例初始化和清理工作放入测试夹具中,

  9. 鸿蒙HarmonyOS开发环境初识及搭建 - 2

    一鸿蒙简介HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念,能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备,提供全场景(移动办公、运动健康、社交通信、媒体娱乐等)业务能力。HarmonyOS提供了支持多种开发语言的API,供开发者进行应用开发。支持的开发语言包括Java、XML(ExtensibleMarkupLanguage)、C/C++、JS(JavaScript)、CSS(CascadingStyleSheets)和HML(HarmonyOSMarkupLan

  10. amazon-web-services - "MissingRegion": could not find region configuration, 但我在 ~/.aws.config 中有它 - 2

    我的代码:sess=session.Must(session.NewSessionWithOptions(session.Options{Profile:"gms-ai",}))我的~/.aws/config:[default]output=jsonregion=us-east-1[profilegms-ai]output=jsonregion=us-east-2但是例如,这是我的部署脚本中的工作片段:AWS_PROFILE=gms-ai\awslambdaupdate-function-code...看起来awscli确实读取了region但AWSSDK忽略了它?

随机推荐