• [Spring] @Bean 修饰方法时如何注入参数


    目录

    一、@Bean 的简单使用

    1、正常情况

    2、问题提出

    二、解决方案

    1、@Qualifier

    2、直接写方法名

    三、特殊情况

    1、DataSource


    一、@Bean 的简单使用

    在开发中,基于 XML 文件配置 Bean 对象的做法非常繁琐且不好维护,因此绝大部分情况下都是使用“完全注解开发”。

    对于 Spring 而言,IOC 容器中的 Bean 对象的创建和使用是一大重点,Spring 也为我们提供了注解方式创建 bean 对象:使用 @Bean。

    在举例之前,先熟悉以下两个需要用到的类:

    (1)User 类

    1. package com.demo.pojo;
    2. import org.springframework.stereotype.Component;
    3. @Component
    4. public class User {
    5. private String name;
    6. public void setName(String name) {
    7. this.name = name;
    8. }
    9. @Override
    10. public String toString() {
    11. return "User{" +
    12. "name='" + name + '\'' +
    13. '}';
    14. }
    15. }

     (2)Book 类

    1. package com.demo.pojo;
    2. import org.springframework.stereotype.Component;
    3. @Component
    4. public class Book {
    5. private User user;
    6. public void setUser(User user) {
    7. this.user = user;
    8. }
    9. public User getUser() {
    10. return user;
    11. }
    12. }

    1、正常情况

    (1)下面是一个简单的 bean 对象创建:

    1. @Bean
    2. public User getUser() {
    3. return new User();
    4. }

    经此操作,IOC 中就会多出一个与 同义的 bean 对象。即:方法名就是 id,返回类型就是 class

    (2)含有普通类型参数的 bean 对象创建:

    1. @Bean
    2. public User getUser(@Value("wyt") String name) {
    3. User user = new User();
    4. user.setName(name);
    5. return user;
    6. }

    需要注意的是,方法中的参数并不是 bean 对象的成员属性,而是代表着 bean 对象的创建依赖于这几个参数,或许用来 setParameter,或许只是中间变量。

    而在 xml 文件中的 则必须要求用 set 方法。

    (3)含有对象类型参数的 bean 对象创建:

    1. package com.demo.config;
    2. import com.demo.pojo.Book;
    3. import com.demo.pojo.User;
    4. import org.springframework.beans.factory.annotation.Value;
    5. import org.springframework.context.annotation.*;
    6. @Configuration
    7. public class Config {
    8. @Bean
    9. public User getUser(@Value("wyt") String name) {
    10. User user = new User();
    11. user.setName(name);
    12. return user;
    13. }
    14. @Bean
    15. public Book createBook(User user) {
    16. Book book = new Book();
    17. book.setUser(user);
    18. return book;
    19. }
    20. }

    对比在 xml 中是如何实现参数是对象类型时的属性注入:

    (4)正常情况下,@Bean 使用总结

    (4-1)@Bean 注解的方法,其返回值就是一个 对象,并且注册到了 IOC 容器中。

    • id 为方法的名字;
    • class 为方法的返回类型;

    (4-2)@Bean 对象的实例化依赖于方法内的参数,参数可以是普通类型,也可以是对象类型。

    • 若为普通类型,用 @Value("xxx") 来注入这个参数;
    • 若为对象类型,则默认情况下,Spring 会到 IOC 容器中寻找与参数类型相同的 bean 对象来注入这个参数;

    2、问题提出

    根据上述内容,我们会想到:如果参数是对象类型,可是 IOC 中拥有不止一个相同类型的 bean 对象,这该怎么办呢?

    比如下面的情况:

    可以看到,Book 对象的参数 user 已经报错了,无法自动装配,因为存在多个 User 类型的 Bean,Spring 不知道应该将哪个 bean 注入到 user 中

    二、解决方案

    首先我们要知道,默认情况下,参数的注入使用的是 @Autowired,不需要显式写出。

    1、@Qualifier

    我们可以想到,@Autowired 是根据类型自动装配,当一个类型有多个 bean 对象时失效。

    而 @Qualifier 是根据名称进行装配,这不就意味着我们可以用 @Qualifier 来明确需要的 bean 对象嘛。

    这有两种写法,都是有效的:

    • 直接在参数前加 @Qualifier("function_name");
    • 在方法前加 @Qualifier("function_别名"),在参数前加 @Qualifier("function_别名");

    (1)配置类

    1. package com.demo.config;
    2. import com.demo.pojo.Book;
    3. import com.demo.pojo.User;
    4. import org.springframework.beans.factory.annotation.Qualifier;
    5. import org.springframework.beans.factory.annotation.Value;
    6. import org.springframework.context.annotation.*;
    7. @Configuration
    8. public class Config {
    9. @Bean
    10. public User getUser(@Value("wyt") String name) {
    11. User user = new User();
    12. user.setName(name);
    13. return user;
    14. }
    15. @Bean
    16. public User createUser(@Value("wyt") String name) {
    17. User user = new User();
    18. user.setName(name);
    19. return user;
    20. }
    21. @Bean
    22. public Book createBook(@Qualifier("createUser") User user) {
    23. Book book = new Book();
    24. book.setUser(user);
    25. return book;
    26. }
    27. }

    (2)测试代码

    1. @Test
    2. public void SameObjectTest() {
    3. ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
    4. Book book = context.getBean("createBook", Book.class);
    5. System.out.println(book.getUser());
    6. }

    (3)输出结果

    2、直接写方法名

    因为一般情况下,方法名不能相同,因此也可以通过将参数名写成对应的方法名来进行注入

    1. package com.demo.config;
    2. import com.demo.pojo.Book;
    3. import com.demo.pojo.User;
    4. import org.springframework.beans.factory.annotation.Value;
    5. import org.springframework.context.annotation.*;
    6. @Configuration
    7. public class Config {
    8. @Bean
    9. public User getUser(@Value("wyt") String name) {
    10. User user = new User();
    11. user.setName(name);
    12. return user;
    13. }
    14. @Bean
    15. public User createUser(@Value("wyt") String name) {
    16. User user = new User();
    17. user.setName(name);
    18. return user;
    19. }
    20. @Bean
    21. public Book createBook(User createUser) {
    22. Book book = new Book();
    23. book.setUser(createUser);
    24. return book;
    25. }
    26. }

    三、特殊情况

    在这里要说明一些特别的对象类型,比如:DataSource。

    1、DataSource

    (1)问题描述

    1. @Bean
    2. public DruidDataSource createDruidDataSource() {
    3. DruidDataSource dataSource = new DruidDataSource();
    4. dataSource.setDriverClassName(driver);
    5. dataSource.setUrl(url);
    6. dataSource.setUsername(username);
    7. dataSource.setPassword(password);
    8. return dataSource;
    9. }
    10. @Bean
    11. public DruidDataSource getDruidDataSource() {
    12. DruidDataSource dataSource = new DruidDataSource();
    13. dataSource.setDriverClassName(driver);
    14. dataSource.setUrl(url);
    15. dataSource.setUsername(username);
    16. dataSource.setPassword(password);
    17. return dataSource;
    18. }

    当我们像上面的代码一样,写了两个数据源的 bean 对象之后,运行就会出现如下报错: 

    No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 2

    简单来说,就是因为 Spring 有其自身的配置类,导致程序不知道选择哪一个数据源。

    (2)解决方法

    给其中任意一个加上 @Primary,代表当出现多个同类型 bean 时,优先使用哪一个。写上之后,就可以使用前文所述的方法,如:@Qualifier 或直接写方法名。

    1. @Bean
    2. @Primary
    3. public DruidDataSource createDruidDataSource() {
    4. DruidDataSource dataSource = new DruidDataSource();
    5. dataSource.setDriverClassName(driver);
    6. dataSource.setUrl(url);
    7. dataSource.setUsername(username);
    8. dataSource.setPassword(password);
    9. return dataSource;
    10. }

  • 相关阅读:
    射频微波芯片设计7:详解基于ADS的低噪声放大器芯片设计
    云计算 - 2 - HDFS文件系统的基本操作
    gradle-7.5.1-all 百度网盘下载
    后端:推荐 2 个 .NET 操作的 Redis 客户端类库
    Hadoop3教程(十):MapReduce中的InputFormat
    05 | Harbor的简介下载及安装
    SQL创建新表
    【17】c++设计模式——>原型模式
    B站视频听不清
    vue配置@路径
  • 原文地址:https://blog.csdn.net/joyride_run/article/details/133611380