SpringBoot条件注解详细教程

发布于:2025-06-11 ⋅ 阅读:(34) ⋅ 点赞:(0)

文章目录

1. 条件注解基础概念

1.1 什么是条件注解

条件注解是SpringBoot提供的一套强大的机制,允许我们根据特定条件来决定是否创建Bean、加载配置类或执行某些操作。它是SpringBoot自动配置的核心基础,让应用能够根据环境、依赖、配置等因素智能地决定加载哪些组件。

核心特点:

  • 智能化:根据条件自动决定是否加载
  • 灵活性:支持多种判断条件
  • 可扩展:可以自定义条件逻辑
  • 高性能:在应用启动时进行条件判断,运行时不影响性能

1.2 为什么需要条件注解

在传统的Spring应用中,我们需要手动配置大量的Bean和组件。SpringBoot通过条件注解实现了"约定优于配置"的理念:

// 传统Spring配置(繁琐)
@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        // 需要手动判断环境、配置等
        if (hasH2Driver() && isTestEnvironment()) {
            return createH2DataSource();
        } else if (hasMySQLDriver() && hasValidMySQLConfig()) {
            return createMySQLDataSource();
        }
        throw new IllegalStateException("No valid datasource configuration found");
    }
    
    private boolean hasH2Driver() {
        try {
            Class.forName("org.h2.Driver");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
    
    // 更多复杂的判断逻辑...
}

// SpringBoot条件注解方式(简洁)
@Configuration
public class DataSourceAutoConfig {
    
    @Bean
    @ConditionalOnClass(name = "org.h2.Driver")
    @ConditionalOnProperty(name = "spring.datasource.url", havingValue = "jdbc:h2:")
    public DataSource h2DataSource() {
        return new H2DataSource();
    }
    
    @Bean
    @ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
    @ConditionalOnProperty(prefix = "spring.datasource", name = "url")
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource mysqlDataSource() {
        return new MySQLDataSource();
    }
}

1.3 条件注解的工作原理

条件注解基于Spring的@Conditional注解实现,工作流程如下:

// 基础Conditional注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

// Condition接口
public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

// SpringBoot条件注解的实现示例
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
    Class<?>[] value() default {};
    String[] name() default {};
}

执行时机:

  1. Spring容器启动时
  2. 解析配置类时
  3. 创建Bean定义时
  4. 在Bean实例化之前进行条件判断

判断顺序:

  1. 首先处理@ConditionalOnClass@ConditionalOnMissingClass
  2. 然后处理@ConditionalOnBean@ConditionalOnMissingBean
  3. 最后处理其他条件注解

2. SpringBoot自动配置原理

2.1 自动配置的核心机制

SpringBoot的自动配置通过@EnableAutoConfiguration注解启动,它会扫描META-INF/spring.factories文件中定义的自动配置类:

// 主启动类
@SpringBootApplication  // 包含了@EnableAutoConfiguration
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// @SpringBootApplication的组成
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration  // 关键注解
@ComponentScan(excludeFilters = { 
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) 
})
public @interface SpringBootApplication {
    // ...
}

2.2 spring.factories文件示例

# META-INF/spring.factories 文件内容示例
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration

2.3 典型的自动配置类结构

// Redis自动配置类示例
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)  // 必须有Redis相关类
@EnableConfigurationProperties(RedisProperties.class)  // 启用配置属性
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")  // 没有自定义时才创建
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)  // 有且仅有一个连接工厂
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean  // 没有自定义时才创建
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

// Redis配置属性类
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

    private int database = 0;
    private String url;
    private String host = "localhost";
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private Duration connectTimeout;
    private String clientName;
    private ClientType clientType;

    // 连接池配置
    private Pool pool;
    // Sentinel配置
    private Sentinel sentinel;
    // Cluster配置
    private Cluster cluster;
    // Jedis配置
    private Jedis jedis = new Jedis();
    // Lettuce配置
    private Lettuce lettuce = new Lettuce();

    // getter和setter方法...
}

3. 基础条件注解详解

3.1 @Conditional - 所有条件注解的基础

@Conditional是所有条件注解的基础,它需要指定一个实现了Condition接口的类:

// 自定义条件类
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取环境信息
        Environment environment = context.getEnvironment();
        String osName = environment.getProperty("os.name");
        
        // 判断是否为Linux系统
        return osName != null && osName.toLowerCase().contains("linux");
    }
}

// 使用自定义条件
@Configuration
public class SystemConfig {
    
    @Bean
    @Conditional(LinuxCondition.class)
    public FileSystemService linuxFileSystemService() {
        return new LinuxFileSystemService();
    }
    
    @Bean
    @Conditional(WindowsCondition.class)
    public FileSystemService windowsFileSystemService() {
        return new WindowsFileSystemService();
    }
}

// Windows条件判断
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String osName = context.getEnvironment().getProperty("os.name");
        return osName != null && osName.toLowerCase().contains("windows");
    }
}

3.2 ConditionContext详解

ConditionContext提供了丰富的上下文信息:

public class DetailedConditionExample implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        
        // 1. 获取Bean定义注册器
        BeanDefinitionRegistry registry = context.getRegistry();
        System.out.println("已注册的Bean数量: " + registry.getBeanDefinitionCount());
        
        // 2. 获取Bean工厂
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        if (beanFactory != null) {
            System.out.println("Bean工厂类型: " + beanFactory.getClass().getSimpleName());
        }
        
        // 3. 获取环境信息
        Environment environment = context.getEnvironment();
        
        // 获取激活的Profile
        String[] activeProfiles = environment.getActiveProfiles();
        System.out.println("激活的Profile: " + Arrays.toString(activeProfiles));
        
        // 获取系统属性
        String javaVersion = environment.getProperty("java.version");
        String osName = environment.getProperty("os.name");
        System.out.println("Java版本: " + javaVersion);
        System.out.println("操作系统: " + osName);
        
        // 获取应用配置
        String appName = environment.getProperty("spring.application.name");
        String serverPort = environment.getProperty("server.port", "8080");
        System.out.println("应用名称: " + appName);
        System.out.println("服务端口: " + serverPort);
        
        // 4. 获取资源加载器
        ResourceLoader resourceLoader = context.getResourceLoader();
        
        // 检查资源是否存在
        Resource resource = resourceLoader.getResource("classpath:custom-config.properties");
        boolean resourceExists = resource.exists();
        System.out.println("自定义配置文件存在: " + resourceExists);
        
        // 5. 获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        
        // 检查特定类是否存在
        try {
            Class<?> clazz = classLoader.loadClass("com.example.OptionalComponent");
            System.out.println("可选组件存在: " + clazz.getName());
            return true;
        } catch (ClassNotFoundException e) {
            System.out.println("可选组件不存在");
            return false;
        }
    }
}

3.3 AnnotatedTypeMetadata详解

AnnotatedTypeMetadata提供了注解元数据信息:

public class AnnotationMetadataCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        
        // 1. 检查是否包含特定注解
        boolean hasService = metadata.isAnnotated(Service.class.getName());
        boolean hasComponent = metadata.isAnnotated(Component.class.getName());
        
        System.out.println("包含@Service注解: " + hasService);
        System.out.println("包含@Component注解: " + hasComponent);
        
        // 2. 获取注解属性
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName());
        if (attributes != null) {
            String prefix = (String) attributes.get("prefix");
            String name = (String) attributes.get("name");
            String havingValue = (String) attributes.get("havingValue");
            
            System.out.println("属性前缀: " + prefix);
            System.out.println("属性名称: " + name);
            System.out.println("期望值: " + havingValue);
            
            // 验证属性值
            String fullPropertyName = prefix.isEmpty() ? name : prefix + "." + name;
            String actualValue = context.getEnvironment().getProperty(fullPropertyName);
            
            return havingValue.equals(actualValue);
        }
        
        // 3. 获取所有注解
        Set<String> annotationTypes = metadata.getAnnotationTypes();
        System.out.println("所有注解: " + annotationTypes);
        
        // 4. 检查元注解
        boolean hasConditional = metadata.isAnnotated(Conditional.class.getName());
        System.out.println("包含@Conditional注解: " + hasConditional);
        
        return true;
    }
}

// 使用示例
@Component
@ConditionalOnProperty(prefix = "app", name = "feature.enabled", havingValue = "true")
@Conditional(AnnotationMetadataCondition.class)
public class FeatureComponent {
    
    @PostConstruct
    public void init() {
        System.out.println("功能组件已初始化");
    }
}

4. 类存在性条件注解

4.1 @ConditionalOnClass - 当类存在时

当指定的类在类路径中存在时,条件才成立:

// 基础用法
@Configuration
public class DatabaseConfig {
    
    // 当H2数据库驱动存在时,创建H2数据源
    @Bean
    @ConditionalOnClass(name = "org.h2.Driver")
    public DataSource h2DataSource() {
        return DataSourceBuilder.create()
            .driverClassName("org.h2.Driver")
            .url("jdbc:h2:mem:testdb")
            .username("sa")
            .password("")
            .build();
    }
    
    // 当MySQL驱动存在时,创建MySQL数据源
    @Bean
    @ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
    @ConditionalOnProperty(prefix = "spring.datasource", name = "url")
    public DataSource mysqlDataSource(@Value("${spring.datasource.url}") String url,
                                     @Value("${spring.datasource.username}") String username,
                                     @Value("${spring.datasource.password}") String password) {
        return DataSourceBuilder.create()
            .driverClassName("com.mysql.cj.jdbc.Driver")
            .url(url)
            .username(username)
            .password(password)
            .build();
    }
}

// 使用Class对象(推荐方式,编译时检查)
@Configuration
public class CacheConfig {
    
    @Bean
    @ConditionalOnClass(RedisTemplate.class)  // 类型安全的方式
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        
        return RedisCacheManager.builder(redisConnectionFactory)
            .cacheDefaults(config)
            .build();
    }
    
    @Bean
    @ConditionalOnClass(name = "com.github.benmanes.caffeine.cache.Caffeine")
    @ConditionalOnMissingBean(CacheManager.class)  // 当没有其他缓存管理器时
    public CacheManager caffeineCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(Duration.ofMinutes(10)));
        return cacheManager;
    }
}

4.2 @ConditionalOnMissingClass - 当类不存在时

当指定的类在类路径中不存在时,条件才成立:

@Configuration
public class FallbackConfig {
    
    // 当Redis不可用时,使用内存缓存
    @Bean
    @ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")
    public CacheManager simpleCacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(
            new ConcurrentMapCache("users"),
            new ConcurrentMapCache("products"),
            new ConcurrentMapCache("orders")
        ));
        return cacheManager;
    }
    
    // 当没有专业的消息队列时,使用简单的内存队列
    @Bean
    @ConditionalOnMissingClass({
        "org.springframework.amqp.rabbit.core.RabbitTemplate",
        "org.apache.kafka.clients.producer.KafkaProducer"
    })
    public MessageQueue simpleMessageQueue() {
        return new SimpleInMemoryMessageQueue();
    }
}

// 简单的内存消息队列实现
@Component
public class SimpleInMemoryMessageQueue implements MessageQueue {
    
    private final Map<String, BlockingQueue<Object>> queues = new ConcurrentHashMap<>();
    private final ExecutorService executor = Executors.newCachedThreadPool();
    
    @Override
    public void send(String topic, Object message) {
        queues.computeIfAbsent(topic, k -> new LinkedBlockingQueue<>()).offer(message);
        System.out.println("消息已发送到内存队列 [" + topic + "]: " + message);
    }
    
    @Override
    public void subscribe(String topic, MessageHandler handler) {
        BlockingQueue<Object> queue = queues.computeIfAbsent(topic, k -> new LinkedBlockingQueue<>());
        
        executor.submit(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Object message = queue.take();
                    handler.handle(message);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        });
    }
}

4.3 多类条件组合

@Configuration
public class AdvancedClassConditionConfig {
    
    // 同时需要多个类存在
    @Bean
    @ConditionalOnClass({
        RedisTemplate.class,
        Jackson2JsonRedisSerializer.class,
        ObjectMapper.class
    })
    public RedisTemplate<String, Object> jsonRedisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 使用Jackson序列化
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LazyResolutionKey.NON_FINAL, 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;
    }
    
    // 复杂的类存在性判断
    @Bean
    @ConditionalOnClass(name = {
        "org.springframework.security.web.SecurityFilterChain",
        "org.springframework.security.config.annotation.web.builders.HttpSecurity"
    })
    @ConditionalOnMissingClass("org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider")
    public SecurityFilterChain basicSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults())
            .build();
    }
}

5. Bean存在性条件注解

5.1 @ConditionalOnBean - 当Bean存在时

当容器中存在指定的Bean时,条件才成立:

@Configuration
public class BeanConditionConfig {
    
    // 基础Bean
    @Bean
    @ConditionalOnProperty(name = "app.datasource.enabled", havingValue = "true")
    public DataSource dataSource() {
        return DataSourceBuilder.create()
            .url("jdbc:h2:mem:testdb")
            .username("sa")
            .password("")
            .build();
    }
    
    // 当DataSource存在时,创建JdbcTemplate
    @Bean
    @ConditionalOnBean(DataSource.class)
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
    
    // 当JdbcTemplate存在时,创建用户服务
    @Bean
    @ConditionalOnBean(JdbcTemplate.class)
    public UserService jdbcUserService(JdbcTemplate jdbcTemplate) {
        return new JdbcUserService(jdbcTemplate);
    }
    
    // 根据Bean名称判断
    @Bean
    @ConditionalOnBean(name = "customUserService")
    public UserController userController(@Qualifier("customUserService") UserService userService) {
        return new UserController(userService);
    }
    
    // 多个Bean条件(需要所有Bean都存在)
    @Bean
    @ConditionalOnBean({DataSource.class, RedisTemplate.class})
    public CacheableUserService cacheableUserService(DataSource dataSource, RedisTemplate<String, Object> redisTemplate) {
        return new CacheableUserService(dataSource, redisTemplate);
    }
}

// 用户服务实现
@Service("jdbcUserService")
public class JdbcUserService implements UserService {
    
    private final JdbcTemplate jdbcTemplate;
    
    public JdbcUserService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    @Override
    public List<User> findAll() {
        return jdbcTemplate.query("SELECT * FROM users", (rs, rowNum) -> {
            User user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            user.setEmail(rs.getString("email"));
            return user;
        });
    }
    
    @Override
    public User findById(Long id) {
        return jdbcTemplate.queryForObject(
            "SELECT * FROM users WHERE id = ?", 
            new Object[]{id},
            (rs, rowNum) -> {
                User user = new User();
                user.setId(rs.getLong("id"));
                user.setName(rs.getString("name"));
                user.setEmail(rs.getString("email"));
                return user;
            }
        );
    }
    
    @Override
    public User save(User user) {
        if (user.getId() == null) {
            KeyHolder keyHolder = new GeneratedKeyHolder();
            jdbcTemplate.update(connection -> {
                PreparedStatement ps = connection.prepareStatement(
                    "INSERT INTO users (name, email) VALUES (?, ?)",
                    Statement.RETURN_GENERATED_KEYS
                );
                ps.setString(1, user.getName());
                ps.setString(2, user.getEmail());
                return ps;
            }, keyHolder);
            user.setId(keyHolder.getKey().longValue());
        } else {
            jdbcTemplate.update(
                "UPDATE users SET name = ?, email = ? WHERE id = ?",
                user.getName(), user.getEmail(), user.getId()
            );
        }
        return user;
    }
}

5.2 @ConditionalOnMissingBean - 当Bean不存在时

当容器中不存在指定的Bean时,条件才成立。这是实现默认配置的常用方式:

@Configuration
public class DefaultBeanConfig {
    
    // 默认的用户服务(当没有其他实现时)
    @Bean
    @ConditionalOnMissingBean(UserService.class)
    public UserService defaultUserService() {
        return new DefaultUserService();
    }
    
    // 默认的缓存管理器
    @Bean
    @ConditionalOnMissingBean(CacheManager.class)
    public CacheManager defaultCacheManager() {
        return new ConcurrentMapCacheManager("users", "products", "orders");
    }
    
    // 根据名称判断Bean是否缺失
    @Bean("primaryDataSource")
    @ConditionalOnMissingBean(name = "primaryDataSource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create()
            .url("jdbc:h2:mem:primary")
            .username("sa")
            .password("")
            .build();
    }
}

// 默认用户服务实现
@Service
public class DefaultUserService implements UserService {
    
    private final Map<Long, User> users = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong(1);
    
    @PostConstruct
    public void init() {
        // 初始化一些测试数据
        save(new User(null, "张三", "zhangsan@example.com"));
        save(new User(null, "李四", "lisi@example.com"));
        save(new User(null, "王五", "wangwu@example.com"));
        System.out.println("默认用户服务已初始化,包含测试数据");
    }
    
    @Override
    public List<User> findAll() {
        return new ArrayList<>(users.values());
    }
    
    @Override
    public User findById(Long id) {
        User user = users.get(id);
        if (user == null) {
            throw new RuntimeException("用户不存在: " + id);
        }
        return user;
    }
    
    @Override
    public User save(User user) {
        if (user.getId() == null) {
            user.setId(idGenerator.getAndIncrement());
        }
        users.put(user.getId(), user);
        System.out.println("用户已保存: " + user);
        return user;
    }
}

6. 属性条件注解

6.1 @ConditionalOnProperty - 基于配置属性的条件

这是使用最频繁的条件注解之一,根据配置文件中的属性值来决定是否创建Bean:

@Configuration
public class PropertyConditionConfig {
    
    // 基础用法:检查属性是否存在
    @Bean
    @ConditionalOnProperty(name = "app.feature.enabled")
    public FeatureService basicFeatureService() {
        return new BasicFeatureService();
    }
    
    // 检查属性值是否匹配
    @Bean
    @ConditionalOnProperty(name = "app.cache.type", havingValue = "redis")
    public CacheManager redisCacheManager() {
        // Redis缓存管理器配置
        return new RedisCacheManager.RedisCacheManagerBuilder(redisConnectionFactory())
            .cacheDefaults(cacheConfiguration())
            .build();
    }
    
    @Bean
    @ConditionalOnProperty(name = "app.cache.type", havingValue = "caffeine")
    public CacheManager caffeineCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(Duration.ofMinutes(10)));
        return cacheManager;
    }
    
    // 使用前缀简化配置
    @Bean
    @ConditionalOnProperty(prefix = "app.security", name = "enabled", havingValue = "true")
    public SecurityConfig securityConfig() {
        return new SecurityConfig();
    }
    
    // 默认值处理
    @Bean
    @ConditionalOnProperty(
        prefix = "app.monitoring", 
        name = "enabled", 
        havingValue = "true", 
        matchIfMissing = true  // 如果属性不存在,默认为true
    )
    public MonitoringService monitoringService() {
        return new MonitoringService();
    }
}

// 配置文件示例 (application.yml)
/*
app:
  feature:
    enabled: true
  cache:
    type: redis  # 可选值: redis, caffeine, simple
  security:
    enabled: true
  monitoring:
    enabled: true  # 或者不配置,使用默认值
*/

// 监控服务
@Component
public class MonitoringService {
    
    @Value("${app.monitoring.interval:60}")
    private int monitoringInterval;
    
    @Value("${app.monitoring.metrics:cpu,memory,disk}")
    private String[] metrics;
    
    @PostConstruct
    public void init() {
        System.out.println("监控服务已启动");
        System.out.println("监控间隔: " + monitoringInterval + " 秒");
        System.out.println("监控指标: " + Arrays.toString(metrics));
    }
    
    @Scheduled(fixedRateString = "${app.monitoring.interval:60}000")
    public void collectMetrics() {
        for (String metric : metrics) {
            switch (metric.toLowerCase()) {
                case "cpu":
                    double cpuUsage = getCpuUsage();
                    System.out.println("CPU使用率: " + String.format("%.2f%%", cpuUsage));
                    break;
                case "memory":
                    long memoryUsage = getMemoryUsage();
                    System.out.println("内存使用: " + formatBytes(memoryUsage));
                    break;
                case "disk":
                    long diskUsage = getDiskUsage();
                    System.out.println("磁盘使用: " + formatBytes(diskUsage));
                    break;
            }
        }
    }
    
    private double getCpuUsage() {
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        return osBean.getProcessCpuLoad() * 100;
    }
    
    private long getMemoryUsage() {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        return memoryBean.getHeapMemoryUsage().getUsed();
    }
    
    private long getDiskUsage() {
        File root = new File("/");
        return root.getTotalSpace() - root.getFreeSpace();
    }
    
    private String formatBytes(long bytes) {
        String[] units = {"B", "KB", "MB", "GB"};
        int unitIndex = 0;
        double size = bytes;
        
        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }
        
        return String.format("%.2f %s", size, units[unitIndex]);
    }
}

7. 资源条件注解

7.1 @ConditionalOnResource - 当资源存在时

当指定的资源文件存在时,条件才成立:

@Configuration
public class ResourceConditionConfig {
    
    // 当配置文件存在时,加载自定义配置
    @Bean
    @ConditionalOnResource(resources = "classpath:custom-config.properties")
    public CustomConfigurationService customConfigService() {
        return new CustomConfigurationService();
    }
    
    // 当模板文件存在时,启用模板服务
    @Bean
    @ConditionalOnResource(resources = "classpath:templates/email-template.html")
    public EmailTemplateService emailTemplateService() {
        return new EmailTemplateService();
    }
    
    // 检查多个资源文件
    @Bean
    @ConditionalOnResource(resources = {
        "classpath:static/css/app.css",
        "classpath:static/js/app.js",
        "classpath:static/images/logo.png"
    })
    public StaticResourceService staticResourceService() {
        return new StaticResourceService();
    }
    
    // 根据外部配置文件决定加载组件
    @Bean
    @ConditionalOnResource(resources = "file:./config/external-config.xml")
    public ExternalConfigProcessor externalConfigProcessor() {
        return new ExternalConfigProcessor();
    }
}

// 自定义配置服务
@Component
public class CustomConfigurationService {
    
    private Properties customProperties;
    
    @PostConstruct
    public void loadCustomConfig() {
        try {
            customProperties = new Properties();
            InputStream inputStream = getClass().getClassLoader()
                .getResourceAsStream("custom-config.properties");
            
            if (inputStream != null) {
                customProperties.load(inputStream);
                System.out.println("自定义配置已加载:");
                customProperties.forEach((key, value) -> 
                    System.out.println("  " + key + " = " + value));
            }
        } catch (IOException e) {
            System.err.println("加载自定义配置失败: " + e.getMessage());
        }
    }
    
    public String getProperty(String key) {
        return customProperties.getProperty(key);
    }
    
    public String getProperty(String key, String defaultValue) {
        return customProperties.getProperty(key, defaultValue);
    }
    
    public Set<String> getAllKeys() {
        return customProperties.stringPropertyNames();
    }
}

// 邮件模板服务
@Component
public class EmailTemplateService {
    
    private String emailTemplate;
    
    @PostConstruct
    public void loadTemplate() {
        try {
            Resource resource = new ClassPathResource("templates/email-template.html");
            emailTemplate = Files.readString(Paths.get(resource.getURI()));
            System.out.println("邮件模板已加载,长度: " + emailTemplate.length());
        } catch (Exception e) {
            System.err.println("加载邮件模板失败: " + e.getMessage());
        }
    }
    
    public String generateEmail(String recipientName, String content) {
        return emailTemplate
            .replace("{{recipientName}}", recipientName)
            .replace("{{content}}", content)
            .replace("{{timestamp}}", LocalDateTime.now().toString());
    }
    
    public void sendEmail(String to, String subject, String recipientName, String content) {
        String emailBody = generateEmail(recipientName, content);
        System.out.println("发送邮件到: " + to);
        System.out.println("主题: " + subject);
        System.out.println("内容: " + emailBody);
        // 实际的邮件发送逻辑...
    }
}

// 静态资源服务
@Component
public class StaticResourceService {
    
    private final List<String> availableResources = new ArrayList<>();
    
    @PostConstruct
    public void scanResources() {
        String[] resourcePaths = {
            "static/css/app.css",
            "static/js/app.js", 
            "static/images/logo.png"
        };
        
        for (String path : resourcePaths) {
            Resource resource = new ClassPathResource(path);
            if (resource.exists()) {
                availableResources.add(path);
                System.out.println("静态资源已发现: " + path);
            }
        }
        
        System.out.println("总共发现 " + availableResources.size() + " 个静态资源");
    }
    
    public List<String> getAvailableResources() {
        return new ArrayList<>(availableResources);
    }
    
    public boolean isResourceAvailable(String resourcePath) {
        return availableResources.contains(resourcePath);
    }
}

7.2 多种资源类型的条件判断

@Configuration
public class AdvancedResourceConfig {
    
    // 数据库初始化脚本
    @Bean
    @ConditionalOnResource(resources = "classpath:db/migration/*.sql")
    public DatabaseMigrationService migrationService() {
        return new DatabaseMigrationService();
    }
    
    // 国际化资源文件
    @Bean
    @ConditionalOnResource(resources = {
        "classpath:messages_zh_CN.properties",
        "classpath:messages_en_US.properties"
    })
    public InternationalizationService i18nService() {
        return new InternationalizationService();
    }
    
    // SSL证书文件
    @Bean
    @ConditionalOnResource(resources = "classpath:ssl/keystore.jks")
    public SSLConfigurationService sslService() {
        return new SSLConfigurationService();
    }
    
    // API文档资源
    @Bean
    @ConditionalOnResource(resources = "classpath:static/swagger-ui/index.html")
    public SwaggerUIService swaggerUIService() {
        return new SwaggerUIService();
    }
}

// 数据库迁移服务
@Component
public class DatabaseMigrationService {
    
    @Autowired
    private DataSource dataSource;
    
    @PostConstruct
    public void runMigrations() {
        try {
            ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:db/migration/*.sql");
            
            System.out.println("发现 " + resources.length + " 个数据库迁移脚本");
            
            for (Resource resource : resources) {
                String filename = resource.getFilename();
                if (filename != null && filename.endsWith(".sql")) {
                    String sql = Files.readString(Paths.get(resource.getURI()));
                    executeMigrationScript(filename, sql);
                }
            }
        } catch (Exception e) {
            System.err.println("数据库迁移失败: " + e.getMessage());
        }
    }
    
    private void executeMigrationScript(String filename, String sql) {
        try (Connection connection = dataSource.getConnection();
             Statement statement = connection.createStatement()) {
            
            System.out.println("执行迁移脚本: " + filename);
            statement.executeUpdate(sql);
            System.out.println("迁移脚本执行成功: " + filename);
            
        } catch (SQLException e) {
            System.err.println("执行迁移脚本失败 [" + filename + "]: " + e.getMessage());
        }
    }
}

// 国际化服务
@Component
public class InternationalizationService {
    
    private final Map<Locale, Properties> messages = new HashMap<>();
    
    @PostConstruct
    public void loadMessages() {
        loadMessageBundle(Locale.SIMPLIFIED_CHINESE, "messages_zh_CN.properties");
        loadMessageBundle(Locale.US, "messages_en_US.properties");
    }
    
    private void loadMessageBundle(Locale locale, String filename) {
        try {
            Properties props = new Properties();
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filename);
            
            if (inputStream != null) {
                props.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                messages.put(locale, props);
                System.out.println("已加载国际化资源: " + filename + " (" + props.size() + " 条消息)");
            }
        } catch (IOException e) {
            System.err.println("加载国际化资源失败 [" + filename + "]: " + e.getMessage());
        }
    }
    
    public String getMessage(String key, Locale locale) {
        Properties props = messages.get(locale);
        if (props != null) {
            return props.getProperty(key);
        }
        
        // 降级到默认语言
        props = messages.get(Locale.US);
        return props != null ? props.getProperty(key, key) : key;
    }
    
    public String getMessage(String key, Locale locale, Object... args) {
        String message = getMessage(key, locale);
        return MessageFormat.format(message, args);
    }
}

8. 表达式条件注解

8.1 @ConditionalOnExpression - SpEL表达式条件

使用Spring表达式语言(SpEL)进行复杂的条件判断:

@Configuration
public class ExpressionConditionConfig {
    
    // 简单的属性表达式
    @Bean
    @ConditionalOnExpression("${app.feature.advanced:false}")
    public AdvancedFeatureService advancedFeatureService() {
        return new AdvancedFeatureService();
    }
    
    // 多个条件的组合
    @Bean
    @ConditionalOnExpression("${app.cache.enabled:true} and '${app.cache.type:redis}'.equals('redis')")
    public RedisCacheService redisCacheService() {
        return new RedisCacheService();
    }
    
    // 数值比较
    @Bean
    @ConditionalOnExpression("${server.port:8080} != 8080")
    public CustomPortService customPortService() {
        return new CustomPortService();
    }
    
    // 复杂的逻辑表达式
    @Bean
    @ConditionalOnExpression(
        "${app.environment.name:dev}.matches('prod|staging') and " +
        "${app.features.monitoring:false} and " + 
        "${app.features.alerting:false}"
    )
    public ProductionMonitoringService productionMonitoringService() {
        return new ProductionMonitoringService();
    }
    
    // 基于JVM参数的条件
    @Bean
    @ConditionalOnExpression("#{systemProperties['java.version'].startsWith('11') or systemProperties['java.version'].startsWith('17')}")
    public ModernJavaFeatureService modernJavaFeatureService() {
        return new ModernJavaFeatureService();
    }
    
    // 基于环境变量的条件
    @Bean
    @ConditionalOnExpression("#{environment.getProperty('PATH') != null}")
    public SystemEnvironmentService systemEnvironmentService() {
        return new SystemEnvironmentService();
    }
    
    // 时间相关的条件
    @Bean
    @ConditionalOnExpression("#{T(java.time.LocalTime).now().getHour() >= 9 and T(java.time.LocalTime).now().getHour() <= 17}")
    public BusinessHoursService businessHoursService() {
        return new BusinessHoursService();
    }
}

// 高级功能服务
@Component
public class AdvancedFeatureService {
    
    @Value("${app.feature.ai.enabled:false}")
    private boolean aiEnabled;
    
    @Value("${app.feature.ml.enabled:false}")
    private boolean mlEnabled;
    
    @Value("${app.feature.analytics.enabled:false}")
    private boolean analyticsEnabled;
    
    @PostConstruct
    public void init() {
        System.out.println("高级功能服务已启动");
        System.out.println("AI功能: " + (aiEnabled ? "启用" : "禁用"));
        System.out.println("机器学习: " + (mlEnabled ? "启用" : "禁用"));
        System.out.println("数据分析: " + (analyticsEnabled ? "启用" : "禁用"));
    }
    
    public Map<String, Boolean> getFeatureStatus() {
        Map<String, Boolean> status = new HashMap<>();
        status.put("ai", aiEnabled);
        status.put("ml", mlEnabled);
        status.put("analytics", analyticsEnabled);
        return status;
    }
    
    public void processAdvancedRequest(String requestType, Object data) {
        switch (requestType.toLowerCase()) {
            case "ai":
                if (aiEnabled) {
                    processAIRequest(data);
                } else {
                    throw new UnsupportedOperationException("AI功能未启用");
                }
                break;
            case "ml":
                if (mlEnabled) {
                    processMLRequest(data);
                } else {
                    throw new UnsupportedOperationException("机器学习功能未启用");
                }
                break;
            case "analytics":
                if (analyticsEnabled) {
                    processAnalyticsRequest(data);
                } else {
                    throw new UnsupportedOperationException("数据分析功能未启用");
                }
                break;
            default:
                throw new IllegalArgumentException("不支持的请求类型: " + requestType);
        }
    }
    
    private void processAIRequest(Object data) {
        System.out.println("处理AI请求: " + data);
        // AI处理逻辑...
    }
    
    private void processMLRequest(Object data) {
        System.out.println("处理机器学习请求: " + data);
        // 机器学习处理逻辑...
    }
    
    private void processAnalyticsRequest(Object data) {
        System.out.println("处理数据分析请求: " + data);
        // 数据分析处理逻辑...
    }
}

// 生产环境监控服务
@Component
public class ProductionMonitoringService {
    
    @Value("${app.monitoring.alert.threshold.cpu:80}")
    private double cpuThreshold;
    
    @Value("${app.monitoring.alert.threshold.memory:85}")
    private double memoryThreshold;
    
    @Value("${app.monitoring.alert.threshold.disk:90}")
    private double diskThreshold;
    
    @Autowired
    private NotificationService notificationService;
    
    @PostConstruct
    public void init() {
        System.out.println("生产环境监控服务已启动");
        System.out.println("CPU告警阈值: " + cpuThreshold + "%");
        System.out.println("内存告警阈值: " + memoryThreshold + "%");
        System.out.println("磁盘告警阈值: " + diskThreshold + "%");
    }
    
    @Scheduled(fixedRate = 30000) // 每30秒检查一次
    public void monitorSystemHealth() {
        SystemHealthMetrics metrics = collectSystemMetrics();
        
        checkAndAlert("CPU", metrics.getCpuUsage(), cpuThreshold);
        checkAndAlert("内存", metrics.getMemoryUsage(), memoryThreshold);
        checkAndAlert("磁盘", metrics.getDiskUsage(), diskThreshold);
    }
    
    private void checkAndAlert(String metricName, double actualValue, double threshold) {
        if (actualValue > threshold) {
            String alertMessage = String.format(
                "⚠️ %s使用率告警: %.2f%% (阈值: %.2f%%)", 
                metricName, actualValue, threshold
            );
            
            System.out.println(alertMessage);
            notificationService.sendAlert(alertMessage);
        }
    }
    
    private SystemHealthMetrics collectSystemMetrics() {
        // 收集系统指标的实现...
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        
        double cpuUsage = osBean.getProcessCpuLoad() * 100;
        double memoryUsage = (double) memoryBean.getHeapMemoryUsage().getUsed() / 
                            memoryBean.getHeapMemoryUsage().getMax() * 100;
        
        File disk = new File("/");
        double diskUsage = (double)(disk.getTotalSpace() - disk.getFreeSpace()) / 
                          disk.getTotalSpace() * 100;
        
        return new SystemHealthMetrics(cpuUsage, memoryUsage, diskUsage);
    }
}

// 系统健康指标类
public class SystemHealthMetrics {
    private final double cpuUsage;
    private final double memoryUsage;
    private final double diskUsage;
    
    public SystemHealthMetrics(double cpuUsage, double memoryUsage, double diskUsage) {
        this.cpuUsage = cpuUsage;
        this.memoryUsage = memoryUsage;
        this.diskUsage = diskUsage;
    }
    
    // getter方法...
    public double getCpuUsage() { return cpuUsage; }
    public double getMemoryUsage() { return memoryUsage; }
    public double getDiskUsage() { return diskUsage; }
}

8.2 复杂的SpEL表达式示例

@Configuration
public class ComplexExpressionConfig {
    
    // 基于多个配置属性的复杂判断
    @Bean
    @ConditionalOnExpression(
        "#{environment.getProperty('spring.profiles.active', 'dev').contains('prod') " +
        "and T(java.lang.Boolean).parseBoolean(environment.getProperty('app.security.strict', 'false')) " +
        "and environment.getProperty('app.version', '1.0').matches('\\d+\\.\\d+')}"
    )
    public StrictSecurityService strictSecurityService() {
        return new StrictSecurityService();
    }
    
    // 基于系统资源的条件
    @Bean
    @ConditionalOnExpression(
        "#{T(java.lang.Runtime).getRuntime().availableProcessors() >= 4 " +
        "and T(java.lang.Runtime).getRuntime().maxMemory() >= 2L * 1024 * 1024 * 1024}"
    )
    public HighPerformanceService highPerformanceService() {
        return new HighPerformanceService();
    }
    
    // 基于外部服务可用性的条件
    @Bean
    @ConditionalOnExpression(
        "#{@networkService.isServiceAvailable('https://api.example.com/health') " +
        "and @networkService.isServiceAvailable('https://cache.example.com/ping')}"
    )
    public ExternalIntegrationService externalIntegrationService() {
        return new ExternalIntegrationService();
    }
    
    // 基于业务规则的条件
    @Bean
    @ConditionalOnExpression(
        "#{T(java.time.LocalDate).now().getDayOfWeek().getValue() <= 5 " +  // 工作日
        "and T(java.time.LocalTime).now().isAfter(T(java.time.LocalTime).of(8, 0)) " +  // 8点之后
        "and T(java.time.LocalTime).now().isBefore(T(java.time.LocalTime).of(18, 0))}"  // 18点之前
    )
    public BusinessHoursOnlyService businessHoursOnlyService() {
        return new BusinessHoursOnlyService();
    }
}

// 网络服务(用于检查外部服务可用性)
@Component("networkService")
public class NetworkService {
    
    private final RestTemplate restTemplate;
    
    public NetworkService() {
        this.restTemplate = new RestTemplate();
    }
    
    @PostConstruct
    public void init() {
        System.out.println("外部API服务已启动,API密钥已配置");
    }
    
    public boolean isServiceAvailable(String url) {
        try {
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            return response.getStatusCode().is2xxSuccessful();
        } catch (Exception e) {
            System.out.println("服务不可用: " + url + " - " + e.getMessage());
            return false;
        }
    }
    
    public boolean isPortOpen(String host, int port) {
        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress(host, port), 3000);
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}

// 严格安全服务
@Component
public class StrictSecurityService {
    
    @PostConstruct
    public void init() {
        System.out.println("严格安全模式已启用");
        enableStrictPolicies();
    }
    
    private void enableStrictPolicies() {
        // 启用严格的安全策略
        System.out.println("- 启用强密码策略");
        System.out.println("- 启用两因素认证");
        System.out.println("- 启用访问日志记录");
        System.out.println("- 启用异常行为检测");
    }
    
    public boolean validateAccess(String userId, String resource, String action) {
        // 严格的访问控制逻辑
        System.out.println("严格验证访问权限: " + userId + " -> " + resource + " (" + action + ")");
        return true;
    }
}

// 高性能服务
@Component
public class HighPerformanceService {
    
    private final int availableProcessors;
    private final long maxMemory;
    private final ExecutorService executorService;
    
    public HighPerformanceService() {
        this.availableProcessors = Runtime.getRuntime().availableProcessors();
        this.maxMemory = Runtime.getRuntime().maxMemory();
        
        // 根据系统资源创建线程池
        this.executorService = Executors.newFixedThreadPool(availableProcessors * 2);
        
        System.out.println("高性能服务已启动:");
        System.out.println("- 可用处理器: " + availableProcessors);
        System.out.println("- 最大内存: " + formatBytes(maxMemory));
        System.out.println("- 线程池大小: " + (availableProcessors * 2));
    }
    
    public CompletableFuture<String> processAsync(String data) {
        return CompletableFuture.supplyAsync(() -> {
            // 模拟高性能处理
            try {
                Thread.sleep(100); // 模拟处理时间
                return "高性能处理结果: " + data.toUpperCase();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        }, executorService);
    }
    
    private String formatBytes(long bytes) {
        return String.format("%.2f GB", bytes / (1024.0 * 1024.0 * 1024.0));
    }
    
    @PreDestroy
    public void shutdown() {
        executorService.shutdown();
    }
}

9. Web环境条件注解

9.1 @ConditionalOnWebApplication - Web应用条件

根据应用类型决定是否创建Bean:

@Configuration
public class WebApplicationConfig {
    
    // 只在Web环境中创建
    @Bean
    @ConditionalOnWebApplication
    public WebSecurityConfig webSecurityConfig() {
        return new WebSecurityConfig();
    }
    
    // 只在Servlet Web环境中创建
    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    public ServletWebServerFactoryCustomizer servletCustomizer() {
        return new ServletWebServerFactoryCustomizer();
    }
    
    // 只在响应式Web环境中创建
    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
    public ReactiveWebServerFactoryCustomizer reactiveCustomizer() {
        return new ReactiveWebServerFactoryCustomizer();
    }
    
    // 任何类型的Web环境
    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.ANY)
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOriginPatterns(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

// Web安全配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/public/**", "/api/health", "/actuator/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
                .permitAll()
            )
            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            )
            .csrf(csrf -> csrf.disable());
        
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder().encode("password"))
            .roles("USER")
            .build();
        
        UserDetails admin = User.builder()
            .username("admin")
            .password(passwordEncoder().encode("admin"))
            .roles("USER", "ADMIN")
            .build();
        
        return new InMemoryUserDetailsManager(user, admin);
    }
}

// Servlet定制器
@Component
public class ServletWebServerFactoryCustomizer 
    implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    
    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        System.out.println("定制Servlet Web服务器");
        
        // 设置端口
        factory.setPort(8080);
        
        // 设置上下文路径
        factory.setContextPath("/api");
        
        // 设置会话超时
        factory.getSession().setTimeout(Duration.ofMinutes(30));
        
        // 添加错误页面
        ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
        ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
        factory.addErrorPages(error404Page, error500Page);
        
        // 设置SSL(如果需要)
        // Ssl ssl = new Ssl();
        // ssl.setKeyStore("classpath:keystore.jks");
        // ssl.setKeyStorePassword("password");
        // factory.setSsl(ssl);
        
        System.out.println("Servlet Web服务器配置完成");
    }
}

// 响应式定制器
@Component
public class ReactiveWebServerFactoryCustomizer 
    implements WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> {
    
    @Override
    public void customize(ConfigurableReactiveWebServerFactory factory) {
        System.out.println("定制响应式Web服务器");
        
        // 设置端口
        factory.setPort(8081);
        
        // 其他响应式特定的配置...
        System.out.println("响应式Web服务器配置完成");
    }
}

9.2 @ConditionalOnNotWebApplication - 非Web应用条件

@Configuration
public class NonWebApplicationConfig {
    
    // 只在非Web环境中创建(如命令行应用)
    @Bean
    @ConditionalOnNotWebApplication
    public CommandLineProcessor commandLineProcessor() {
        return new CommandLineProcessor();
    }
    
    // 批处理任务调度器(非Web环境)
    @Bean
    @ConditionalOnNotWebApplication
    public TaskScheduler batchTaskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10);
        scheduler.setThreadNamePrefix("batch-task-");
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        scheduler.setAwaitTerminationSeconds(30);
        return scheduler;
    }
    
    // 文件监控服务(非Web环境)
    @Bean
    @ConditionalOnNotWebApplication
    public FileMonitorService fileMonitorService() {
        return new FileMonitorService();
    }
}

// 命令行处理器
@Component
public class CommandLineProcessor implements CommandLineRunner {
    
    @Value("${app.input.directory:./input}")
    private String inputDirectory;
    
    @Value("${app.output.directory:./output}")
    private String outputDirectory;
    
    @Override
    public void run(String... args) throws Exception {
        System.out.println("命令行应用启动");
        System.out.println("输入目录: " + inputDirectory);
        System.out.println("输出目录: " + outputDirectory);
        
        // 处理命令行参数
        if (args.length > 0) {
            System.out.println("命令行参数:");
            for (int i = 0; i < args.length; i++) {
                System.out.println("  参数" + (i + 1) + ": " + args[i]);
            }
            
            processCommand(args);
        } else {
            System.out.println("没有提供命令行参数,启动交互模式");
            startInteractiveMode();
        }
    }
    
    private void processCommand(String[] args) {
        String command = args[0].toLowerCase();
        
        switch (command) {
            case "process":
                if (args.length > 1) {
                    processFile(args[1]);
                } else {
                    System.out.println("请指定要处理的文件");
                }
                break;
            case "batch":
                processBatch();
                break;
            case "status":
                showStatus();
                break;
            default:
                System.out.println("未知命令: " + command);
                showHelp();
        }
    }
    
    private void startInteractiveMode() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("交互模式已启动。输入 'help' 查看可用命令,输入 'exit' 退出。");
        
        while (true) {
            System.out.print("> ");
            String input = scanner.nextLine().trim();
            
            if ("exit".equalsIgnoreCase(input)) {
                System.out.println("再见!");
                break;
            }
            
            if ("help".equalsIgnoreCase(input)) {
                showHelp();
                continue;
            }
            
            processCommand(input.split("\\s+"));
        }
    }
    
    private void processFile(String filename) {
        System.out.println("处理文件: " + filename);
        // 文件处理逻辑...
    }
    
    private void processBatch() {
        System.out.println("开始批处理...");
        // 批处理逻辑...
    }
    
    private void showStatus() {
        System.out.println("应用状态: 运行中");
        System.out.println("内存使用: " + getMemoryUsage());
        System.out.println("处理的文件数: " + getProcessedFileCount());
    }
    
    private void showHelp() {
        System.out.println("可用命令:");
        System.out.println("  process <filename> - 处理指定文件");
        System.out.println("  batch - 批处理所有文件");
        System.out.println("  status - 显示应用状态");
        System.out.println("  help - 显示此帮助信息");
        System.out.println("  exit - 退出应用");
    }
    
    private String getMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        long used = runtime.totalMemory() - runtime.freeMemory();
        long max = runtime.maxMemory();
        return String.format("%.2f%% (%s / %s)", 
            (double) used / max * 100,
            formatBytes(used),
            formatBytes(max));
    }
    
    private long getProcessedFileCount() {
        // 返回已处理的文件数量
        return 0; // 示例值
    }
    
    private String formatBytes(long bytes) {
        String[] units = {"B", "KB", "MB", "GB"};
        int unitIndex = 0;
        double size = bytes;
        
        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }
        
        return String.format("%.2f %s", size, units[unitIndex]);
    }
}

// 文件监控服务
@Component
public class FileMonitorService {
    
    @Value("${app.monitor.directory:./watch}")
    private String monitorDirectory;
    
    private WatchService watchService;
    private boolean monitoring = false;
    
    @PostConstruct
    public void startMonitoring() {
        try {
            Path path = Paths.get(monitorDirectory);
            Files.createDirectories(path);
            
            watchService = FileSystems.getDefault().newWatchService();
            path.register(watchService, 
                StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_MODIFY,
                StandardWatchEventKinds.ENTRY_DELETE);
            
            monitoring = true;
            
            // 在后台线程中监控文件变化
            CompletableFuture.runAsync(this::monitorFiles);
            
            System.out.println("文件监控服务已启动,监控目录: " + monitorDirectory);
        } catch (IOException e) {
            System.err.println("启动文件监控失败: " + e.getMessage());
        }
    }
    
    private void monitorFiles() {
        while (monitoring) {
            try {
                WatchKey key = watchService.take();
                
                for (WatchEvent<?> event : key.pollEvents()) {
                    WatchEvent.Kind<?> kind = event.kind();
                    Path filename = (Path) event.context();
                    
                    System.out.println("文件事件: " + kind + " - " + filename);
                    
                    if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                        handleFileCreated(filename);
                    } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
                        handleFileModified(filename);
                    } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
                        handleFileDeleted(filename);
                    }
                }
                
                key.reset();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    
    private void handleFileCreated(Path filename) {
        System.out.println("新文件创建: " + filename);
        // 处理新文件创建的逻辑...
    }
    
    private void handleFileModified(Path filename) {
        System.out.println("文件修改: " + filename);
        // 处理文件修改的逻辑...
    }
    
    private void handleFileDeleted(Path filename) {
        System.out.println("文件删除: " + filename);
        // 处理文件删除的逻辑...
    }
    
    @PreDestroy
    public void stopMonitoring() {
        monitoring = false;
        try {
            if (watchService != null) {
                watchService.close();
            }
        } catch (IOException e) {
            System.err.println("关闭文件监控失败: " + e.getMessage());
        }
    }
}

10. 自定义条件注解

10.1 创建自定义条件类

实现Condition接口创建自定义条件逻辑:

// 操作系统条件
public class OperatingSystemCondition implements Condition {
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 获取注解属性
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnOS.class.getName());
        if (attributes == null) {
            return false;
        }
        
        OS[] targetOS = (OS[]) attributes.get("value");
        String osName = context.getEnvironment().getProperty("os.name", "").toLowerCase();
        
        for (OS os : targetOS) {
            switch (os) {
                case WINDOWS:
                    if (osName.contains("windows")) return true;
                    break;
                case LINUX:
                    if (osName.contains("linux")) return true;
                    break;
                case MAC:
                    if (osName.contains("mac") || osName.contains("darwin")) return true;
                    break;
                case UNIX:
                    if (osName.contains("unix") || osName.contains("linux") || 
                        osName.contains("mac") || osName.contains("darwin")) return true;
                    break;
            }
        }
        
        return false;
    }
}

// 操作系统枚举
public enum OS {
    WINDOWS, LINUX, MAC, UNIX
}

// 自定义操作系统条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OperatingSystemCondition.class)
public @interface ConditionalOnOS {
    OS[] value();
}

// 使用自定义条件注解
@Configuration
public class OSSpecificConfig {
    
    @Bean
    @ConditionalOnOS({OS.WINDOWS})
    public FileSystemService windowsFileSystemService() {
        return new WindowsFileSystemService();
    }
    
    @Bean
    @ConditionalOnOS({OS.LINUX, OS.MAC})
    public FileSystemService unixFileSystemService() {
        return new UnixFileSystemService();
    }
    
    @Bean
    @ConditionalOnOS({OS.MAC})
    public NotificationService macNotificationService() {
        return new MacNotificationService();
    }
}

// Windows文件系统服务
@Component
public class WindowsFileSystemService implements FileSystemService {
    
    @PostConstruct
    public void init() {
        System.out.println("Windows文件系统服务已启动");
        System.out.println("- 支持NTFS文件系统");
        System.out.println("- 支持Windows路径分隔符");
        System.out.println("- 支持Windows文件属性");
    }
    
    @Override
    public String getPathSeparator() {
        return "\\";
    }
    
    @Override
    public boolean createDirectory(String path) {
        // Windows特定的目录创建逻辑
        System.out.println("使用Windows API创建目录: " + path);
        return new File(path).mkdirs();
    }
    
    @Override
    public List<String> listFiles(String directory) {
        File dir = new File(directory);
        if (dir.exists() && dir.isDirectory()) {
            String[] files = dir.list();
            return files != null ? Arrays.asList(files) : new ArrayList<>();
        }
        return new ArrayList<>();
    }
    
    @Override
    public long getFileSize(String filePath) {
        return new File(filePath).length();
    }
    
    public void setFileAttributes(String filePath, boolean hidden, boolean readOnly) {
        File file = new File(filePath);
        if (file.exists()) {
            // Windows特定的文件属性设置
            if (hidden) {
                System.out.println("设置文件为隐藏: " + filePath);
                // 实际实现需要调用Windows API
            }
            if (readOnly) {
                file.setReadOnly();
                System.out.println("设置文件为只读: " + filePath);
            }
        }
    }
}

// Unix文件系统服务
@Component
public class UnixFileSystemService implements FileSystemService {
    
    @PostConstruct
    public void init() {
        System.out.println("Unix文件系统服务已启动");
        System.out.println("- 支持ext4/HFS+等文件系统");
        System.out.println("- 支持Unix路径分隔符");
        System.out.println("- 支持Unix文件权限");
    }
    
    @Override
    public String getPathSeparator() {
        return "/";
    }
    
    @Override
    public boolean createDirectory(String path) {
        // Unix特定的目录创建逻辑
        System.out.println("使用Unix系统调用创建目录: " + path);
        return new File(path).mkdirs();
    }
    
    @Override
    public List<String> listFiles(String directory) {
        File dir = new File(directory);
        if (dir.exists() && dir.isDirectory()) {
            String[] files = dir.list();
            return files != null ? Arrays.asList(files) : new ArrayList<>();
        }
        return new ArrayList<>();
    }
    
    @Override
    public long getFileSize(String filePath) {
        return new File(filePath).length();
    }
    
    public void setFilePermissions(String filePath, String permissions) {
        // Unix特定的权限设置
        System.out.println("设置文件权限: " + filePath + " -> " + permissions);
        // 实际实现需要调用chmod命令或系统API
        try {
            ProcessBuilder pb = new ProcessBuilder("chmod", permissions, filePath);
            Process process = pb.start();
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("权限设置成功");
            } else {
                System.out.println("权限设置失败");
            }
        } catch (Exception e) {
            System.err.println("设置权限失败: " + e.getMessage());
        }
    }
}

10.2 复杂的自定义条件

// 时间范围条件
public class TimeRangeCondition implements Condition {
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnTimeRange.class.getName());
        if (attributes == null) {
            return false;
        }
        
        String startTime = (String) attributes.get("startTime");
        String endTime = (String) attributes.get("endTime");
        String timezone = (String) attributes.get("timezone");
        
        try {
            ZoneId zoneId = ZoneId.of(timezone);
            LocalTime start = LocalTime.parse(startTime);
            LocalTime end = LocalTime.parse(endTime);
            LocalTime now = LocalTime.now(zoneId);
            
            if (start.isBefore(end)) {
                // 同一天内的时间范围
                return now.isAfter(start) && now.isBefore(end);
            } else {
                // 跨午夜的时间范围
                return now.isAfter(start) || now.isBefore(end);
            }
        } catch (Exception e) {
            System.err.println("时间范围条件解析失败: " + e.getMessage());
            return false;
        }
    }
}

// 时间范围条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(TimeRangeCondition.class)
public @interface ConditionalOnTimeRange {
    String startTime();
    String endTime();
    String timezone() default "UTC";
}

// 环境变量条件
public class EnvironmentVariableCondition implements Condition {
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnEnvironmentVariable.class.getName());
        if (attributes == null) {
            return false;
        }
        
        String name = (String) attributes.get("name");
        String value = (String) attributes.get("value");
        boolean ignoreCase = (Boolean) attributes.get("ignoreCase");
        
        String envValue = System.getenv(name);
        
        if (value.isEmpty()) {
            // 只检查环境变量是否存在
            return envValue != null && !envValue.isEmpty();
        }
        
        if (envValue == null) {
            return false;
        }
        
        return ignoreCase ? envValue.equalsIgnoreCase(value) : envValue.equals(value);
    }
}

// 环境变量条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(EnvironmentVariableCondition.class)
public @interface ConditionalOnEnvironmentVariable {
    String name();
    String value() default "";
    boolean ignoreCase() default false;
}

// 使用复杂自定义条件
@Configuration
public class AdvancedConditionConfig {
    
    // 只在工作时间启用的服务
    @Bean
    @ConditionalOnTimeRange(startTime = "09:00", endTime = "17:00", timezone = "Asia/Shanghai")
    public BusinessHoursService businessHoursService() {
        return new BusinessHoursService();
    }
    
    // 只在夜间启用的批处理服务
    @Bean
    @ConditionalOnTimeRange(startTime = "23:00", endTime = "06:00", timezone = "Asia/Shanghai")
    public NightBatchService nightBatchService() {
        return new NightBatchService();
    }
    
    // 基于环境变量的服务
    @Bean
    @ConditionalOnEnvironmentVariable(name = "DEPLOYMENT_ENV", value = "production", ignoreCase = true)
    public ProductionLoggingService productionLoggingService() {
        return new ProductionLoggingService();
    }
    
    // 检查环境变量是否存在
    @Bean
    @ConditionalOnEnvironmentVariable(name = "API_KEY")
    public ExternalApiService externalApiService() {
        return new ExternalApiService();
    }
}

// 业务时间服务
@Component
public class BusinessHoursService {
    
    @PostConstruct
    public void init() {
        System.out.println("业务时间服务已启动 (工作时间: 09:00-17:00)");
    }
    
    @Scheduled(fixedRate = 60000) // 每分钟检查一次
    public void checkBusinessHours() {
        LocalTime now = LocalTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println("当前时间: " + now + " - 业务时间内");
        
        // 业务时间内的定期任务
        processBusinessRequests();
    }
    
    private void processBusinessRequests() {
        System.out.println("处理业务请求...");
        // 业务请求处理逻辑
    }
}

// 夜间批处理服务
@Component
public class NightBatchService {
    
    @PostConstruct
    public void init() {
        System.out.println("夜间批处理服务已启动 (处理时间: 23:00-06:00)");
    }
    
    @Scheduled(cron = "0 0 23 * * ?") // 每天23点开始
    public void startNightBatch() {
        System.out.println("开始夜间批处理任务");
        
        try {
            // 数据备份
            performDataBackup();
            
            // 数据清理
            performDataCleanup();
            
            // 报表生成
            generateDailyReports();
            
            // 系统维护
            performSystemMaintenance();
            
            System.out.println("夜间批处理任务完成");
        } catch (Exception e) {
            System.err.println("夜间批处理任务失败: " + e.getMessage());
        }
    }
    
    private void performDataBackup() {
        System.out.println("执行数据备份...");
        // 数据备份逻辑
    }
    
    private void performDataCleanup() {
        System.out.println("执行数据清理...");
        // 数据清理逻辑
    }
    
    private void generateDailyReports() {
        System.out.println("生成日报表...");
        // 报表生成逻辑
    }
    
    private void performSystemMaintenance() {
        System.out.println("执行系统维护...");
        // 系统维护逻辑
    }
}

// 外部API服务
@Component
public class ExternalApiService {
    
    @Value("${API_KEY:}")
    private String apiKey;
    
    private final RestTemplate restTemplate;
    
    public ExternalApiService() {
        this.restTemplate = new RestTemplate();
    }
    
    @PostConstruct
    public void init() {
        if (apiKey.isEmpty()) {
            apiKey = System.getenv("API_KEY");
        }
        System.out.println("外部API服务已启动,API密钥已配置");
    }
    
    public Map<String, Object> callExternalApi(String endpoint, Map<String, Object> params) {
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setBearerAuth(apiKey);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(params, headers);
            
            ResponseEntity<Map> response = restTemplate.postForEntity(
                "https://api.example.com/" + endpoint, entity, Map.class);
            
            return response.getBody();
        } catch (Exception e) {
            System.err.println("调用外部API失败: " + e.getMessage());
            return Map.of("error", e.getMessage());
        }
    }
}

11. 条件注解组合使用

11.1 多条件组合

@Configuration
public class CombinedConditionsConfig {
    
    // 组合多个条件:类存在 + 属性配置 + Bean不存在
    @Bean
    @ConditionalOnClass(RedisTemplate.class)
    @ConditionalOnProperty(prefix = "spring.redis", name = "host")
    @ConditionalOnMissingBean(name = "customRedisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 设置序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.afterPropertiesSet();
        return template;
    }
    
    // 复杂的多条件组合
    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    @ConditionalOnClass(name = "org.springframework.security.web.SecurityFilterChain")
    @ConditionalOnProperty(name = "app.security.enabled", havingValue = "true", matchIfMissing = true)
    @ConditionalOnMissingBean(SecurityFilterChain.class)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/public/**", "/actuator/health").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(Customizer.withDefaults())
            .build();
    }
    
    // 基于环境和功能的组合条件
    @Bean
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "prod")
    @ConditionalOnProperty(prefix = "app.monitoring", name = "enabled", havingValue = "true")
    @ConditionalOnClass(name = "io.micrometer.core.instrument.MeterRegistry")
    @ConditionalOnBean(MeterRegistry.class)
    public ProductionMetricsService productionMetricsService(MeterRegistry meterRegistry) {
        return new ProductionMetricsService(meterRegistry);
    }
}

// 生产环境指标服务
@Component
public class ProductionMetricsService {
    
    private final MeterRegistry meterRegistry;
    private final Counter requestCounter;
    private final Timer responseTimer;
    private final Gauge systemLoadGauge;
    
    public ProductionMetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 初始化指标
        this.requestCounter = Counter.builder("http.requests.total")
            .description("Total HTTP requests")
            .register(meterRegistry);
        
        this.responseTimer = Timer.builder("http.response.time")
            .description("HTTP response time")
            .register(meterRegistry);
        
        this.systemLoadGauge = Gauge.builder("system.load.average")
            .description("System load average")
            .register(meterRegistry, this, ProductionMetricsService::getSystemLoad);
    }
    
    @PostConstruct
    public void init() {
        System.out.println("生产环境指标服务已启动");
        startMetricsCollection();
    }
    
    private void startMetricsCollection() {
        // 定期收集自定义指标
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(this::collectCustomMetrics, 0, 30, TimeUnit.SECONDS);
    }
    
    private void collectCustomMetrics() {
        // 应用特定的指标收集
        collectDatabaseMetrics();
        collectCacheMetrics();
        collectBusinessMetrics();
    }
    
    private void collectDatabaseMetrics() {
        // 数据库连接池指标
        Timer.Sample sample = Timer.start(meterRegistry);
        // 模拟数据库查询时间
        sample.stop(Timer.builder("database.query.time")
            .description("Database query execution time")
            .register(meterRegistry));
    }
    
    private void collectCacheMetrics() {
        // 缓存命中率指标
        meterRegistry.gauge("cache.hit.ratio", Math.random() * 100);
    }
    
    private void collectBusinessMetrics() {
        // 业务指标
        meterRegistry.gauge("active.users", getActiveUserCount());
        meterRegistry.gauge("pending.orders", getPendingOrderCount());
    }
    
    private double getSystemLoad() {
        return ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
    }
    
    private int getActiveUserCount() {
        // 模拟活跃用户数
        return (int) (Math.random() * 1000);
    }
    
    private int getPendingOrderCount() {
        // 模拟待处理订单数
        return (int) (Math.random() * 50);
    }
    
    public void recordRequest(String endpoint) {
        requestCounter.increment(Tags.of("endpoint", endpoint));
    }
    
    public Timer.Sample startTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void stopTimer(Timer.Sample sample, String endpoint) {
        sample.stop(responseTimer.tag("endpoint", endpoint));
    }
}

11.2 条件优先级和顺序

@Configuration
public class ConditionalPriorityConfig {
    
    // 第一优先级:特定环境的Redis配置
    @Bean("redisTemplate")
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "prod")
    @ConditionalOnProperty(prefix = "app.redis.cluster", name = "enabled", havingValue = "true")
    @ConditionalOnClass(RedisTemplate.class)
    public RedisTemplate<String, Object> clusterRedisTemplate() {
        System.out.println("创建集群Redis模板 (生产环境)");
        // 集群Redis配置
        return createClusterRedisTemplate();
    }
    
    // 第二优先级:单机Redis配置
    @Bean("redisTemplate")
    @ConditionalOnProperty(prefix = "spring.redis", name = "host")
    @ConditionalOnClass(RedisTemplate.class)
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> standaloneRedisTemplate() {
        System.out.println("创建单机Redis模板");
        // 单机Redis配置
        return createStandaloneRedisTemplate();
    }
    
    // 第三优先级:内存缓存(Redis不可用时的降级方案)
    @Bean
    @ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")
    @ConditionalOnMissingBean(CacheManager.class)
    public CacheManager fallbackCacheManager() {
        System.out.println("创建内存缓存管理器 (Redis不可用)");
        return new ConcurrentMapCacheManager("default", "users", "products");
    }
    
    private RedisTemplate<String, Object> createClusterRedisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        
        // 集群连接工厂配置
        JedisClusterConfiguration clusterConfig = new JedisClusterConfiguration();
        // 添加集群节点...
        
        JedisConnectionFactory factory = new JedisConnectionFactory(clusterConfig);
        template.setConnectionFactory(factory);
        
        configureRedisTemplate(template);
        return template;
    }
    
    private RedisTemplate<String, Object> createStandaloneRedisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        
        // 单机连接工厂配置
        JedisConnectionFactory factory = new JedisConnectionFactory();
        template.setConnectionFactory(factory);
        
        configureRedisTemplate(template);
        return template;
    }
    
    private void configureRedisTemplate(RedisTemplate<String, Object> template) {
        // 通用Redis模板配置
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
    }
}

12. 实际应用场景

12.1 多环境配置管理

// 开发环境配置
@Configuration
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
public class DevelopmentConfig {
    
    @Bean
    public DataSource devDataSource() {
        return DataSourceBuilder.create()
            .driverClassName("org.h2.Driver")
            .url("jdbc:h2:mem:devdb;DB_CLOSE_DELAY=-1")
            .username("sa")
            .password("")
            .build();
    }
    
    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder devPasswordEncoder() {
        // 开发环境使用简单的密码编码器
        return NoOpPasswordEncoder.getInstance();
    }
    
    @Bean
    public LoggingService devLoggingService() {
        return new ConsoleLoggingService();
    }
}

// 测试环境配置
@Configuration
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "test")
public class TestConfig {
    
    @Bean
    @Primary
    public UserService mockUserService() {
        return Mockito.mock(UserService.class);
    }
    
    @Bean
    @Primary
    public EmailService mockEmailService() {
        return new MockEmailService();
    }
    
    @Bean
    public TestDataInitializer testDataInitializer() {
        return new TestDataInitializer();
    }
}

// 生产环境配置
@Configuration
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "prod")
public class ProductionConfig {
    
    @Bean
    @ConditionalOnProperty(prefix = "spring.datasource", name = "url")
    public DataSource prodDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(environment.getProperty("spring.datasource.url"));
        config.setUsername(environment.getProperty("spring.datasource.username"));
        config.setPassword(environment.getProperty("spring.datasource.password"));
        
        // 生产环境连接池优化
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);
        
        return new HikariDataSource(config);
    }
    
    @Bean
    public PasswordEncoder prodPasswordEncoder() {
        return new BCryptPasswordEncoder(12); // 更强的加密强度
    }
    
    @Bean
    public LoggingService prodLoggingService() {
        return new DatabaseLoggingService();
    }
    
    @Bean
    @ConditionalOnProperty(prefix = "app.monitoring", name = "enabled", havingValue = "true")
    public HealthCheckService healthCheckService() {
        return new HealthCheckService();
    }
}

// 控制台日志服务(开发环境)
@Component
public class ConsoleLoggingService implements LoggingService {
    
    @Override
    public void log(LogLevel level, String message, Object... args) {
        String formattedMessage = MessageFormat.format(message, args);
        System.out.printf("[%s] %s: %s%n", 
            LocalDateTime.now(), level, formattedMessage);
    }
    
    @Override
    public void logError(String message, Throwable throwable) {
        System.err.printf("[%s] ERROR: %s%n", LocalDateTime.now(), message);
        throwable.printStackTrace();
    }
}

// 数据库日志服务(生产环境)
@Component
public class DatabaseLoggingService implements LoggingService {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public void log(LogLevel level, String message, Object... args) {
        String formattedMessage = MessageFormat.format(message, args);
        
        jdbcTemplate.update(
            "INSERT INTO application_logs (level, message, created_at) VALUES (?, ?, ?)",
            level.toString(), formattedMessage, Timestamp.valueOf(LocalDateTime.now())
        );
    }
    
    @Override
    public void logError(String message, Throwable throwable) {
        String stackTrace = Arrays.stream(throwable.getStackTrace())
            .map(StackTraceElement::toString)
            .collect(Collectors.joining("\n"));
        
        jdbcTemplate.update(
            "INSERT INTO error_logs (message, stack_trace, created_at) VALUES (?, ?, ?)",
            message, stackTrace, Timestamp.valueOf(LocalDateTime.now())
        );
    }
}

12.2 功能开关和A/B测试

@Configuration
public class FeatureToggleConfig {
    
    // 新功能开关
    @Bean
    @ConditionalOnProperty(name = "app.features.new-ui", havingValue = "true")
    public UIService newUIService() {
        return new NewUIService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "app.features.new-ui", havingValue = "false", matchIfMissing = true)
    public UIService legacyUIService() {
        return new LegacyUIService();
    }
    
    // A/B测试配置
    @Bean
    @ConditionalOnProperty(name = "app.ab-test.algorithm", havingValue = "v2")
    public RecommendationService experimentalRecommendationService() {
        return new ExperimentalRecommendationService();
    }
    
    @Bean
    @ConditionalOnProperty(name = "app.ab-test.algorithm", havingValue = "v1", matchIfMissing = true)
    public RecommendationService standardRecommendationService() {
        return new StandardRecommendationService();
    }
    
    // 渐进式功能发布
    @Bean
    @ConditionalOnExpression("#{environment.getProperty('app.features.beta-users', '').contains(authentication.name)}")
    public BetaFeatureService betaFeatureService() {
        return new BetaFeatureService();
    }
}

// 新UI服务
@Component
public class NewUIService implements UIService {
    
    @PostConstruct
    public void init() {
        System.out.println("新UI服务已启用 - 使用现代化界面");
    }
    
    @Override
    public String renderPage(String pageName, Map<String, Object> model) {
        return "<!DOCTYPE html><html>" +
               "<head><title>New UI - " + pageName + "</title>" +
               "<link rel='stylesheet' href='/css/modern-theme.css'></head>" +
               "<body class='modern-layout'>" +
               renderModernContent(pageName, model) +
               "</body></html>";
    }
    
    private String renderModernContent(String pageName, Map<String, Object> model) {
        StringBuilder content = new StringBuilder();
        content.append("<nav class='modern-nav'>").append(renderNavigation()).append("</nav>");
        content.append("<main class='modern-main'>").append(renderMainContent(pageName, model)).append("</main>");
        content.append("<footer class='modern-footer'>").append(renderFooter()).append("</footer>");
        return content.toString();
    }
    
    private String renderNavigation() {
        return "<ul><li><a href='/dashboard'>Dashboard</a></li>" +
               "<li><a href='/profile'>Profile</a></li>" +
               "<li><a href='/settings'>Settings</a></li></ul>";
    }
    
    private String renderMainContent(String pageName, Map<String, Object> model) {
        return "<h1>Welcome to " + pageName + "</h1>" +
               "<p>This is the new modern interface.</p>";
    }
    
    private String renderFooter() {
        return "<p>&copy; 2024 Modern App. All rights reserved.</p>";
    }
}

// 旧UI服务
@Component
public class LegacyUIService implements UIService {
    
    @PostConstruct
    public void init() {
        System.out.println("旧UI服务已启用 - 使用传统界面");
    }
    
    @Override
    public String renderPage(String pageName, Map<String, Object> model) {
        return "<html>" +
               "<head><title>Legacy UI - " + pageName + "</title>" +
               "<link rel='stylesheet' href='/css/legacy-theme.css'></head>" +
               "<body>" +
               renderLegacyContent(pageName, model) +
               "</body></html>";
    }
    
    private String renderLegacyContent(String pageName, Map<String, Object> model) {
        return "<table width='100%'>" +
               "<tr><td>" + renderLegacyNavigation() + "</td></tr>" +
               "<tr><td>" + renderLegacyMainContent(pageName, model) + "</td></tr>" +
               "<tr><td>" + renderLegacyFooter() + "</td></tr>" +
               "</table>";
    }
    
    private String renderLegacyNavigation() {
        return "<table><tr>" +
               "<td><a href='/dashboard'>Dashboard</a></td>" +
               "<td><a href='/profile'>Profile</a></td>" +
               "<td><a href='/settings'>Settings</a></td>" +
               "</tr></table>";
    }
    
    private String renderLegacyMainContent(String pageName, Map<String, Object> model) {
        return "<h2>Welcome to " + pageName + "</h2>" +
               "<p>This is the legacy interface.</p>";
    }
    
    private String renderLegacyFooter() {
        return "<hr><p>Copyright 2024 Legacy App</p>";
    }
}

// 实验性推荐服务
@Component
public class ExperimentalRecommendationService implements RecommendationService {
    
    @PostConstruct
    public void init() {
        System.out.println("实验性推荐服务已启用 - 使用机器学习算法");
    }
    
    @Override
    public List<Product> getRecommendations(String userId, int limit) {
        System.out.println("使用ML算法为用户 " + userId + " 生成推荐");
        
        // 模拟机器学习推荐算法
        return generateMLRecommendations(userId, limit);
    }
    
    private List<Product> generateMLRecommendations(String userId, int limit) {
        List<Product> recommendations = new ArrayList<>();
        
        // 模拟复杂的ML算法
        for (int i = 1; i <= limit; i++) {
            Product product = new Product();
            product.setId("ml-" + i);
            product.setName("ML推荐商品 " + i);
            product.setScore(0.95 - (i * 0.1)); // 模拟置信度分数
            recommendations.add(product);
        }
        
        return recommendations;
    }
}

// 标准推荐服务
@Component
public class StandardRecommendationService implements RecommendationService {
    
    @PostConstruct
    public void init() {
        System.out.println("标准推荐服务已启用 - 使用基于规则的算法");
    }
    
    @Override
    public List<Product> getRecommendations(String userId, int limit) {
        System.out.println("使用规则算法为用户 " + userId + " 生成推荐");
        
        // 模拟基于规则的推荐算法
        return generateRuleBasedRecommendations(userId, limit);
    }
    
    private List<Product> generateRuleBasedRecommendations(String userId, int limit) {
        List<Product> recommendations = new ArrayList<>();
        
        // 模拟简单的规则算法
        for (int i = 1; i <= limit; i++) {
            Product product = new Product();
            product.setId("rule-" + i);
            product.setName("规则推荐商品 " + i);
            product.setScore(0.80 + (Math.random() * 0.15)); // 模拟分数
            recommendations.add(product);
        }
        
        return recommendations;
    }
}

13. 最佳实践和注意事项

13.1 条件注解设计原则

// ✅ 好的实践:明确的条件逻辑
@Configuration
public class GoodConditionalConfig {
    
    // 1. 条件清晰明确
    @Bean
    @ConditionalOnClass(RedisTemplate.class)
    @ConditionalOnProperty(prefix = "spring.redis", name = "host")
    @ConditionalOnMissingBean(RedisTemplate.class)
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
    
    // 2. 提供默认实现
    @Bean
    @ConditionalOnMissingBean(CacheManager.class)
    public CacheManager defaultCacheManager() {
        return new ConcurrentMapCacheManager("default", "users", "products");
    }
    
    // 3. 合理的条件组合
    @Bean
    @ConditionalOnWebApplication
    @ConditionalOnClass(name = "org.springframework.security.web.SecurityFilterChain")
    @ConditionalOnProperty(name = "app.security.enabled", matchIfMissing = true)
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated())
            .formLogin(Customizer.withDefaults())
            .build();
    }
}

13.2 性能优化建议

@Configuration
public class PerformanceOptimizedConfig {
    
    // 1. 使用类名字符串避免不必要的类加载
    @Bean
    @ConditionalOnClass(name = "com.expensive.library.ExpensiveClass")
    public ExpensiveService expensiveService() {
        return new ExpensiveService();
    }
    
    // 2. 合理使用@ConditionalOnBean的搜索范围
    @Bean
    @ConditionalOnBean(value = DataSource.class, search = SearchStrategy.CURRENT)
    public LocalTransactionManager transactionManager(DataSource dataSource) {
        return new LocalTransactionManager(dataSource);
    }
    
    // 3. 避免在条件中进行昂贵的操作
    @Bean
    @ConditionalOnProperty(name = "app.feature.enabled")
    public FeatureService featureService() {
        return new FeatureService();
    }
}

// 自定义高效条件
public class CachedCondition implements Condition {
    
    private volatile Boolean cachedResult;
    private final Object lock = new Object();
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (cachedResult == null) {
            synchronized (lock) {
                if (cachedResult == null) {
                    cachedResult = performExpensiveCheck(context);
                }
            }
        }
        return cachedResult;
    }
    
    private boolean performExpensiveCheck(ConditionContext context) {
        // 昂贵的检查逻辑
        String osName = context.getEnvironment().getProperty("os.name");
        return osName != null && osName.toLowerCase().contains("linux");
    }
}

14. 常见问题和解决方案

14.1 条件注解不生效

问题1:配置类没有被扫描到

// ❌ 问题:配置类不在扫描路径中
package com.other.package.config;

@Configuration
@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
public class FeatureConfig {
    @Bean
    public FeatureService featureService() {
        return new FeatureService();
    }
}

// ✅ 解决方案1:确保在扫描路径中
@SpringBootApplication(scanBasePackages = {"com.myapp", "com.other.package"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// ✅ 解决方案2:使用@Import显式导入
@SpringBootApplication
@Import(FeatureConfig.class)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

问题2:属性配置错误

// ❌ 问题:属性名称拼写错误
@Bean
@ConditionalOnProperty(name = "app.feature.enable", havingValue = "true") // 应该是enabled
public FeatureService featureService() {
    return new FeatureService();
}

// ✅ 解决方案:添加调试组件
@Component
public class ConfigurationDebugger {
    
    @Autowired
    private Environment environment;
    
    @PostConstruct
    public void debugConfiguration() {
        System.out.println("=== 配置调试信息 ===");
        System.out.println("Active profiles: " + Arrays.toString(environment.getActiveProfiles()));
        
        // 检查关键属性
        checkProperty("app.feature.enabled");
        checkProperty("spring.redis.host");
        checkProperty("spring.datasource.url");
    }
    
    private void checkProperty(String propertyName) {
        String value = environment.getProperty(propertyName);
        System.out.println(propertyName + " = " + value);
    }
}

14.2 Bean循环依赖问题

// ❌ 问题:循环依赖
@Configuration
public class CircularDependencyConfig {
    
    @Bean
    @ConditionalOnBean(ServiceB.class)
    public ServiceA serviceA(ServiceB serviceB) {
        return new ServiceA(serviceB);
    }
    
    @Bean
    @ConditionalOnBean(ServiceA.class) 
    public ServiceB serviceB(ServiceA serviceA) {
        return new ServiceB(serviceA);
    }
}

// ✅ 解决方案:重新设计依赖关系
@Configuration
public class FixedDependencyConfig {
    
    @Bean
    public ServiceA serviceA() {
        return new ServiceA();
    }
    
    @Bean
    @ConditionalOnBean(ServiceA.class)
    public ServiceB serviceB(ServiceA serviceA) {
        return new ServiceB(serviceA);
    }
    
    @Bean
    @ConditionalOnBean({ServiceA.class, ServiceB.class})
    public ServiceCoordinator serviceCoordinator(ServiceA serviceA, ServiceB serviceB) {
        return new ServiceCoordinator(serviceA, serviceB);
    }
}

15. 高级主题

15.1 条件注解执行顺序

// 条件注解的执行顺序演示
@Configuration
public class ConditionalOrderDemo {
    
    // 1. 类级别条件首先执行
    @ConditionalOnClass(RedisTemplate.class)
    static class RedisConfiguration {
        
        // 2. 方法级别条件随后执行
        @Bean
        @ConditionalOnProperty(prefix = "spring.redis", name = "host")
        @ConditionalOnMissingBean
        public RedisTemplate<String, Object> redisTemplate() {
            return new RedisTemplate<>();
        }
    }
}

// 自定义条件的优先级控制
public class HighPriorityCondition implements Condition, Ordered {
    
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        System.out.println("执行高优先级条件检查");
        return true;
    }
    
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

15.2 监控和诊断

@Component
public class ConditionalMonitor implements ApplicationContextAware {
    
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    @EventListener(ContextRefreshedEvent.class)
    public void reportConditionalBeans() {
        System.out.println("=== 条件Bean创建报告 ===");
        
        String[] beanNames = applicationContext.getBeanDefinitionNames();
        int conditionalBeanCount = 0;
        
        for (String beanName : beanNames) {
            if (isConditionalBean(beanName)) {
                conditionalBeanCount++;
                System.out.println("条件Bean: " + beanName);
            }
        }
        
        System.out.println("总共创建了 " + conditionalBeanCount + " 个条件Bean");
    }
    
    private boolean isConditionalBean(String beanName) {
        try {
            BeanDefinition definition = ((ConfigurableApplicationContext) applicationContext)
                .getBeanFactory().getBeanDefinition(beanName);
            
            if (definition instanceof AnnotatedBeanDefinition) {
                MethodMetadata metadata = ((AnnotatedBeanDefinition) definition).getFactoryMethodMetadata();
                return metadata != null && hasConditionalAnnotations(metadata);
            }
        } catch (Exception e) {
            // 忽略异常
        }
        return false;
    }
    
    private boolean hasConditionalAnnotations(MethodMetadata metadata) {
        return metadata.isAnnotated(ConditionalOnClass.class.getName()) ||
               metadata.isAnnotated(ConditionalOnProperty.class.getName()) ||
               metadata.isAnnotated(ConditionalOnBean.class.getName()) ||
               metadata.isAnnotated(Conditional.class.getName());
    }
}

总结

SpringBoot条件注解是一个强大而灵活的特性,它让我们能够根据不同的条件智能地配置应用程序。通过本教程,您应该已经掌握了:

🎯 核心知识点

  1. 基础概念 - 理解条件注解的工作原理和执行时机
  2. 常用注解 - 熟练使用各种内置条件注解
  3. 自定义条件 - 能够创建符合业务需求的自定义条件
  4. 最佳实践 - 遵循良好的设计原则和编码规范
  5. 问题解决 - 能够诊断和解决常见问题

🚀 实际应用

  • 多环境管理 - 开发、测试、生产环境的差异化配置
  • 功能开关 - 灵活控制功能的启用和禁用
  • 降级方案 - 当某些依赖不可用时提供备选方案
  • 性能优化 - 避免不必要的Bean创建和初始化

📚 进阶学习建议

  1. 深入源码 - 研究SpringBoot自动配置的源码实现
  2. 实践项目 - 在真实项目中应用条件注解
  3. 性能监控 - 关注条件注解对启动性能的影响
  4. 社区学习 - 关注Spring社区的最新发展

🌟 关键要点

  • 条件注解在应用启动时执行,不是运行时
  • 合理组合多个条件注解可以实现复杂的配置逻辑
  • 自定义条件类应该尽可能高效,避免昂贵的操作
  • 使用@ConditionalOnMissingBean提供默认实现是好的实践
  • 测试条件注解配置是确保功能正确的重要环节

记住,条件注解不仅仅是技术工具,更是设计思想的体现。合理使用条件注解可以让您的应用更加灵活、可维护和可扩展。


网站公告

今日签到

点亮在社区的每一天
去签到