Spring常见注解

1. 概述

我们都知道Spring最核心的特性就是IOC(控制反转)+ AOP(⾯向切⾯编程),IOC的原理就是实现了一个Spring容器,用来管理所有Spring Bean实例,DI也就是依赖注入,是我们作为开发者需要关心的核心话题,如何注入依赖,注入哪个依赖,是我们需要明确知道的。 很久之前使用xml配置文件来声明一个bean,但现在,使用注解和代码来完成DI的过程。

我们可以使用 org.springframework.beans.factory.annotationorg.springframework.context.annotation 包中的注释来启用 Spring DI 引擎的功能。

2. DI(依赖注⼊)相关注解

2.1 @Autowired

我们可以使用 @Autowired 来标记 Spring 将要解析和注入的依赖项。 我们可以将此注释与构造函数、setter 或字段注入一起使用。

构造器注入:

class Car {
    Engine engine;

    @Autowired
    Car(Engine engine) {
        this.engine = engine;
    }
}

Setter注入

class Car {
    Engine engine;

    @Autowired
    void setEngine(Engine engine) {
        this.engine = engine;
    }
}

变量注入

class Car {
    @Autowired
    Engine engine;
}

2.2 @Bean

@Bean 标记实例化 Spring bean 的工厂方法:

@Bean
Engine engine() {
    return new Engine();
}

当需要返回类型的新实例时,Spring 会调用这些方法。

生成的 bean 与工厂方法同名。 如果我们想以不同的方式命名,我们可以使用此注释的名称或值参数(参数值是参数名称的别名):

@Bean("engine")
Engine getEngine() {
    return new Engine();
}

这是一种非常常见的bean声明方式,因为很多的bean并不是我们一开始就在代码里定义好的,它可能需要基于运行时环境来进行按需构建。

我们可以自由地声明和定义Bean,并且也可以赋予它自定义的bean名称。

注意,所有用@Bean 注释的方法都必须在@Configuration 类中。

举例

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.config.KafkaListenerContainerFactory;
import org.springframework.kafka.core.*;
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;


@Configuration
public class CloudKafkaConfig {
    @Resource
    private AppConfig appConfig;
    
    @Bean
    public KafkaTemplate<String, String> kafkaCloudTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }

    @Bean(name = "kafkaCloudContainerFactory")
    KafkaListenerContainerFactory<ConcurrentMessageListenerContainer<Integer, String>> kafkaCloudContainerFactory() {
        ConcurrentKafkaListenerContainerFactory<Integer, String> factory = new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory());
        factory.getContainerProperties().setPollTimeout(3000);
        return factory;
    }

    private ProducerFactory<String, String> producerFactory() {
        return new DefaultKafkaProducerFactory<>(producerConfigs());
    }

    private ConsumerFactory<Integer, String> consumerFactory() {
        return new DefaultKafkaConsumerFactory<>(consumerConfigs());
    }

    private Map<String, Object> producerConfigs() {
        Map<String, Object> props = new HashMap<>(3);
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, appConfig.getKafkaServers());
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        return props;
    }

    private Map<String, Object> consumerConfigs() {
        Map<String, Object> props = new HashMap<>(4);
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, appConfig.getKafkaServers());
        props.put(ConsumerConfig.GROUP_ID_CONFIG, appConfig.getKafkaGroupId());
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
        props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
        props.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, "30000");
        props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
        props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,true);
        return props;
    }
}

2.3 @Qualifier

我们使用@Qualifier 和@Autowired 来提供我们想要在不明确情况下使用的bean id 或bean 名称。
例如,以下两个 bean 实现相同的接口:

class Bike implements Vehicle {}

class Car implements Vehicle {}

如果 Spring 需要注入一个 Vehicle bean,它会以多个匹配定义结束。 在这种情况下,我们可以使用 @Qualifier 注释显式提供 bean 的名称。

构造器注入

@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}

Setter注入

@Autowired
void setVehicle(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}

或者

@Autowired
@Qualifier("bike")
void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;

变量注入

@Autowired
@Qualifier("bike")
Vehicle vehicle;

这个注解我们可能平常用的不多,但是当一个接口有多个实现类时,它就会经常派上用场!

2.4 @Required (很少使用)

@Required 在 setter 方法上标记我们想要通过 XML 填充的依赖项:

@Required
void setColor(String color) {
	this.color = color;
}

xml

<bean class="com.baeldung.annotations.Bike">
    <property name="color" value="green" />
</bean>

@Required 注解是 Spring 框架中的一个注解,用于确保依赖注入的属性必须被设置。如果 Spring 容器在创建 bean 时发现被 @Required 注解标记的属性没有被设置,它会抛出一个 BeanInitializationException,从而阻止 bean 的创建。

使用场景
@Required 注解通常用于确保某些关键属性在配置 bean 时被设置,以防止在 bean 使用过程中出现未初始化的属性导致的错误。

使用方法
@Required 注解通常与 setter 方法一起使用,确保相应的 setter 方法必须被调用以设置属性值。

2.5 @Value

非常常用的一个注解,因为我们很多时候都需要从application.properties或者其他配置文件中来读取配置属性值。

engine.fuelType=petrol

@Value("${engine.fuelType}")
String fuelType;

2.6 @Lazy

使用场景

  • 性能优化:对于一些耗资源或启动时间长的 bean,希望在启动时不创建它们,而是在首次使用时才进行创建。
  • 避免循环依赖:延迟初始化某些 bean 可以帮助解决循环依赖问题。
  • 懒加载特性:有时需要根据具体使用场景决定是否创建某个 bean。

使用方法

  • @Lazy 注解可以应用于类、字段、方法和配置方法。

示例
以下是一些使用 @Lazy 注解的示例:

  1. 懒加载类
    当整个类被标记为 @Lazy 时,Spring 容器在启动时不会初始化这个类,而是在第一次需要它时进行初始化。
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy
public class ExpensiveService {

    public ExpensiveService() {
        System.out.println("ExpensiveService is initialized");
    }

    public void performService() {
        System.out.println("Performing expensive service...");
    }
}
  1. 懒加载字段
    在字段级别使用 @Lazy 注解,只有在访问该字段时才会初始化它。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired
    @Lazy
    private ExpensiveService expensiveService;

    public void useService() {
        System.out.println("UserService is calling ExpensiveService");
        expensiveService.performService();
    }
}
  1. 懒加载方法
    在方法级别使用 @Lazy 注解,方法返回的 bean 会延迟初始化。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class AppConfig {

    @Bean
    @Lazy
    public ExpensiveService expensiveService() {
        return new ExpensiveService();
    }
}

2.7 @Profile

@Profile 注解在 Spring 框架中用于指定 bean 在特定环境(或配置文件)下才会被创建和加载。它可以帮助开发者根据不同的环境(如开发、测试、生产)来加载不同的配置和 bean。

使用场景

  • 环境配置:在不同的环境中加载不同的 bean。
  • 测试和开发:在测试环境中加载模拟(mock)bean,在生产环境中加载实际 bean。
  • 多环境支持:根据环境变量或配置文件动态切换配置。
public interface MessageService {
    String getMessage();
}

@Profile("dev")
@Component
public class DevMessageService implements MessageService {
    @Override
    public String getMessage() {
        return "Hello from Development";
    }
}

@Profile("prod")
@Component
public class ProdMessageService implements MessageService {
    @Override
    public String getMessage() {
        return "Hello from Production";
    }
}

配置文件方式
除了在代码中设置 spring.profiles.active,也可以在外部配置文件(如 application.properties 或 application.yml)中进行设置。

spring.profiles.active=dev
  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

boy快快长大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值