学习目标

掌握Spring Boot高级特性,了解微服务架构设计理念,学习Spring Cloud基础组件,为构建分布式系统打下基础。


1. Spring Boot自动配置原理深入

1.1 自动配置机制深度解析

核心概念:

  • @EnableAutoConfiguration 注解的工作原理
  • spring.factories 文件的作用机制
  • 条件注解的使用场景和原理
  • 自动配置类的加载顺序和优先级

代码示例:

// 自定义自动配置类
@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(prefix = "custom.datasource", name = "enabled", havingValue = "true")
@EnableConfigurationProperties(CustomDataSourceProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class CustomDataSourceAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    @Primary
    public DataSource customDataSource(CustomDataSourceProperties properties) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(properties.getUrl());
        config.setUsername(properties.getUsername());
        config.setPassword(properties.getPassword());
        config.setMaximumPoolSize(properties.getMaxPoolSize());
        config.setMinimumIdle(properties.getMinIdle());
        config.setConnectionTimeout(properties.getConnectionTimeout());
        config.setIdleTimeout(properties.getIdleTimeout());
        config.setMaxLifetime(properties.getMaxLifetime());
        config.setLeakDetectionThreshold(properties.getLeakDetectionThreshold());
        return new HikariDataSource(config);
    }
    
    @Bean
    @ConditionalOnMissingBean
    public DataSourceTransactionManager customTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

// 配置属性类
@ConfigurationProperties(prefix = "custom.datasource")
@Validated
public class CustomDataSourceProperties {
    
    @NotBlank
    private String url;
    
    @NotBlank
    private String username;
    
    @NotBlank
    private String password;
    
    @Min(1)
    @Max(100)
    private int maxPoolSize = 10;
    
    @Min(1)
    @Max(50)
    private int minIdle = 5;
    
    @Min(1000)
    private long connectionTimeout = 30000;
    
    @Min(1000)
    private long idleTimeout = 600000;
    
    @Min(1000)
    private long maxLifetime = 1800000;
    
    @Min(0)
    private long leakDetectionThreshold = 60000;
    
    // getter和setter方法
    public String getUrl() { return url; }
    public void setUrl(String url) { this.url = url; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    public int getMaxPoolSize() { return maxPoolSize; }
    public void setMaxPoolSize(int maxPoolSize) { this.maxPoolSize = maxPoolSize; }
    public int getMinIdle() { return minIdle; }
    public void setMinIdle(int minIdle) { this.minIdle = minIdle; }
    public long getConnectionTimeout() { return connectionTimeout; }
    public void setConnectionTimeout(long connectionTimeout) { this.connectionTimeout = connectionTimeout; }
    public long getIdleTimeout() { return idleTimeout; }
    public void setIdleTimeout(long idleTimeout) { this.idleTimeout = idleTimeout; }
    public long getMaxLifetime() { return maxLifetime; }
    public void setMaxLifetime(long maxLifetime) { this.maxLifetime = maxLifetime; }
    public long getLeakDetectionThreshold() { return leakDetectionThreshold; }
    public void setLeakDetectionThreshold(long leakDetectionThreshold) { this.leakDetectionThreshold = leakDetectionThreshold; }
}

1.2 条件注解详解与实战

常用条件注解使用:

@Configuration
@EnableConfigurationProperties(ApplicationProperties.class)
public class ConditionalConfig {
    
    // 类路径存在时生效
    @Bean
    @ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.registerModule(new JavaTimeModule());
        return mapper;
    }
    
    // 属性值匹配时生效
    @Bean
    @ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true", matchIfMissing = false)
    @ConditionalOnClass(CacheManager.class)
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .maximumSize(1000)
                .expireAfterWrite(Duration.ofMinutes(10))
                .recordStats());
        return cacheManager;
    }
    
    // 缺少Bean时生效
    @Bean
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.url", matchIfMissing = true)
    public DataSource defaultDataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .setName("testdb")
                .addScript("classpath:schema.sql")
                .addScript("classpath:data.sql")
                .build();
    }
    
    // 表达式条件
    @Bean
    @ConditionalOnExpression("'${app.profile}' == 'dev' and '${app.debug}' == 'true'")
    public DevTools devTools() {
        DevTools devTools = new DevTools();
        devTools.setRestartEnabled(true);
        devTools.setLiveReloadEnabled(true);
        return devTools;
    }
    
    // 自定义条件
    @Bean
    @ConditionalOnCustomProperty(prefix = "app.redis", name = "enabled", havingValue = "true")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 设置序列化器
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);
        
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        
        template.afterPropertiesSet();
        return template;
    }
}

// 自定义条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(CustomPropertyCondition.class)
public @interface ConditionalOnCustomProperty {
    String prefix() default "";
    String name() default "";
    String havingValue() default "";
    boolean matchIfMissing() default false;
}

// 自定义条件实现
public class CustomPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> attrs = metadata.getAnnotationAttributes(
            ConditionalOnCustomProperty.class.getName());
        String prefix = (String) attrs.get("prefix");
        String name = (String) attrs.get("name");
        String havingValue = (String) attrs.get("havingValue");
        boolean matchIfMissing = (Boolean) attrs.get("matchIfMissing");
        
        String propertyName = prefix.isEmpty() ? name : prefix + "." + name;
        String actualValue = context.getEnvironment().getProperty(propertyName);
        
        if (actualValue == null) {
            return matchIfMissing;
        }
        
        return havingValue.equals(actualValue);
    }
}

1.3 自定义Starter开发实战

创建自定义Starter步骤:

// 1. 核心功能类
public class CustomService {
    private final CustomProperties properties;
    private final RedisTemplate<String, Object> redisTemplate;
    
    public CustomService(CustomProperties properties, RedisTemplate<String, Object> redisTemplate) {
        this.properties = properties;
        this.redisTemplate = redisTemplate;
    }
    
    public String process(String input) {
        String result = properties.getPrefix() + input + properties.getSuffix();
        
        // 如果启用了缓存
        if (properties.isCacheEnabled()) {
            String cacheKey = "custom:process:" + input.hashCode();
            Object cached = redisTemplate.opsForValue().get(cacheKey);
            if (cached != null) {
                return (String) cached;
            }
            
            redisTemplate.opsForValue().set(cacheKey, result, 
                Duration.ofSeconds(properties.getCacheTtl()));
        }
        
        return result;
    }
    
    public void clearCache() {
        if (properties.isCacheEnabled()) {
            redisTemplate.delete("custom:process:*");
        }
    }
}

// 2. 配置属性
@ConfigurationProperties(prefix = "custom.service")
@Validated
public class CustomProperties {
    
    @NotBlank
    private String prefix = "[";
    
    @NotBlank
    private String suffix = "]";
    
    private boolean enabled = true;
    
    private boolean cacheEnabled = false;
    
    @Min(1)
    @Max(3600)
    private long cacheTtl = 300;
    
    // getter和setter方法
    public String getPrefix() { return prefix; }
    public void setPrefix(String prefix) { this.prefix = prefix; }
    public String getSuffix() { return suffix; }
    public void setSuffix(String suffix) { this.suffix = suffix; }
    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    public boolean isCacheEnabled() { return cacheEnabled; }
    public void setCacheEnabled(boolean cacheEnabled) { this.cacheEnabled = cacheEnabled; }
    public long getCacheTtl() { return cacheTtl; }
    public void setCacheTtl(long cacheTtl) { this.cacheTtl = cacheTtl; }
}

// 3. 自动配置类
@Configuration
@ConditionalOnClass(CustomService.class)
@EnableConfigurationProperties(CustomProperties.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class CustomServiceAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "custom.service", name = "enabled", havingValue = "true")
    public CustomService customService(CustomProperties properties, 
                                     RedisTemplate<String, Object> redisTemplate) {
        return new CustomService(properties, redisTemplate);
    }
    
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "custom.service", name = "enabled", havingValue = "true")
    public CustomServiceController customServiceController(CustomService customService) {
        return new CustomServiceController(customService);
    }
}

// 4. 控制器
@RestController
@RequestMapping("/api/custom")
public class CustomServiceController {
    
    private final CustomService customService;
    
    public CustomServiceController(CustomService customService) {
        this.customService = customService;
    }
    
    @PostMapping("/process")
    public ResponseEntity<String> process(@RequestBody ProcessRequest request) {
        String result = customService.process(request.getInput());
        return ResponseEntity.ok(result);
    }
    
    @DeleteMapping("/cache")
    public ResponseEntity<Void> clearCache() {
        customService.clearCache();
        return ResponseEntity.ok().build();
    }
}

// 5. spring.factories文件内容
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=
// com.example.custom.CustomServiceAutoConfiguration

2. 微服务架构基础深入

2.1 微服务设计原则与最佳实践

核心原则:

// 1. 单一职责原则 - 用户服务
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> getUser(@PathVariable @Min(1) Long id) {
        User user = userService.findById(id);
        if (user == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(UserResponse.from(user));
    }
    
    @PostMapping
    public ResponseEntity<UserResponse> createUser(@Valid @RequestBody CreateUserRequest request) {
        User user = userService.create(request);
        return ResponseEntity.status(HttpStatus.CREATED)
                .body(UserResponse.from(user));
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<UserResponse> updateUser(@PathVariable @Min(1) Long id,
                                                 @Valid @RequestBody UpdateUserRequest request) {
        User user = userService.update(id, request);
        if (user == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(UserResponse.from(user));
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable @Min(1) Long id) {
        boolean deleted = userService.delete(id);
        if (!deleted) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.noContent().build();
    }
    
    @GetMapping
    public ResponseEntity<Page<UserResponse>> getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sortBy,
            @RequestParam(defaultValue = "asc") String sortDir) {
        Page<User> users = userService.findAll(page, size, sortBy, sortDir);
        Page<UserResponse> response = users.map(UserResponse::from);
        return ResponseEntity.ok(response);
    }
}

// 2. 数据独立原则 - 用户实体
@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false, length = 50)
    @NotBlank
    @Size(min = 3, max = 50)
    private String username;
    
    @Column(nullable = false, length = 100)
    @NotBlank
    @Email
    @Size(max = 100)
    private String email;
    
    @Column(name = "first_name", length = 50)
    @Size(max = 50)
    private String firstName;
    
    @Column(name = "last_name", length = 50)
    @Size(max = 50)
    private String lastName;
    
    @Column(name = "phone", length = 20)
    @Pattern(regexp = "^[0-9+\-\s()]+$")
    private String phone;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "status", nullable = false)
    private UserStatus status = UserStatus.ACTIVE;
    
    @Column(name = "created_at", nullable = false, updatable = false)
    @CreatedDate
    private LocalDateTime createdAt;
    
    @Column(name = "updated_at")
    @LastModifiedDate
    private LocalDateTime updatedAt;
    
    @Column(name = "created_by", length = 50)
    @CreatedBy
    private String createdBy;
    
    @Column(name = "updated_by", length = 50)
    @LastModifiedBy
    private String updatedBy;
    
    // 构造函数
    public User() {}
    
    public User(String username, String email, String firstName, String lastName) {
        this.username = username;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
        this.status = UserStatus.ACTIVE;
    }
    
    // getter和setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    public UserStatus getStatus() { return status; }
    public void setStatus(UserStatus status) { this.status = status; }
    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
    public LocalDateTime getUpdatedAt() { return updatedAt; }
    public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
    public String getCreatedBy() { return createdBy; }
    public void setCreatedBy(String createdBy) { this.createdBy = createdBy; }
    public String getUpdatedBy() { return updatedBy; }
    public void setUpdatedBy(String updatedBy) { this.updatedBy = updatedBy; }
}

// 3. 用户状态枚举
public enum UserStatus {
    ACTIVE("激活"),
    INACTIVE("未激活"),
    SUSPENDED("暂停"),
    DELETED("已删除");
    
    private final String description;
    
    UserStatus(String description) {
        this.description = description;
    }
    
    public String getDescription() {
        return description;
    }
}

2.2 服务间通信模式

RESTful API调用:

// 订单服务调用用户服务
@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired
    private CircuitBreakerFactory circuitBreakerFactory;
    
    @Value("${user.service.url}")
    private String userServiceUrl;
    
    @Value("${user.service.timeout:5000}")
    private int timeout;
    
    public Order createOrder(Long userId, OrderRequest request) {
        // 使用熔断器调用用户服务
        CircuitBreaker circuitBreaker = circuitBreakerFactory.create("user-service");
        
        User user = circuitBreaker.run(() -> {
            try {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                headers.set("X-Service-Name", "order-service");
                headers.set("X-Request-ID", UUID.randomUUID().toString());
                
                HttpEntity<Void> entity = new HttpEntity<>(headers);
                
                ResponseEntity<User> response = restTemplate.exchange(
                    userServiceUrl + "/api/users/" + userId,
                    HttpMethod.GET,
                    entity,
                    User.class
                );
                
                if (response.getStatusCode() == HttpStatus.OK) {
                    return response.getBody();
                } else {
                    throw new ServiceException("用户服务返回错误状态: " + response.getStatusCode());
                }
            } catch (ResourceAccessException e) {
                log.error("调用用户服务超时", e);
                throw new ServiceTimeoutException("用户服务调用超时", e);
            } catch (HttpClientErrorException e) {
                if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
                    throw new UserNotFoundException("用户不存在: " + userId);
                }
                log.error("调用用户服务失败", e);
                throw new ServiceException("用户服务调用失败: " + e.getMessage(), e);
            }
        }, throwable -> {
            log.error("用户服务熔断器触发", throwable);
            throw new ServiceUnavailableException("用户服务暂时不可用");
        });
        
        if (user == null) {
            throw new UserNotFoundException("用户不存在");
        }
        
        // 验证用户状态
        if (user.getStatus() != UserStatus.ACTIVE) {
            throw new UserInactiveException("用户状态异常,无法创建订单");
        }
        
        // 创建订单
        Order order = new Order();
        order.setUserId(userId);
        order.setAmount(request.getAmount());
        order.setStatus(OrderStatus.PENDING);
        order.setCreatedAt(LocalDateTime.now());
        order.setOrderNumber(generateOrderNumber());
        
        return orderRepository.save(order);
    }
    
    private String generateOrderNumber() {
        return "ORD" + System.currentTimeMillis() + RandomStringUtils.randomNumeric(4);
    }
}

// 异常定义
public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

public class UserInactiveException extends RuntimeException {
    public UserInactiveException(String message) {
        super(message);
    }
}

public class ServiceTimeoutException extends RuntimeException {
    public ServiceTimeoutException(String message, Throwable cause) {
        super(message, cause);
    }
}

public class ServiceUnavailableException extends RuntimeException {
    public ServiceUnavailableException(String message) {
        super(message);
    }
}

2.3 API网关设计

网关配置示例:

// 网关配置类
@Configuration
@EnableWebFlux
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r.path("/api/users/**")
                .filters(f -> f.stripPrefix(2)
                    .addRequestHeader("X-Gateway", "true")
                    .addRequestHeader("X-Request-ID", generateRequestId())
                    .circuitBreaker(config -> config
                        .setName("user-service")
                        .setFallbackUri("forward:/fallback/user-service"))
                    .retry(config -> config
                        .setRetries(3)
                        .setMethods(HttpMethod.GET, HttpMethod.POST)
                        .setStatuses(HttpStatus.INTERNAL_SERVER_ERROR)
                        .setBackoff(Duration.ofMillis(100), Duration.ofMillis(1000), 2, true))
                    .requestRateLimiter(config -> config
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(ipKeyResolver()))
                    .modifyResponseBody(String.class, String.class, 
                        (exchange, response) -> {
                            // 添加响应头
                            ServerHttpResponse httpResponse = exchange.getResponse();
                            httpResponse.getHeaders().add("X-Response-Time", 
                                String.valueOf(System.currentTimeMillis()));
                            return Mono.just(response);
                        }))
                .uri("lb://user-service"))
            .route("order-service", r -> r.path("/api/orders/**")
                .filters(f -> f.stripPrefix(2)
                    .addRequestHeader("X-Gateway", "true")
                    .addRequestHeader("X-Request-ID", generateRequestId())
                    .circuitBreaker(config -> config
                        .setName("order-service")
                        .setFallbackUri("forward:/fallback/order-service"))
                    .retry(config -> config
                        .setRetries(2)
                        .setMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT)
                        .setStatuses(HttpStatus.INTERNAL_SERVER_ERROR)
                        .setBackoff(Duration.ofMillis(200), Duration.ofMillis(2000), 2, true)))
                .uri("lb://order-service"))
            .route("notification-service", r -> r.path("/api/notifications/**")
                .filters(f -> f.stripPrefix(2)
                    .addRequestHeader("X-Gateway", "true")
                    .addRequestHeader("X-Request-ID", generateRequestId())
                    .circuitBreaker(config -> config
                        .setName("notification-service")
                        .setFallbackUri("forward:/fallback/notification-service")))
                .uri("lb://notification-service"))
            .build();
    }
    
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20, 1);
    }
    
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }
    
    private String generateRequestId() {
        return UUID.randomUUID().toString();
    }
    
    @Bean
    public GlobalFilter customGlobalFilter() {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            
            // 添加请求ID
            String requestId = UUID.randomUUID().toString();
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-Request-ID", requestId)
                .header("X-Forwarded-For", getClientIp(request))
                .build();
            
            // 记录请求日志
            log.info("Gateway Request: {} {} from {}", 
                request.getMethod(), path, getClientIp(request));
            
            return chain.filter(exchange.mutate().request(mutatedRequest).build())
                .doOnSuccess(response -> {
                    log.info("Gateway Response: {} {} - {}", 
                        request.getMethod(), path, response.getStatusCode());
                })
                .doOnError(error -> {
                    log.error("Gateway Error: {} {} - {}", 
                        request.getMethod(), path, error.getMessage());
                });
        };
    }
    
    private String getClientIp(ServerHttpRequest request) {
        String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        return request.getRemoteAddress() != null ? 
            request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
    }
}

3. Spring Cloud入门深入

3.1 服务注册与发现 - Eureka

Eureka Server配置:

// Eureka服务端
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// application.yml配置
server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 10000
    response-cache-update-interval-ms: 3000
    response-cache-auto-expiration-in-seconds: 180
    renewal-percent-threshold: 0.85

Eureka Client配置:

// 服务提供者
@SpringBootApplication
@EnableEurekaClient
@RestController
@Slf4j
public class UserServiceApplication {
    
    @Value("${server.port}")
    private String port;
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> health() {
        Map<String, Object> health = new HashMap<>();
        health.put("status", "UP");
        health.put("service", "user-service");
        health.put("port", port);
        health.put("timestamp", LocalDateTime.now());
        health.put("database", checkDatabaseHealth());
        return ResponseEntity.ok(health);
    }
    
    @GetMapping("/info")
    public ResponseEntity<Map<String, Object>> info() {
        Map<String, Object> info = new HashMap<>();
        info.put("service", "user-service");
        info.put("version", "1.0.0");
        info.put("description", "用户管理服务");
        info.put("port", port);
        info.put("uptime", getUptime());
        return ResponseEntity.ok(info);
    }
    
    private String checkDatabaseHealth() {
        try {
            // 检查数据库连接
            return "UP";
        } catch (Exception e) {
            return "DOWN";
        }
    }
    
    private String getUptime() {
        // 计算服务运行时间
        return "运行中";
    }
    
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// application.yml配置
spring:
  application:
    name: user-service
  profiles:
    active: dev

server:
  port: 8081

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    register-with-eureka: true
    fetch-registry: true
    registry-fetch-interval-seconds: 30
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.profiles.active}:${server.port}
    lease-renewal-interval-in-seconds: 30
    lease-expiration-duration-in-seconds: 90
    status-page-url-path: /actuator/info
    health-check-url-path: /actuator/health

3.2 配置中心 - Spring Cloud Config

Config Server配置:

@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

// application.yml
server:
  port: 8888

spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-repo/config-repo
          search-paths: configs
          clone-on-start: true
          force-pull: true
          timeout: 10
        native:
          search-locations: classpath:/config
      label: main
  profiles:
    active: git

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

Config Client使用:

@RestController
@RefreshScope
@Slf4j
public class ConfigController {
    
    @Value("${app.name:default}")
    private String appName;
    
    @Value("${app.version:1.0}")
    private String appVersion;
    
    @Value("${app.description:默认描述}")
    private String appDescription;
    
    @Value("${app.features:[]}")
    private List<String> features;
    
    @Value("${app.database.url:jdbc:h2:mem:testdb}")
    private String databaseUrl;
    
    @Value("${app.redis.host:localhost}")
    private String redisHost;
    
    @Value("${app.redis.port:6379}")
    private int redisPort;
    
    @GetMapping("/config")
    public ResponseEntity<Map<String, Object>> getConfig() {
        Map<String, Object> config = new HashMap<>();
        config.put("name", appName);
        config.put("version", appVersion);
        config.put("description", appDescription);
        config.put("features", features);
        config.put("database", Map.of("url", databaseUrl));
        config.put("redis", Map.of("host", redisHost, "port", redisPort));
        config.put("timestamp", LocalDateTime.now());
        return ResponseEntity.ok(config);
    }
    
    @PostMapping("/refresh")
    public ResponseEntity<Map<String, String>> refresh() {
        // 手动刷新配置
        log.info("手动刷新配置");
        return ResponseEntity.ok(Map.of("status", "success", "message", "配置已刷新"));
    }
}

// bootstrap.yml配置
spring:
  application:
    name: user-service
  cloud:
    config:
      uri: http://localhost:8888
      fail-fast: true
      retry:
        initial-interval: 1000
        max-attempts: 6
        max-interval: 2000
        multiplier: 1.1
      discovery:
        enabled: true
        service-id: config-server

3.3 服务调用 - OpenFeign

Feign客户端配置:

// 用户服务Feign客户端
@FeignClient(name = "user-service", 
             fallback = UserServiceFallback.class,
             configuration = FeignConfig.class)
public interface UserServiceClient {
    
    @GetMapping("/api/users/{id}")
    User getUserById(@PathVariable("id") Long id);
    
    @PostMapping("/api/users")
    User createUser(@RequestBody User user);
    
    @GetMapping("/api/users")
    List<User> getAllUsers(@RequestParam("page") int page, 
                          @RequestParam("size") int size);
    
    @PutMapping("/api/users/{id}")
    User updateUser(@PathVariable("id") Long id, @RequestBody User user);
    
    @DeleteMapping("/api/users/{id}")
    void deleteUser(@PathVariable("id") Long id);
}

// Feign配置
@Configuration
public class FeignConfig {
    
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
    
    @Bean
    public RequestInterceptor requestInterceptor() {
        return requestTemplate -> {
            requestTemplate.header("X-Service-Name", "order-service");
            requestTemplate.header("X-Request-ID", UUID.randomUUID().toString());
            requestTemplate.header("X-Request-Time", String.valueOf(System.currentTimeMillis()));
        };
    }
    
    @Bean
    public Retryer retryer() {
        return new Retryer.Default(1000, 2000, 3);
    }
    
    @Bean
    public ErrorDecoder errorDecoder() {
        return new CustomErrorDecoder();
    }
}

// 自定义错误解码器
public class CustomErrorDecoder implements ErrorDecoder {
    
    private final ErrorDecoder defaultErrorDecoder = new Default();
    
    @Override
    public Exception decode(String methodKey, Response response) {
        switch (response.status()) {
            case 400:
                return new BadRequestException("请求参数错误");
            case 401:
                return new UnauthorizedException("未授权访问");
            case 403:
                return new ForbiddenException("禁止访问");
            case 404:
                return new UserNotFoundException("用户不存在");
            case 500:
                return new ServiceException("服务内部错误");
            default:
                return defaultErrorDecoder.decode(methodKey, response);
        }
    }
}

// 降级处理
@Component
@Slf4j
public class UserServiceFallback implements UserServiceClient {
    
    @Override
    public User getUserById(Long id) {
        log.warn("用户服务降级处理: getUserById, id={}", id);
        User user = new User();
        user.setId(id);
        user.setUsername("用户服务暂时不可用");
        user.setEmail("[email protected]");
        user.setStatus(UserStatus.INACTIVE);
        return user;
    }
    
    @Override
    public User createUser(User user) {
        log.warn("用户服务降级处理: createUser");
        throw new ServiceUnavailableException("用户服务暂时不可用,无法创建用户");
    }
    
    @Override
    public List<User> getAllUsers(int page, int size) {
        log.warn("用户服务降级处理: getAllUsers");
        return Collections.emptyList();
    }
    
    @Override
    public User updateUser(Long id, User user) {
        log.warn("用户服务降级处理: updateUser, id={}", id);
        throw new ServiceUnavailableException("用户服务暂时不可用,无法更新用户");
    }
    
    @Override
    public void deleteUser(Long id) {
        log.warn("用户服务降级处理: deleteUser, id={}", id);
        throw new ServiceUnavailableException("用户服务暂时不可用,无法删除用户");
    }
}

3.4 熔断器 - Hystrix

熔断器配置:

@Service
@Slf4j
public class PaymentService {
    
    @HystrixCommand(fallbackMethod = "processPaymentFallback",
                   commandProperties = {
                       @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
                       @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                       @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
                       @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"),
                       @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
                       @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000"),
                       @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10")
                   },
                   threadPoolProperties = {
                       @HystrixProperty(name = "coreSize", value = "10"),
                       @HystrixProperty(name = "maxQueueSize", value = "100"),
                       @HystrixProperty(name = "queueSizeRejectionThreshold", value = "80")
                   })
    public PaymentResult processPayment(PaymentRequest request) {
        log.info("开始处理支付请求: {}", request.getOrderId());
        
        // 模拟支付处理
        if (Math.random() > 0.7) {
            throw new RuntimeException("支付服务异常");
        }
        
        // 模拟网络延迟
        try {
            Thread.sleep(1000 + (long)(Math.random() * 2000));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("支付处理被中断", e);
        }
        
        PaymentResult result = new PaymentResult();
        result.setSuccess(true);
        result.setTransactionId(UUID.randomUUID().toString());
        result.setAmount(request.getAmount());
        result.setOrderId(request.getOrderId());
        result.setProcessedAt(LocalDateTime.now());
        result.setPaymentMethod(request.getPaymentMethod());
        
        log.info("支付处理成功: {}", result.getTransactionId());
        return result;
    }
    
    public PaymentResult processPaymentFallback(PaymentRequest request, Throwable throwable) {
        log.error("支付服务降级处理: {}", request.getOrderId(), throwable);
        
        PaymentResult result = new PaymentResult();
        result.setSuccess(false);
        result.setMessage("支付服务暂时不可用,请稍后重试");
        result.setOrderId(request.getOrderId());
        result.setProcessedAt(LocalDateTime.now());
        result.setErrorCode("SERVICE_UNAVAILABLE");
        result.setErrorDetails(throwable != null ? throwable.getMessage() : "未知错误");
        
        return result;
    }
    
    @HystrixCommand(fallbackMethod = "refundPaymentFallback")
    public RefundResult refundPayment(String transactionId, BigDecimal amount) {
        log.info("开始处理退款请求: {}", transactionId);
        
        // 模拟退款处理
        if (Math.random() > 0.8) {
            throw new RuntimeException("退款服务异常");
        }
        
        RefundResult result = new RefundResult();
        result.setSuccess(true);
        result.setRefundId(UUID.randomUUID().toString());
        result.setTransactionId(transactionId);
        result.setAmount(amount);
        result.setProcessedAt(LocalDateTime.now());
        
        log.info("退款处理成功: {}", result.getRefundId());
        return result;
    }
    
    public RefundResult refundPaymentFallback(String transactionId, BigDecimal amount, Throwable throwable) {
        log.error("退款服务降级处理: {}", transactionId, throwable);
        
        RefundResult result = new RefundResult();
        result.setSuccess(false);
        result.setMessage("退款服务暂时不可用,请稍后重试");
        result.setTransactionId(transactionId);
        result.setAmount(amount);
        result.setProcessedAt(LocalDateTime.now());
        result.setErrorCode("SERVICE_UNAVAILABLE");
        
        return result;
    }
}

4. 实战案例:构建简单微服务系统

4.1 项目结构设计

microservice-demo/
├── eureka-server/          # 注册中心
│   ├── src/main/java/
│   ├── src/main/resources/
│   └── pom.xml
├── config-server/          # 配置中心
│   ├── src/main/java/
│   ├── src/main/resources/
│   └── pom.xml
├── api-gateway/           # API网关
│   ├── src/main/java/
│   ├── src/main/resources/
│   └── pom.xml
├── user-service/          # 用户服务
│   ├── src/main/java/
│   ├── src/main/resources/
│   └── pom.xml
├── order-service/         # 订单服务
│   ├── src/main/java/
│   ├── src/main/resources/
│   └── pom.xml
├── notification-service/  # 通知服务
│   ├── src/main/java/
│   ├── src/main/resources/
│   └── pom.xml
└── common/               # 公共模块
    ├── model/            # 实体类
    ├── dto/              # 数据传输对象
    ├── util/             # 工具类
    └── pom.xml

4.2 服务间通信实现

异步消息处理:

// 消息发布者
@Component
@Slf4j
public class OrderEventPublisher {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Value("${app.rabbitmq.exchange.order}")
    private String orderExchange;
    
    @Value("${app.rabbitmq.routing-key.order.created}")
    private String orderCreatedRoutingKey;
    
    public void publishOrderCreated(Order order) {
        try {
            OrderEvent event = new OrderEvent();
            event.setOrderId(order.getId());
            event.setUserId(order.getUserId());
            event.setAmount(order.getAmount());
            event.setEventType("ORDER_CREATED");
            event.setTimestamp(LocalDateTime.now());
            event.setOrderNumber(order.getOrderNumber());
            
            // 设置消息属性
            MessageProperties properties = new MessageProperties();
            properties.setContentType("application/json");
            properties.setMessageId(UUID.randomUUID().toString());
            properties.setTimestamp(new Date());
            properties.setHeader("eventType", "ORDER_CREATED");
            properties.setHeader("serviceName", "order-service");
            
            Message message = new Message(JSON.toJSONBytes(event), properties);
            
            rabbitTemplate.convertAndSend(orderExchange, orderCreatedRoutingKey, message);
            log.info("订单创建事件发布成功: {}", order.getOrderNumber());
        } catch (Exception e) {
            log.error("订单创建事件发布失败: {}", order.getOrderNumber(), e);
            throw new EventPublishException("事件发布失败", e);
        }
    }
    
    public void publishOrderPaid(Order order, PaymentResult payment) {
        try {
            OrderEvent event = new OrderEvent();
            event.setOrderId(order.getId());
            event.setUserId(order.getUserId());
            event.setAmount(order.getAmount());
            event.setEventType("ORDER_PAID");
            event.setTimestamp(LocalDateTime.now());
            event.setOrderNumber(order.getOrderNumber());
            event.setTransactionId(payment.getTransactionId());
            
            MessageProperties properties = new MessageProperties();
            properties.setContentType("application/json");
            properties.setMessageId(UUID.randomUUID().toString());
            properties.setTimestamp(new Date());
            properties.setHeader("eventType", "ORDER_PAID");
            properties.setHeader("serviceName", "order-service");
            
            Message message = new Message(JSON.toJSONBytes(event), properties);
            
            rabbitTemplate.convertAndSend(orderExchange, "order.paid", message);
            log.info("订单支付事件发布成功: {}", order.getOrderNumber());
        } catch (Exception e) {
            log.error("订单支付事件发布失败: {}", order.getOrderNumber(), e);
            throw new EventPublishException("事件发布失败", e);
        }
    }
}

// 消息消费者
@Component
@RabbitListener(queues = "order.notification.queue")
@Slf4j
public class OrderNotificationConsumer {
    
    @Autowired
    private NotificationService notificationService;
    
    @RabbitHandler
    public void handleOrderCreated(OrderEvent event) {
        try {
            log.info("接收到订单创建事件: {}", event.getOrderId());
            
            // 发送订单创建通知
            notificationService.sendOrderCreatedNotification(event);
            
            log.info("订单创建通知发送成功: {}", event.getOrderId());
        } catch (Exception e) {
            log.error("订单创建通知发送失败: {}", event.getOrderId(), e);
            // 可以在这里实现重试机制或死信队列处理
        }
    }
    
    @RabbitHandler
    public void handleOrderPaid(OrderEvent event) {
        try {
            log.info("接收到订单支付事件: {}", event.getOrderId());

            // 发送订单支付通知
            notificationService.sendOrderPaidNotification(event);
            
            log.info("订单支付通知发送成功: {}", event.getOrderId());
        } catch (Exception e) {
            log.error("订单支付通知发送失败: {}", event.getOrderId(), e);
        }
    }
}

// 订单事件实体
public class OrderEvent {
    private Long orderId;
    private Long userId;
    private BigDecimal amount;
    private String eventType;
    private LocalDateTime timestamp;
    private String orderNumber;
    private String transactionId;
    
    // 构造函数
    public OrderEvent() {}
    
    // getter和setter方法
    public Long getOrderId() { return orderId; }
    public void setOrderId(Long orderId) { this.orderId = orderId; }
    public Long getUserId() { return userId; }
    public void setUserId(Long userId) { this.userId = userId; }
    public BigDecimal getAmount() { return amount; }
    public void setAmount(BigDecimal amount) { this.amount = amount; }
    public String getEventType() { return eventType; }
    public void setEventType(String eventType) { this.eventType = eventType; }
    public LocalDateTime getTimestamp() { return timestamp; }
    public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
    public String getOrderNumber() { return orderNumber; }
    public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }
    public String getTransactionId() { return transactionId; }
    public void setTransactionId(String transactionId) { this.transactionId = transactionId; }
}

4.3 分布式事务处理

Saga模式实现:

// Saga编排器
@Component
@Slf4j
public class OrderSagaOrchestrator {
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    @Autowired
    private PaymentServiceClient paymentServiceClient;
    
    @Autowired
    private InventoryServiceClient inventoryServiceClient;
    
    @Autowired
    private OrderEventPublisher eventPublisher;
    
    public OrderResult processOrder(OrderRequest request) {
        log.info("开始处理订单Saga: {}", request.getOrderNumber());
        
        List<SagaStep> steps = new ArrayList<>();
        
        // 步骤1:验证用户
        steps.add(new SagaStep("validateUser", 
            () -> {
                log.info("执行用户验证步骤");
                User user = userServiceClient.getUserById(request.getUserId());
                if (user == null || user.getStatus() != UserStatus.ACTIVE) {
                    throw new UserValidationException("用户验证失败");
                }
                return user;
            },
            () -> {
                log.info("补偿用户验证步骤");
                // 用户验证步骤通常不需要补偿
            }));
        
        // 步骤2:扣减库存
        steps.add(new SagaStep("reserveInventory",
            () -> {
                log.info("执行库存扣减步骤");
                InventoryReservation reservation = inventoryServiceClient.reserve(
                    request.getProductId(), request.getQuantity());
                if (reservation == null || !reservation.isSuccess()) {
                    throw new InventoryException("库存扣减失败");
                }
                return reservation;
            },
            () -> {
                log.info("补偿库存扣减步骤");
                inventoryServiceClient.release(request.getProductId(), request.getQuantity());
            }));
        
        // 步骤3:处理支付
        steps.add(new SagaStep("processPayment",
            () -> {
                log.info("执行支付处理步骤");
                PaymentRequest paymentRequest = new PaymentRequest();
                paymentRequest.setOrderId(request.getOrderId());
                paymentRequest.setAmount(request.getAmount());
                paymentRequest.setPaymentMethod(request.getPaymentMethod());
                
                PaymentResult payment = paymentServiceClient.charge(paymentRequest);
                if (payment == null || !payment.isSuccess()) {
                    throw new PaymentException("支付处理失败");
                }
                return payment;
            },
            () -> {
                log.info("补偿支付处理步骤");
                paymentServiceClient.refund(request.getTransactionId(), request.getAmount());
            }));
        
        // 步骤4:创建订单
        steps.add(new SagaStep("createOrder",
            () -> {
                log.info("执行订单创建步骤");
                Order order = createOrder(request);
                eventPublisher.publishOrderCreated(order);
                return order;
            },
            () -> {
                log.info("补偿订单创建步骤");
                // 删除已创建的订单
                deleteOrder(request.getOrderId());
            }));
        
        return executeSaga(steps);
    }
    
    private OrderResult executeSaga(List<SagaStep> steps) {
        List<SagaStep> executedSteps = new ArrayList<>();
        
        try {
            for (SagaStep step : steps) {
                log.info("执行Saga步骤: {}", step.getName());
                step.execute();
                executedSteps.add(step);
                log.info("Saga步骤执行成功: {}", step.getName());
            }
            
            log.info("Saga执行成功");
            return OrderResult.success("订单处理成功");
        } catch (Exception e) {
            log.error("Saga执行失败,开始补偿操作", e);
            
            // 补偿执行
            Collections.reverse(executedSteps);
            for (SagaStep step : executedSteps) {
                try {
                    log.info("执行补偿步骤: {}", step.getName());
                    step.compensate();
                    log.info("补偿步骤执行成功: {}", step.getName());
                } catch (Exception ex) {
                    log.error("补偿操作失败: {}", step.getName(), ex);
                    // 记录补偿失败,可能需要人工干预
                }
            }
            
            return OrderResult.failure("订单处理失败: " + e.getMessage());
        }
    }
    
    private Order createOrder(OrderRequest request) {
        Order order = new Order();
        order.setId(request.getOrderId());
        order.setUserId(request.getUserId());
        order.setAmount(request.getAmount());
        order.setStatus(OrderStatus.PENDING);
        order.setCreatedAt(LocalDateTime.now());
        order.setOrderNumber(request.getOrderNumber());
        return orderRepository.save(order);
    }
    
    private void deleteOrder(Long orderId) {
        orderRepository.deleteById(orderId);
    }
}

// Saga步骤类
public class SagaStep {
    private final String name;
    private final Runnable executeAction;
    private final Runnable compensateAction;
    
    public SagaStep(String name, Runnable executeAction, Runnable compensateAction) {
        this.name = name;
        this.executeAction = executeAction;
        this.compensateAction = compensateAction;
    }
    
    public void execute() {
        executeAction.run();
    }
    
    public void compensate() {
        compensateAction.run();
    }
    
    public String getName() {
        return name;
    }
}

// 订单结果类
public class OrderResult {
    private boolean success;
    private String message;
    private String orderId;
    private LocalDateTime timestamp;
    
    public OrderResult(boolean success, String message) {
        this.success = success;
        this.message = message;
        this.timestamp = LocalDateTime.now();
    }
    
    public static OrderResult success(String message) {
        return new OrderResult(true, message);
    }
    
    public static OrderResult failure(String message) {
        return new OrderResult(false, message);
    }
    
    // getter和setter方法
    public boolean isSuccess() { return success; }
    public void setSuccess(boolean success) { this.success = success; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
    public String getOrderId() { return orderId; }
    public void setOrderId(String orderId) { this.orderId = orderId; }
    public LocalDateTime getTimestamp() { return timestamp; }
    public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}

4.4 服务监控与健康检查

健康检查配置:

// 自定义健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {
    
    @Autowired
    private DataSource dataSource;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Override
    public Health health() {
        Health.Builder builder = new Health.Builder();
        
        // 检查数据库连接
        try {
            Connection connection = dataSource.getConnection();
            if (connection.isValid(5)) {
                builder.withDetail("database", "UP");
                connection.close();
            } else {
                builder.withDetail("database", "DOWN");
                builder.down();
            }
        } catch (Exception e) {
            builder.withDetail("database", "DOWN");
            builder.withDetail("database.error", e.getMessage());
            builder.down();
        }
        
        // 检查Redis连接
        try {
            redisTemplate.opsForValue().get("health-check");
            builder.withDetail("redis", "UP");
        } catch (Exception e) {
            builder.withDetail("redis", "DOWN");
            builder.withDetail("redis.error", e.getMessage());
            builder.down();
        }
        
        // 检查内存使用情况
        Runtime runtime = Runtime.getRuntime();
        long maxMemory = runtime.maxMemory();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        
        builder.withDetail("memory.used", usedMemory);
        builder.withDetail("memory.max", maxMemory);
        builder.withDetail("memory.usage", (double) usedMemory / maxMemory * 100);
        
        // 检查磁盘空间
        File root = new File("/");
        long totalSpace = root.getTotalSpace();
        long freeSpace = root.getFreeSpace();
        long usedSpace = totalSpace - freeSpace;
        
        builder.withDetail("disk.used", usedSpace);
        builder.withDetail("disk.total", totalSpace);
        builder.withDetail("disk.usage", (double) usedSpace / totalSpace * 100);
        
        return builder.build();
    }
}

// 服务信息端点
@Component
@Endpoint(id = "service-info")
public class ServiceInfoEndpoint {
    
    @Value("${spring.application.name}")
    private String applicationName;
    
    @Value("${spring.application.version:1.0.0}")
    private String version;
    
    @Value("${server.port}")
    private String port;
    
    @ReadOperation
    public Map<String, Object> serviceInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("name", applicationName);
        info.put("version", version);
        info.put("port", port);
        info.put("uptime", getUptime());
        info.put("timestamp", LocalDateTime.now());
        info.put("jvm", getJvmInfo());
        return info;
    }
    
    private String getUptime() {
        long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
        return Duration.ofMillis(uptime).toString();
    }
    
    private Map<String, Object> getJvmInfo() {
        Map<String, Object> jvmInfo = new HashMap<>();
        RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
        jvmInfo.put("name", runtimeBean.getVmName());
        jvmInfo.put("version", runtimeBean.getVmVersion());
        jvmInfo.put("vendor", runtimeBean.getVmVendor());
        return jvmInfo;
    }
}

5. 学习总结与练习

5.1 核心知识点回顾

  1. Spring Boot高级特性

    • 自动配置原理和条件注解深入理解
    • 自定义Starter开发完整流程
    • 配置属性和外部化配置最佳实践
    • 条件注解的自定义实现
  2. 微服务架构设计

    • 服务拆分原则和最佳实践
    • API网关设计和服务治理
    • 服务间通信模式和容错处理
    • 分布式事务处理Saga模式
  3. Spring Cloud基础组件

    • Eureka服务注册发现配置优化
    • Config配置中心动态刷新
    • Feign服务调用和降级处理
    • Hystrix熔断器配置和监控
  4. 分布式系统实践

    • 异步消息处理机制
    • 服务监控和健康检查
    • 分布式事务协调
    • 容错和降级策略

5.2 实践练习

练习1:自定义Starter开发

  • 创建一个Redis操作Starter
  • 包含自动配置和条件注解
  • 提供简单的Redis操作API
  • 支持配置属性验证
  • 实现健康检查

练习2:微服务拆分实战

  • 将单体应用拆分为多个微服务
  • 实现服务注册发现
  • 配置API网关路由和熔断
  • 实现服务间调用和降级

练习3:分布式事务处理

  • 使用Saga模式处理分布式事务
  • 实现消息驱动的异步处理
  • 配置死信队列和重试机制
  • 实现事务补偿机制

练习4:服务监控和治理

  • 配置服务健康检查
  • 实现服务监控指标
  • 配置日志聚合和链路追踪
  • 实现服务降级和熔断

5.3 学习建议

  1. 理论学习:深入理解微服务架构的设计理念和最佳实践
  2. 实践操作:通过实际项目练习Spring Cloud组件的使用
  3. 问题解决:学会处理分布式系统中的常见问题
  4. 性能优化:了解微服务系统的性能调优方法
  5. 监控运维:掌握分布式系统的监控和运维技能

5.4 常见问题解决

问题1:服务注册失败

# 解决方案:检查Eureka配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${server.port}

问题2:配置刷新不生效

// 解决方案:添加@RefreshScope注解
@RestController
@RefreshScope
public class ConfigController {
    @Value("${app.name}")
    private String appName;
}

问题3:Feign调用超时

# 解决方案:配置超时时间
feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 10000

问题4:熔断器不生效

// 解决方案:检查Hystrix配置
@HystrixCommand(fallbackMethod = "fallbackMethod",
               commandProperties = {
                   @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10")
               })
public String serviceMethod() {
    // 服务调用逻辑
}

6. 明日预告

第24天将学习:

  • Spring Cloud Gateway:现代API网关实现
  • Spring Cloud Sleuth:分布式链路追踪
  • Spring Cloud Security:微服务安全认证
  • Docker容器化:微服务容器化部署
  • Kubernetes基础:容器编排和管理

继续加油,您已经掌握了微服务架构的核心概念!


7. 学习资源推荐

7.1 官方文档

  • Spring Boot官方文档
  • Spring Cloud官方文档
  • Eureka官方文档

7.2 推荐书籍

  • 《Spring Boot实战》
  • 《Spring Cloud微服务实战》
  • 《微服务架构设计模式》

7.3 在线资源

  • Spring官方教程
  • 微服务架构最佳实践
  • 分布式系统设计模式
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]