Springboot基础篇(3):Bean管理

前言:Spring 通过扫描类路径(Classpath)来查找带有特定注解(如 @Component、@Service、@Repository 等)的类,并将它们注册为 Spring 容器中的 Bean。

1 Bean扫描

  1. Bean 扫描是 Spring 框架的核心功能之一,通过注解和配置可以灵活控制 Bean 的注册和扫描范围
  2. Bean的扫描范围:Spring Boot 默认会扫描主应用程序类(即带有 @SpringBootApplication 注解的类)所在包及其子包中的所有组件【原因在第四点】
  3. 自定义扫描范围:使用 @ComponentScan 注解指定要扫描的包路径。
java 复制代码
@SpringBootApplication
@ComponentScan(basePackages = {"com.example", "com.anotherpackage"})
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
  1. @SpringBootApplication 是一个组合注解,包含以下三个核心注解:
    @SpringBootConfiguration:标记该类为 Spring Boot 的配置类。
    @EnableAutoConfiguration:启用 Spring Boot 的自动配置功能。
    @ComponentScan: 启用组件扫描功能,默认扫描主应用程序类所在的包及其子包。

2 Bean注册

2.1 概念

Bean 注册是指将 Java 对象交给 Spring 容器管理,使其成为 Spring Bean 的过程

2.2 注册方式

  1. 基于注解的注册
java 复制代码
/*
用于标注普通组件类。
Spring 会自动扫描并注册该类为 Bean
*/
@Component
public class MyComponent {
    // 组件逻辑
}
/*
用于标注服务层组件。
是 @Component 的特化形式,语义上更明确
*/
@Service
public class MyService {
    // 服务逻辑
}
/*
很少用
用于标注数据访问层(DAO)组件。
是 @Component 的特化形式,支持异常转换
*/
@Repository
public class MyRepository {
    // 数据访问逻辑
}
/*
用于标注控制器层组件(如 Spring MVC 控制器)。
是 @Component 的特化形式。
*/
@Controller
public class MyController {
    // 控制器逻辑
}
  1. 基于 XML 的 Bean 注册:在早期的 Spring 版本中,Bean 通常通过 XML 配置文件注册。虽然现在推荐使用注解,但 XML 配置仍然支持
xml 复制代码
<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.xsd">
    <!-- 注册一个 Bean -->
    <bean id="myService" class="com.example.MyService"/>
</beans>
  1. 基于 Java 配置的 Bean 注册:如果要注册的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,此时需要在配置类中进行注册

CommonConfig.java

java 复制代码
@Configuration// 配置注解
public class CommonConfig {
    /**
     * @Bean注解标注的方法会被 Spring容器调用,并将返回值注册为一个 Bean
     */
    @Bean
    public Country country(){
        return new Country();
    }
     /**
     * 默认情况下,Bean 的名称是方法名。你可以通过name或value属性指定Bean的名称。
     */
    @Bean(name = "customService")
    public MyService myService() {
        //Bean 的名称为 customService,而不是默认的 myService。
        return new MyService();
    }
}

SpringbootBeanRegisterApplication.java

java 复制代码
/*
1@Import 是 Spring 框架中的一个注解,用于将其他配置类或组件类导入到当前配置类中
2@Import 可以标注在 @Configuration 类或 @Component 类上,用于导入其他配置类或组件类
3@Import 可以同时导入多个配置类。
4@Import 还可以导入实现了 ImportSelector 接口的类,用于动态选择需要导入的配置类或组件类
*/
@Import(com.wfs.config.CommonImportSeletor.class)//使用@Import导入ImportSelector
//@Import(com.wfs.config.CommonConfig.class)
@SpringBootApplication
public class SpringbootBeanRegisterApplication {
    public static void main(String[] args) {
      ApplicationContext context =  SpringApplication.run(SpringbootBeanRegisterApplication.class, args);//获取ioc容器
      Country country = context.getBean(Country.class);//获取bean
      System.out.println(country);
      System.out.println(context.getBean("aa"));
    }

CommonImportSeletor.java

java 复制代码
package com.wfs.config;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @ImportSelector:导入选择器
 * 作用:导入指定配置类
 */
public class CommonImportSeletor implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.wfs.config.CommonConfig"};
    }
}
  1. 条件化的 Bean 注册:可以结合条件注解(如 @ConditionalOnProperty、@ConditionalOnClass 等)实现条件化的 Bean 注册
java 复制代码
@Configuration
public class CommonConfig {
    /**
     * 1 Bean对象的名字默认是方法名
     * 2 @Bean("aa")自定义对象名
     * 3 方法注入:Spring会自动将容器中的 Bean 注入到方法的参数中。
     * 4 使用@ConditionalOnProperty 条件注入:配置文件中前缀是province,属性名为name的值若是wfs,则声明此Bean
     * 5 @ConditionalOnMissingBean 当不存在当前类型的bean时,才声明该bean
     * 6 @ConditionalOnClass 当classpath下存在指定类时,才声明该bean
     * @return
     */
    @Bean("aa")
    @ConditionalOnProperty(prefix = "province",name = "name" ,havingValue = "wfs")
    @ConditionalOnMissingBean
    @ConditionalOnClass(name = "com.wfs.config.CommonConfig")
    public Province province(@Value("${province.name}") String name,
                             @Value("${province.direction}") String direction) {
        Province province = new Province();
        province.setName(name);
        province.setDirection(direction);
        return province;
    }
}

3 Bean的依赖注入

  1. 构造器注入:推荐的方式,适用于强制依赖。
java 复制代码
@Service
public class MyService {
    private final MyRepository repository;
    @Autowired
    public MyService(MyRepository repository) {
        this.repository = repository;
    }
}
  1. Setter 注入:适用于可选依赖
java 复制代码
@Service
public class MyService {
    private MyRepository repository;
    @Autowired
    public void setRepository(MyRepository repository) {
        this.repository = repository;
    }
}
  1. 字段注入:不推荐,因为不利于测试和代码可读性。
java 复制代码
@Service
public class MyService {
    @Autowired
    private MyRepository repository;
}
相关推荐
㳺三才人子5 小时前
初探 Flask
后端·python·flask·html
星栈独行5 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Lei活在当下5 小时前
先用起来,再理解,关于协程Coroutine应该知道的事
android·java·jvm
Java爱好狂.5 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易6 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
tongluowan0076 小时前
以ReentrantLock为例解释AQS的工作流程
java·模板方法模式·aqs·reentrantlock
装不满的克莱因瓶6 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl7 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
身如柳絮随风扬7 小时前
Java 项目打包与部署完全指南:JAR vs WAR,从构建到运行
java·firefox·jar
云烟成雨TD7 小时前
Spring AI Alibaba 1.x 系列【62】时光旅行(Time-Travel)
java·人工智能·spring