2.1 CDI(Contexts and Dependency Injection)基础
2.1.1 CDI 概述
CDI 是 Jakarta EE 的核心规范之一,Quarkus 使用 ArC(一个轻量级的 CDI 实现)来提供依赖注入功能。CDI 提供了类型安全的依赖注入、拦截器、装饰器和事件机制。
graph TB
A[CDI 容器] --> B[Bean 管理]
A --> C[依赖注入]
A --> D[生命周期管理]
A --> E[事件系统]
A --> F[拦截器]
B --> B1[Bean 发现]
B --> B2[Bean 创建]
B --> B3[Bean 销毁]
C --> C1[构造器注入]
C --> C2[字段注入]
C --> C3[方法注入]
D --> D1[@ApplicationScoped]
D --> D2[@RequestScoped]
D --> D3[@Singleton]
E --> E1[事件发布]
E --> E2[事件监听]
F --> F1[方法拦截]
F --> F2[AOP 支持]
2.1.2 Bean 的定义和发现
基本 Bean 定义
package com.example.service;
import jakarta.enterprise.context.ApplicationScoped;
// 应用作用域的 Bean
@ApplicationScoped
public class GreetingService {
public String greet(String name) {
return "Hello, " + name + "!";
}
public String greetWithTime(String name) {
return String.format("Hello, %s! Current time: %s",
name, java.time.LocalTime.now());
}
}
Bean 发现规则
// 1. 使用 CDI 注解的类自动成为 Bean
@ApplicationScoped
public class UserService {
// 自动发现
}
// 2. 使用 @Produces 方法创建 Bean
@ApplicationScoped
public class ConfigurationProducer {
@Produces
@ApplicationScoped
public DatabaseConfig createDatabaseConfig() {
return new DatabaseConfig("localhost", 5432, "mydb");
}
}
// 3. 接口实现自动成为 Bean
public interface NotificationService {
void sendNotification(String message);
}
@ApplicationScoped
public class EmailNotificationService implements NotificationService {
@Override
public void sendNotification(String message) {
System.out.println("Email: " + message);
}
}
2.2 依赖注入模式
2.2.1 构造器注入(推荐)
package com.example.resource;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import com.example.service.GreetingService;
import com.example.service.UserService;
@Path("/api/greetings")
public class GreetingResource {
private final GreetingService greetingService;
private final UserService userService;
// 构造器注入 - 推荐方式
public GreetingResource(GreetingService greetingService,
UserService userService) {
this.greetingService = greetingService;
this.userService = userService;
}
@GET
@Path("/hello/{name}")
@Produces(MediaType.TEXT_PLAIN)
public String hello(@PathParam("name") String name) {
return greetingService.greet(name);
}
@GET
@Path("/time/{name}")
@Produces(MediaType.TEXT_PLAIN)
public String helloWithTime(@PathParam("name") String name) {
return greetingService.greetWithTime(name);
}
}
2.2.2 字段注入
@Path("/api/users")
public class UserResource {
// 字段注入
@Inject
UserService userService;
@Inject
NotificationService notificationService;
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public User getUser(@PathParam("id") Long id) {
return userService.findById(id);
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public User createUser(User user) {
User savedUser = userService.save(user);
notificationService.sendNotification("User created: " + user.getName());
return savedUser;
}
}
2.2.3 方法注入
@ApplicationScoped
public class OrderService {
private PaymentService paymentService;
private InventoryService inventoryService;
// 方法注入
@Inject
public void setServices(PaymentService paymentService,
InventoryService inventoryService) {
this.paymentService = paymentService;
this.inventoryService = inventoryService;
}
public Order processOrder(Order order) {
// 检查库存
if (!inventoryService.checkAvailability(order.getItems())) {
throw new IllegalStateException("Insufficient inventory");
}
// 处理支付
Payment payment = paymentService.processPayment(order.getTotal());
order.setPayment(payment);
return order;
}
}
2.3 Bean 作用域
2.3.1 应用作用域(@ApplicationScoped)
// 应用启动时创建,应用关闭时销毁
// 整个应用共享一个实例
@ApplicationScoped
public class CacheService {
private final Map<String, Object> cache = new ConcurrentHashMap<>();
public void put(String key, Object value) {
cache.put(key, value);
}
public <T> T get(String key, Class<T> type) {
return type.cast(cache.get(key));
}
public void clear() {
cache.clear();
}
// 生命周期回调
@PostConstruct
void init() {
System.out.println("CacheService initialized");
}
@PreDestroy
void cleanup() {
System.out.println("CacheService destroyed");
cache.clear();
}
}
2.3.2 请求作用域(@RequestScoped)
// 每个 HTTP 请求创建一个新实例
@RequestScoped
public class RequestContext {
private String requestId;
private LocalDateTime startTime;
private Map<String, Object> attributes = new HashMap<>();
@PostConstruct
void init() {
this.requestId = UUID.randomUUID().toString();
this.startTime = LocalDateTime.now();
System.out.println("Request context created: " + requestId);
}
@PreDestroy
void cleanup() {
Duration duration = Duration.between(startTime, LocalDateTime.now());
System.out.println("Request " + requestId + " completed in " +
duration.toMillis() + "ms");
}
// Getter 和 Setter 方法
public String getRequestId() { return requestId; }
public LocalDateTime getStartTime() { return startTime; }
public Map<String, Object> getAttributes() { return attributes; }
}
2.3.3 单例作用域(@Singleton)
// 应用启动时立即创建,线程安全
@Singleton
public class MetricsCollector {
private final AtomicLong requestCount = new AtomicLong(0);
private final AtomicLong errorCount = new AtomicLong(0);
private final Map<String, AtomicLong> endpointCounts = new ConcurrentHashMap<>();
public void incrementRequestCount() {
requestCount.incrementAndGet();
}
public void incrementErrorCount() {
errorCount.incrementAndGet();
}
public void incrementEndpointCount(String endpoint) {
endpointCounts.computeIfAbsent(endpoint, k -> new AtomicLong(0))
.incrementAndGet();
}
public MetricsSnapshot getSnapshot() {
return new MetricsSnapshot(
requestCount.get(),
errorCount.get(),
new HashMap<>(endpointCounts.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().get()
)))
);
}
public static class MetricsSnapshot {
public final long requestCount;
public final long errorCount;
public final Map<String, Long> endpointCounts;
public MetricsSnapshot(long requestCount, long errorCount,
Map<String, Long> endpointCounts) {
this.requestCount = requestCount;
this.errorCount = errorCount;
this.endpointCounts = endpointCounts;
}
}
}
2.4 限定符(Qualifiers)
2.4.1 自定义限定符
// 定义限定符注解
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Email {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface SMS {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Push {
}
2.4.2 使用限定符
// 不同的通知服务实现
@Email
@ApplicationScoped
public class EmailNotificationService implements NotificationService {
@Override
public void sendNotification(String message) {
System.out.println("📧 Email: " + message);
}
}
@SMS
@ApplicationScoped
public class SmsNotificationService implements NotificationService {
@Override
public void sendNotification(String message) {
System.out.println("📱 SMS: " + message);
}
}
@Push
@ApplicationScoped
public class PushNotificationService implements NotificationService {
@Override
public void sendNotification(String message) {
System.out.println("🔔 Push: " + message);
}
}
// 使用特定的实现
@ApplicationScoped
public class NotificationManager {
private final NotificationService emailService;
private final NotificationService smsService;
private final NotificationService pushService;
public NotificationManager(@Email NotificationService emailService,
@SMS NotificationService smsService,
@Push NotificationService pushService) {
this.emailService = emailService;
this.smsService = smsService;
this.pushService = pushService;
}
public void sendAllNotifications(String message) {
emailService.sendNotification(message);
smsService.sendNotification(message);
pushService.sendNotification(message);
}
public void sendEmailNotification(String message) {
emailService.sendNotification(message);
}
}
2.4.3 参数化限定符
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface Database {
DatabaseType value();
enum DatabaseType {
MYSQL, POSTGRESQL, MONGODB
}
}
// 不同数据库的实现
@Database(Database.DatabaseType.MYSQL)
@ApplicationScoped
public class MySQLUserRepository implements UserRepository {
@Override
public User findById(Long id) {
// MySQL 实现
return new User(id, "MySQL User");
}
}
@Database(Database.DatabaseType.POSTGRESQL)
@ApplicationScoped
public class PostgreSQLUserRepository implements UserRepository {
@Override
public User findById(Long id) {
// PostgreSQL 实现
return new User(id, "PostgreSQL User");
}
}
// 使用参数化限定符
@ApplicationScoped
public class UserService {
private final UserRepository primaryRepository;
private final UserRepository secondaryRepository;
public UserService(@Database(Database.DatabaseType.POSTGRESQL) UserRepository primaryRepository,
@Database(Database.DatabaseType.MYSQL) UserRepository secondaryRepository) {
this.primaryRepository = primaryRepository;
this.secondaryRepository = secondaryRepository;
}
public User findById(Long id) {
try {
return primaryRepository.findById(id);
} catch (Exception e) {
// 降级到备用数据库
return secondaryRepository.findById(id);
}
}
}
2.5 配置管理
2.5.1 配置文件层次结构
graph TB
A[配置源优先级] --> B[系统属性]
A --> C[环境变量]
A --> D[.env 文件]
A --> E[application.properties]
A --> F[application.yaml]
A --> G[配置文件 Profile]
G --> G1[application-dev.properties]
G --> G2[application-prod.properties]
G --> G3[application-test.properties]
B --> H[最高优先级]
C --> I[高优先级]
D --> J[中等优先级]
E --> K[低优先级]
F --> L[最低优先级]
2.5.2 基本配置属性
# application.properties
# 应用基本信息
app.name=Quarkus Demo
app.version=1.0.0
app.description=A sample Quarkus application
# 服务器配置
quarkus.http.port=8080
quarkus.http.host=0.0.0.0
quarkus.http.cors=true
# 数据库配置
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=admin
quarkus.datasource.password=secret
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/mydb
quarkus.datasource.jdbc.max-size=20
quarkus.datasource.jdbc.min-size=5
# JPA/Hibernate 配置
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true
quarkus.hibernate-orm.sql-load-script=import.sql
# 日志配置
quarkus.log.level=INFO
quarkus.log.category."com.example".level=DEBUG
quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n
# 自定义业务配置
business.email.smtp.host=smtp.gmail.com
business.email.smtp.port=587
business.email.from=noreply@example.com
business.cache.ttl=3600
business.cache.max-size=1000
business.notification.enabled=true
business.notification.batch-size=100
2.5.3 配置属性注入
单个属性注入
@ApplicationScoped
public class EmailService {
@ConfigProperty(name = "business.email.smtp.host")
String smtpHost;
@ConfigProperty(name = "business.email.smtp.port")
int smtpPort;
@ConfigProperty(name = "business.email.from")
String fromAddress;
// 带默认值的配置
@ConfigProperty(name = "business.email.timeout", defaultValue = "30")
int timeout;
// Optional 配置
@ConfigProperty(name = "business.email.debug")
Optional<Boolean> debugEnabled;
public void sendEmail(String to, String subject, String body) {
System.out.printf("Sending email via %s:%d from %s to %s%n",
smtpHost, smtpPort, fromAddress, to);
System.out.printf("Subject: %s%n", subject);
System.out.printf("Body: %s%n", body);
if (debugEnabled.orElse(false)) {
System.out.println("Debug mode enabled");
}
}
}
配置对象映射
// 配置映射接口
@ConfigMapping(prefix = "business.cache")
public interface CacheConfig {
@WithDefault("3600")
int ttl();
@WithDefault("1000")
int maxSize();
@WithDefault("true")
boolean enabled();
Optional<String> provider();
// 嵌套配置
RedisConfig redis();
interface RedisConfig {
String host();
@WithDefault("6379")
int port();
Optional<String> password();
@WithDefault("0")
int database();
}
}
// 使用配置对象
@ApplicationScoped
public class CacheService {
private final CacheConfig config;
private final Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
public CacheService(CacheConfig config) {
this.config = config;
}
@PostConstruct
void init() {
System.out.println("Cache initialized with TTL: " + config.ttl() +
", Max Size: " + config.maxSize());
if (config.redis().host() != null) {
System.out.println("Redis configured at: " +
config.redis().host() + ":" + config.redis().port());
}
}
public void put(String key, Object value) {
if (!config.enabled()) {
return;
}
if (cache.size() >= config.maxSize()) {
// 简单的 LRU 清理
cache.entrySet().iterator().next();
cache.remove(cache.keySet().iterator().next());
}
cache.put(key, new CacheEntry(value, System.currentTimeMillis()));
}
public <T> Optional<T> get(String key, Class<T> type) {
if (!config.enabled()) {
return Optional.empty();
}
CacheEntry entry = cache.get(key);
if (entry == null) {
return Optional.empty();
}
// 检查 TTL
if (System.currentTimeMillis() - entry.timestamp > config.ttl() * 1000L) {
cache.remove(key);
return Optional.empty();
}
return Optional.of(type.cast(entry.value));
}
private static class CacheEntry {
final Object value;
final long timestamp;
CacheEntry(Object value, long timestamp) {
this.value = value;
this.timestamp = timestamp;
}
}
}
2.5.4 环境特定配置
Profile 配置
# application.properties (默认配置)
app.environment=default
quarkus.log.level=INFO
# application-dev.properties (开发环境)
app.environment=development
quarkus.log.level=DEBUG
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.hibernate-orm.log.sql=true
# application-prod.properties (生产环境)
app.environment=production
quarkus.log.level=WARN
quarkus.hibernate-orm.database.generation=none
quarkus.hibernate-orm.log.sql=false
quarkus.datasource.jdbc.max-size=50
# application-test.properties (测试环境)
app.environment=test
quarkus.log.level=DEBUG
quarkus.datasource.db-kind=h2
quarkus.datasource.jdbc.url=jdbc:h2:mem:testdb
quarkus.hibernate-orm.database.generation=drop-and-create
环境变量配置
# 设置环境变量
export QUARKUS_PROFILE=prod
export QUARKUS_DATASOURCE_PASSWORD=prod_secret
export BUSINESS_EMAIL_SMTP_HOST=prod-smtp.example.com
# 或者在 .env 文件中
QUARKUS_PROFILE=dev
QUARKUS_DATASOURCE_PASSWORD=dev_secret
BUSINESS_EMAIL_SMTP_HOST=dev-smtp.example.com
2.5.5 动态配置和配置热更新
@ApplicationScoped
public class DynamicConfigService {
@Inject
@ConfigProperty(name = "business.feature.enabled")
Instance<Boolean> featureEnabled;
@Inject
@ConfigProperty(name = "business.rate.limit")
Instance<Integer> rateLimit;
public boolean isFeatureEnabled() {
return featureEnabled.get();
}
public int getRateLimit() {
return rateLimit.get();
}
// 配置变更监听
void onConfigChange(@Observes @ConfigProperty(name = "business.feature.enabled")
ConfigPropertyChangeEvent event) {
System.out.println("Feature enabled changed from " +
event.getOldValue() + " to " + event.getNewValue());
}
}
2.6 生产者方法(Producer Methods)
2.6.1 基本生产者方法
@ApplicationScoped
public class ConfigurationProducer {
@Produces
@ApplicationScoped
public ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.registerModule(new JavaTimeModule());
return mapper;
}
@Produces
@ApplicationScoped
public RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
return restTemplate;
}
@Produces
@ApplicationScoped
@Named("systemClock")
public Clock createSystemClock() {
return Clock.systemDefaultZone();
}
@Produces
@ApplicationScoped
@Named("utcClock")
public Clock createUtcClock() {
return Clock.systemUTC();
}
}
2.6.2 条件化生产者
@ApplicationScoped
public class ConditionalProducer {
@Produces
@ApplicationScoped
public DataSource createDataSource(CacheConfig config) {
if (config.redis().host() != null) {
return createRedisDataSource(config.redis());
} else {
return createInMemoryDataSource();
}
}
private DataSource createRedisDataSource(CacheConfig.RedisConfig redis) {
// 创建 Redis 数据源
System.out.println("Creating Redis data source: " +
redis.host() + ":" + redis.port());
return new RedisDataSource(redis.host(), redis.port());
}
private DataSource createInMemoryDataSource() {
// 创建内存数据源
System.out.println("Creating in-memory data source");
return new InMemoryDataSource();
}
// 模拟数据源接口和实现
public interface DataSource {
void connect();
void disconnect();
}
public static class RedisDataSource implements DataSource {
private final String host;
private final int port;
public RedisDataSource(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public void connect() {
System.out.println("Connecting to Redis: " + host + ":" + port);
}
@Override
public void disconnect() {
System.out.println("Disconnecting from Redis");
}
}
public static class InMemoryDataSource implements DataSource {
@Override
public void connect() {
System.out.println("Connecting to in-memory data source");
}
@Override
public void disconnect() {
System.out.println("Disconnecting from in-memory data source");
}
}
}
2.7 事件系统
2.7.1 事件定义和发布
// 事件类
public class UserCreatedEvent {
private final User user;
private final LocalDateTime timestamp;
public UserCreatedEvent(User user) {
this.user = user;
this.timestamp = LocalDateTime.now();
}
// Getters
public User getUser() { return user; }
public LocalDateTime getTimestamp() { return timestamp; }
}
public class OrderProcessedEvent {
private final Order order;
private final String status;
private final LocalDateTime timestamp;
public OrderProcessedEvent(Order order, String status) {
this.order = order;
this.status = status;
this.timestamp = LocalDateTime.now();
}
// Getters
public Order getOrder() { return order; }
public String getStatus() { return status; }
public LocalDateTime getTimestamp() { return timestamp; }
}
// 事件发布者
@ApplicationScoped
public class UserService {
@Inject
Event<UserCreatedEvent> userCreatedEvent;
@Inject
UserRepository userRepository;
public User createUser(User user) {
// 保存用户
User savedUser = userRepository.save(user);
// 发布事件
userCreatedEvent.fire(new UserCreatedEvent(savedUser));
return savedUser;
}
}
2.7.2 事件监听
@ApplicationScoped
public class UserEventListener {
@Inject
@Email
NotificationService emailService;
@Inject
AuditService auditService;
// 同步事件监听
void onUserCreated(@Observes UserCreatedEvent event) {
System.out.println("User created: " + event.getUser().getName());
// 发送欢迎邮件
emailService.sendNotification(
"Welcome " + event.getUser().getName() + "!");
// 记录审计日志
auditService.logUserCreation(event.getUser());
}
// 异步事件监听
void onUserCreatedAsync(@ObservesAsync UserCreatedEvent event) {
// 异步处理,不阻塞主流程
try {
Thread.sleep(1000); // 模拟耗时操作
System.out.println("Async processing completed for user: " +
event.getUser().getName());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
@ApplicationScoped
public class OrderEventListener {
@Inject
InventoryService inventoryService;
@Inject
@SMS
NotificationService smsService;
void onOrderProcessed(@Observes OrderProcessedEvent event) {
Order order = event.getOrder();
String status = event.getStatus();
System.out.println("Order " + order.getId() + " status: " + status);
if ("COMPLETED".equals(status)) {
// 更新库存
inventoryService.updateInventory(order.getItems());
// 发送短信通知
smsService.sendNotification(
"Your order " + order.getId() + " has been completed!");
}
}
}
2.7.3 条件化事件监听
@ApplicationScoped
public class ConditionalEventListener {
// 只监听特定类型的用户创建事件
void onVipUserCreated(@Observes UserCreatedEvent event) {
if ("VIP".equals(event.getUser().getType())) {
System.out.println("VIP user created: " + event.getUser().getName());
// VIP 用户特殊处理
}
}
// 使用限定符过滤事件
void onHighValueOrder(@Observes @HighValue OrderProcessedEvent event) {
System.out.println("High value order processed: " + event.getOrder().getId());
}
}
// 事件限定符
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface HighValue {
}
// 发布带限定符的事件
@ApplicationScoped
public class OrderService {
@Inject
Event<OrderProcessedEvent> orderEvent;
@Inject
@HighValue
Event<OrderProcessedEvent> highValueOrderEvent;
public void processOrder(Order order) {
// 处理订单逻辑
if (order.getTotal().compareTo(BigDecimal.valueOf(1000)) > 0) {
// 高价值订单
highValueOrderEvent.fire(new OrderProcessedEvent(order, "COMPLETED"));
} else {
// 普通订单
orderEvent.fire(new OrderProcessedEvent(order, "COMPLETED"));
}
}
}
2.8 实践练习
2.8.1 练习1:创建用户管理系统
创建一个完整的用户管理系统,包含以下组件:
// 用户实体
public class User {
private Long id;
private String name;
private String email;
private String type; // NORMAL, VIP
private LocalDateTime createdAt;
// 构造器、getter、setter
public User() {}
public User(Long id, String name, String email, String type) {
this.id = id;
this.name = name;
this.email = email;
this.type = type;
this.createdAt = LocalDateTime.now();
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}
// 用户仓库
public interface UserRepository {
User save(User user);
User findById(Long id);
List<User> findAll();
void deleteById(Long id);
}
@ApplicationScoped
public class InMemoryUserRepository implements UserRepository {
private final Map<Long, User> users = new ConcurrentHashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
@Override
public User save(User user) {
if (user.getId() == null) {
user.setId(idGenerator.getAndIncrement());
}
users.put(user.getId(), user);
return user;
}
@Override
public User findById(Long id) {
return users.get(id);
}
@Override
public List<User> findAll() {
return new ArrayList<>(users.values());
}
@Override
public void deleteById(Long id) {
users.remove(id);
}
}
// 审计服务
@ApplicationScoped
public class AuditService {
public void logUserCreation(User user) {
System.out.println("AUDIT: User created - ID: " + user.getId() +
", Name: " + user.getName() +
", Time: " + LocalDateTime.now());
}
public void logUserDeletion(Long userId) {
System.out.println("AUDIT: User deleted - ID: " + userId +
", Time: " + LocalDateTime.now());
}
}
2.8.2 练习2:配置驱动的功能开关
// 功能开关配置
@ConfigMapping(prefix = "features")
public interface FeatureConfig {
@WithDefault("true")
boolean userRegistration();
@WithDefault("false")
boolean advancedSearch();
@WithDefault("true")
boolean emailNotifications();
@WithDefault("false")
boolean smsNotifications();
RateLimitConfig rateLimit();
interface RateLimitConfig {
@WithDefault("100")
int requestsPerMinute();
@WithDefault("true")
boolean enabled();
}
}
// 功能开关服务
@ApplicationScoped
public class FeatureToggleService {
private final FeatureConfig config;
public FeatureToggleService(FeatureConfig config) {
this.config = config;
}
public boolean isUserRegistrationEnabled() {
return config.userRegistration();
}
public boolean isAdvancedSearchEnabled() {
return config.advancedSearch();
}
public boolean isEmailNotificationsEnabled() {
return config.emailNotifications();
}
public boolean isSmsNotificationsEnabled() {
return config.smsNotifications();
}
public boolean isRateLimitEnabled() {
return config.rateLimit().enabled();
}
public int getRateLimitRequestsPerMinute() {
return config.rateLimit().requestsPerMinute();
}
}
2.8.3 练习3:多环境配置管理
# application.properties
features.user-registration=true
features.advanced-search=false
features.email-notifications=true
features.sms-notifications=false
features.rate-limit.enabled=true
features.rate-limit.requests-per-minute=100
# application-dev.properties
features.advanced-search=true
features.sms-notifications=true
features.rate-limit.requests-per-minute=1000
# application-prod.properties
features.advanced-search=true
features.rate-limit.requests-per-minute=50
2.9 本章小结
2.9.1 核心概念回顾
CDI 基础
- Bean 的定义和发现
- 依赖注入模式
- Bean 作用域管理
- 生命周期回调
限定符系统
- 自定义限定符
- 参数化限定符
- 多实现选择
配置管理
- 配置属性注入
- 配置对象映射
- 环境特定配置
- 动态配置更新
生产者方法
- Bean 创建定制
- 条件化生产
- 第三方库集成
事件系统
- 事件发布和监听
- 同步和异步处理
- 条件化事件处理
2.9.2 技术要点
- 类型安全: CDI 提供编译时类型检查
- 松耦合: 通过接口和限定符实现组件解耦
- 可测试性: 依赖注入便于单元测试
- 配置外部化: 配置与代码分离
- 事件驱动: 异步处理和系统解耦
2.9.3 最佳实践
依赖注入
- 优先使用构造器注入
- 避免循环依赖
- 合理选择 Bean 作用域
配置管理
- 使用配置映射接口
- 提供合理的默认值
- 支持多环境配置
事件系统
- 保持事件的简单性
- 合理使用异步处理
- 避免事件链过长
2.9.4 下一章预告
下一章我们将学习 RESTful Web 服务开发,包括: - JAX-RS 基础和注解 - 请求和响应处理 - 内容协商和序列化 - 异常处理和验证 - OpenAPI 文档生成
恭喜! 🎉 您已经掌握了 Quarkus 的依赖注入和配置管理核心概念。继续下一章的学习,开始构建 RESTful Web 服务!