首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【SpringBoot】@Bean && @ComponentScan && 三种依赖注入的方式

【SpringBoot】@Bean && @ComponentScan && 三种依赖注入的方式

原创
作者头像
lirendada
发布2026-06-06 12:36:57
发布2026-06-06 12:36:57
290
举报
文章被收录于专栏:JavaJava

注解 @Bean

@Bean 告诉 spring这个方法返回的对象要放进 IoC 容器(ApplicationContext)里,成为可被任何其他 Bean 注入的组件

💥注意事项:

  1. @Bean 要配合五大注解使用,不能单独使用
  2. Spring 中,默认情况下 Bean 的作用域是 singleton(单例)的,即整个 Spring 容器中只存在一个该 Bean 实例
  3. 对于同一个类,要定义多个 Bean 对象的话,需要对不同的方法进行注解,然后使用 ApplicationContext 对象的 getBean() 方法中传入 Bean 名称的方式进行获取,对应的 Bean 名称是对应方法的名称,当然也可以进行重命名,默认重命名的属性是 name,如下所示:
    代码语言:javascript
    复制
    @Component
    public class UserComponent {
        @Bean("{u3}")
        public User u1() {
            return new User();
        }
    
        @Bean
        public User u2() {
            return new User();
        }
    }
    
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Application.class, args);
        
        // 通过 Bean 名获取,不然 Spring 会报错,识别不出要哪个对象
        // 并且可以对 Bean 对象进行重命名!
        User u1 = (User)context.getBean("u3");
        User u2 = (User)context.getBean("u2");
        System.out.println(u1);
        System.out.println(u2);
    }
    
    // 运行结果:
    com.liren.ioc.model.User@abbe000
    com.liren.ioc.model.User@3f81621c

扫描路径 @ComponentScan

Spring 默认扫描的范围是 SpringBoot 启动类所在包及其子包,如下图所示,一般也推荐直接把启动类放到项目目录中!

但是如果需要放在特定包内,还需要访问其它非子包的包内,则需要使用 @ComponentScan 来添加要扫描的包,如下所示,当然也可以{} 配置多个包路径

代码语言:javascript
复制
@ComponentScan("com.liren.ioc.service") // 指定扫描com.liren.ioc.service包中的内容
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

依赖注入

一、三种注入方式 @Autowired

① 属性注入

这种方式虽然不是官方最推荐的,但却是日常开发最常用的。

代码语言:javascript
复制
@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void func() {
        System.out.println("UserController");
        userService.func();
    }
}

② 构造方法注入

💥注意:如果类只有一个构造方法,那么 @Autowired 注解可以省略;如果类中有多个构造方法,那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法。

代码语言:javascript
复制
@Controller
public class UserController {
    private UserService userService;
    
    // 默认构造方法
    public UserController() {}
    
    // 如果有默认构造方法,那么不显式写上@Autowired的话,会去调用默认构造方法
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void func() {
        System.out.println("UserController");
        userService.func();
    }
}

Setter方法注入

代码语言:javascript
复制
@Controller
public class UserController {
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void func() {
        System.out.println("UserController");
        userService.func();
    }
}

三种注入方式的区别

  1. 属性注入
    1. 优点:简洁,使用方便
    2. 缺点:
      1. 只能用于 IOC 容器,如果是非 IOC 容器不可用,并且只有在使用的时候才会出现空指针异常
      2. 不能注入一个 Final 修饰的属性
  2. 构造函数注入(Spring 4.X 推荐)
    1. 优点:
      • 可以注入 final 修饰的属性
      • 注入的对象不会被修改
      • 依赖对象在使用前一定会被完全初始化,因为依赖是在类的构造方法中执行的,而构造方法是在类加载阶段就会执行的方法。
      • 通用性好,构造方法是 JDK 支持的,所以更换任何框架,它都是适用的
    2. 缺点:
      • 注入多个对象时,代码会比较繁琐

3. Setter 注入(Spring 3.X 推荐)

  1. 优点:方便在类实例之后,重新对该对象进行配置或者注入
  2. 缺点:
    • 不能注入一个 final 修饰的属性
    • 注入对象可能会被改变,因为 setter 方法可能会被多次调用,就有被修改的风险

二、@Autowired 存在的问题

当同一个类存在多个 Bean 时,使用 @Autowired 会存在问题,如下所示:

如何解决上述问题呢❓❓❓Spring 提供了以下几种解决方案:

  • @Primary
  • @Qualifier
  • @Resource

@Primary

当存在多个相同类型的 Bean 注入时,加上 @Primary 注解,来确定默认的实现!

这个注解加在要被指定注入的 Bean 对象上,如下所示:

代码语言:javascript
复制
@Component
public class UserComponent {
    @Primary
    @Bean
    public User u3() {
        return new User();
    }

    @Bean
    public User u4() {
        return new User();
    }
}

@Qualifier

注意该注解不能单独使用,需要配合 @Autowired 才行

代码语言:javascript
复制
@Controller
public class UserController2 {
    @Qualifier("u3") // 指定对应Bean的名称
    @Autowired
    private User user;

    public void func() {
        System.out.println("UserController2");
    }
}

@Resource⭐⭐⭐

该注解可以单独使用,不过需要显式用属性 name 来指定对应的 Bean 对象!

代码语言:javascript
复制
@Controller
public class UserController2 {
    @Resource(name = "u3") // 需要显式写一下name来指定
    private User user;

    public void func() {
        System.out.println("UserController2");
    }
}

需要注意的是,@ResourceJDK 自带的,支持更多的参数设置,而 @AutowiredSpring 框架提供的,没有前者功能那么多!

@Autowired 的装配顺序如下图所示:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 注解 @Bean
  • 扫描路径 @ComponentScan
  • 依赖注入
    • 一、三种注入方式 @Autowired
      • ① 属性注入
      • ② 构造方法注入
      • ③ Setter方法注入
      • 三种注入方式的区别
    • 二、@Autowired 存在的问题
      • ① @Primary
      • ② @Qualifier
      • ③ @Resource⭐⭐⭐
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档