Spring Boot 依赖注入指南:多种方式深度剖析与代码演示

在Spring Boot中,依赖注入是一项核心特性,它有助于创建松散耦合的应用程序。

1. 构造函数注入

构造函数注入通过类的构造函数来传递依赖。这确保了在对象创建时,依赖就已经准备好,并且不可变。如果一个类的依赖在其整个生命周期内都不会改变,构造函数注入是一个很好的选择。它还能帮助确保依赖不为空,因为构造函数参数通常是必需的。

示例代码

假设我们有一个UserService依赖于UserRepository

首先定义UserRepository接口和实现类:

java 复制代码
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    public void saveUser(String user) {
        System.out.println("Saving user: " + user);
    }
}

然后定义UserService,通过构造函数注入UserRepository

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(String user) {
        userRepository.saveUser(user);
    }
}

在Spring Boot中,@Autowired注解并非必需,如果构造函数只有一个,Spring会自动进行依赖注入。上述代码可以简化为:

java 复制代码
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(String user) {
        userRepository.saveUser(user);
    }
}

2. Setter方法注入

Setter方法注入通过调用Setter方法来设置依赖。这种方式更加灵活,因为可以在对象创建后再设置依赖。适用于依赖在对象创建时可能不可用,或者依赖可能在对象的生命周期内发生变化的情况。

示例代码

同样基于前面的UserRepository,定义使用Setter注入的UserService

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(String user) {
        userRepository.saveUser(user);
    }
}

3. 字段注入(属性注入)

字段注入直接在类的字段上使用注解来注入依赖。这种方式代码简洁,但不利于单元测试,因为难以在测试中替换依赖。

示例代码
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public void registerUser(String user) {
        userRepository.saveUser(user);
    }
}

4. 基于Java配置类的依赖注入

在Spring Boot中,除了使用组件扫描和自动装配,还可以通过Java配置类来手动配置Bean及其依赖关系。这种方式在需要更精细控制Bean的创建和配置时非常有用。

示例代码

首先创建一个Java配置类AppConfig

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public UserRepository userRepository() {
        return new UserRepository();
    }

    @Bean
    public UserService userService(UserRepository userRepository) {
        return new UserService(userRepository);
    }
}

然后可以在其他组件中使用UserService,Spring会根据配置类来注入依赖。

5. 基于注解驱动的条件注入

有时候,我们可能希望根据某些条件来决定是否注入某个依赖。Spring Boot提供了基于注解的条件注入方式,如@Conditional注解及其变体。

示例代码

假设我们有一个DatabaseConfig类,根据系统属性来决定是否创建DataSource

java 复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import org.apache.tomcat.jdbc.pool.DataSource as TomcatDataSource;

@Configuration
public class DatabaseConfig {

    @Value("${use.in.memory.database:false}")
    private boolean useInMemoryDatabase;

    @Bean
    @Conditional(InMemoryDatabaseCondition.class)
    public DataSource inMemoryDataSource() {
        TomcatDataSource dataSource = new TomcatDataSource();
        dataSource.setUrl("jdbc:h2:mem:testdb");
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUsername("sa");
        dataSource.setPassword("password");
        return dataSource;
    }

    @Bean
    @Conditional(ProductionDatabaseCondition.class)
    public DataSource productionDataSource() {
        TomcatDataSource dataSource = new TomcatDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/productiondb");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }
}

这里定义了两个DataSource的Bean,inMemoryDataSourceproductionDataSource,分别基于不同的条件进行创建。@Conditional注解的参数是一个实现了Condition接口的类,通过实现matches方法来定义条件逻辑。例如:

java 复制代码
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class InMemoryDatabaseCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("use.in.memory.database", Boolean.class, false);
    }
}
java 复制代码
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class ProductionDatabaseCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return!context.getEnvironment().getProperty("use.in.memory.database", Boolean.class, false);
    }
}
相关推荐
遇印记18 小时前
蓝桥java求最大公约数
java·开发语言
ONExiaobaijs18 小时前
【无标题】
java·开发语言·spring·maven·程序员创富
m0_7381207218 小时前
渗透测试——y0usef靶机渗透提权详细过程(插件伪造请求头)
服务器·网络·web安全·ssh·php
gaize121318 小时前
阿里云服务器用途配置选购指南与最新价格表
服务器·阿里云·云计算
符哥200818 小时前
Mybatis和Mybatis-plus区别
java·开发语言·mybatis
企业对冲系统官18 小时前
期货与期权一体化平台风险收益评估方法与模型实现
运维·服务器·开发语言·数据库·python·自动化
lkbhua莱克瓦2418 小时前
JavaWeb技术概述
java·javaweb·web
爬山算法18 小时前
Hibernate(46) Hibernate的配置文件如何加载?
java·后端·hibernate
风景的人生18 小时前
springboot项目用maven插件打包时候报错
java·spring boot·maven
二哈喇子!18 小时前
基于SSM框架的网上商城购物系统的设计与实现(开源项目——实现CRUD功能整体流程超详细)
java·spring·mybatis·ssm