spring06-配置类的作用

一、配置类的作用是什么?

简单来说:

配置类是一个专门用于告诉 Spring:“我要哪些对象成为 Bean,被 Spring 管理”的类。

它的作用主要是:配置和注册 Bean 到 Spring 容器中,也就是你说的“管理 Bean”。

二、配置类 = Bean 管理中心

你可以用两种方式告诉 Spring 管 Bean:

方式 举例 本质
注解扫描方式 @Component / @Service / @Controller 自动注册到容器
Java 配置类方式 @Configuration + @Bean 手动注册到容器,完全可控

三、一定要把所有类都放在配置类里用 @Bean 管理吗?

不是必须的!具体视情况而定

1. 推荐用注解自动扫描的情况:

如果你的类是 常规组件类,比如:

  • 业务类(@Service

  • 数据访问类(@Repository

  • 控制器(@RestController / @Controller

  • 工具类(@Component

这些你直接加注解让 Spring 扫描就行,不需要写在配置类里。

@Component
public class EmailService { ... }

然后配置类只需要:

@Configuration
@ComponentScan("com.example")  // Spring 自动扫描并管理 @Component 的类
public class AppConfig {}

2. 推荐用 @Bean 注册的情况:

适合以下几类场景:

情况 示例 为什么适合用 @Bean
你不能改源码 第三方库中的类 你没法加 @Component
需要复杂构造逻辑 创建一个带参数的对象 @Bean 方法可写逻辑
想精确控制生命周期、依赖等 自定义初始化方法等 更灵活
同一个类要注册多个 Bean 多个不同配置的实例 每个 @Bean 都独立

举例:

@Configuration
public class AppConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    public DataSource dataSource() {
        return new HikariDataSource(); // 你可以写初始化逻辑
    }
}

四、总结对比

类类型 用法建议
你自己写的业务类 用注解:@Component / @Service
你不能改的类 / 初始化复杂 用配置类 @Bean 注册
想统一注册/组合多个类 用配置类统一管理逻辑

总结一句话:

配置类的作用是手动定义管理 Spring 容器中的 Bean,但不是所有类都要放进配置类里。常规类推荐用注解 + 扫描,特殊情况才用 @Bean 注册,这样灵活又清晰。

五、将同一个类注册为多个配置不同的 Bean

场景说明:

我们有一个 Server 类,需要为它注册两个不同的实例:

  • 一个叫 devServer,端口是 8080;

  • 一个叫 prodServer,端口是 80。


1、Server 类(不能加 @Component)

package com.example;

public class Server {
    private String environment;
    private int port;

    public Server(String environment, int port) {
        this.environment = environment;
        this.port = port;
    }

    public void start() {
        System.out.println("Starting " + environment + " server on port " + port);
    }
}

2、配置类:AppConfig.java

package com.example.config;

import com.example.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public Server devServer() {
        return new Server("dev", 8080);
    }

    @Bean
    public Server prodServer() {
        return new Server("prod", 80);
    }
}

【注意】:

这两个bean,返回值都是Server,同一个,不同的实例! 


3、主程序 MainApp.java

package com.example;

import com.example.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(AppConfig.class);

        Server dev = context.getBean("devServer", Server.class);
        Server prod = context.getBean("prodServer", Server.class);

        dev.start();   // 输出: Starting dev server on port 8080
        prod.start();  // 输出: Starting prod server on port 80

        context.close();
    }
}

4、输出结果

Starting dev server on port 8080
Starting prod server on port 80

5、总结这个用法的价值:

优点 说明
配置灵活 可以为不同环境或用途构造不同 Bean
互不影响 每个 @Bean 是独立对象
使用方便 在代码中通过名字或类型获取想要的实例

6、补充:注入时指定某个实例

@Autowired
@Qualifier("devServer")
private Server server;

你可以通过 @Qualifier 指定注入哪个 Bean 实例。


7、一句话总结:

当你想根据不同配置注册同一个类的多个实例时,用 @Bean 方法来命名和构造它们是最清晰灵活的方式。

适用场景:比如一个数据源配置多个 DataSource 的真实项目场景示例。

六、一个数据源配置多个 DataSource

这是真实企业开发中常见的高级用法场景:配置多个数据源(多库访问)

你希望项目中同时连接:

  • 主库(primary):用于写操作

  • 从库(replica):用于读操作

这时我们就需要在 Spring 中注册两个不同的 DataSource 实例,并使用 @Qualifier 精确注入。


1、引入依赖(以 Spring Boot 项目为例)



    com.zaxxer
    HikariCP


2、配置文件(application.yml 示例)

spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/main_db
      username: root
      password: root
    replica:
      url: jdbc:mysql://localhost:3306/replica_db
      username: root
      password: root

3、Java 配置类:DataSourceConfig.java

package com.example.config;

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    @Bean(name = "primaryDataSource")
    @Primary  // 默认首选(如果有歧义时优先)
    public DataSource primaryDataSource(
        @Value("${spring.datasource.primary.url}") String url,
        @Value("${spring.datasource.primary.username}") String username,
        @Value("${spring.datasource.primary.password}") String password
    ) {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }

    @Bean(name = "replicaDataSource")
    public DataSource replicaDataSource(
        @Value("${spring.datasource.replica.url}") String url,
        @Value("${spring.datasource.replica.username}") String username,
        @Value("${spring.datasource.replica.password}") String password
    ) {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}

4、使用时注入:用 @Qualifier

package com.example.dao;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;

@Repository
public class UserDao {

    private final DataSource writeDataSource;
    private final DataSource readDataSource;

    public UserDao(
        @Qualifier("primaryDataSource") DataSource writeDataSource,
        @Qualifier("replicaDataSource") DataSource readDataSource
    ) {
        this.writeDataSource = writeDataSource;
        this.readDataSource = readDataSource;
    }

    public void writeToDb() {
        System.out.println("写入操作用的 DataSource 是:" + writeDataSource);
    }

    public void readFromDb() {
        System.out.println("读取操作用的 DataSource 是:" + readDataSource);
    }
}

5、启动测试类

public class MainApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(DataSourceConfig.class, UserDao.class);

        UserDao dao = context.getBean(UserDao.class);
        dao.writeToDb();
        dao.readFromDb();
    }
}

控制输出

写入操作用的 DataSource 是:HikariDataSource (jdbc:mysql://localhost:3306/main_db)
读取操作用的 DataSource 是:HikariDataSource (jdbc:mysql://localhost:3306/replica_db)

6、常见应用场景总结

场景 举例
主从库分离 主库写、从库读,提高性能
多租户系统 不同租户连接不同数据库
动态切换数据源 数据源通过上下文线程绑定,动态决定

7、关键技术点总结

技术 说明
@Bean(name="xxx") 注册命名 Bean
@Primary 指定默认 Bean
@Qualifier 精确注入指定 Bean
@Value 从配置文件中读取属性

8、一句话总结:

通过配置类中定义多个 @Bean,可以为同一个类(如 DataSource)创建不同配置的实例,并通过 @Qualifier 精确控制注入,实现多数据源管理。

你可能感兴趣的:(spring,spring)