Skip to content

Spring Boot 集成

本文档详细介绍如何在 Spring Boot 应用中集成 LCGYL Framework。

快速开始

添加依赖

gradle
dependencies {
    implementation 'com.lcgyl:lcgyl-framework-spring:${version}'
}
xml
<dependency>
    <groupId>com.lcgyl</groupId>
    <artifactId>lcgyl-framework-spring</artifactId>
    <version>${version}</version>
</dependency>

启用框架

java
@SpringBootApplication
@EnableLcgylFramework
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

配置

基本配置

yaml
# application.yml
lcgyl:
  enabled: true
  
  # 插件配置
  plugin:
    enabled: true
    directory: plugins
    scan-packages:
      - com.example.plugins
    auto-start: true
  
  # 事件总线配置
  event:
    enabled: true
    async: true
    thread-pool-size: 10
    queue-capacity: 1000
  
  # IoC 容器配置
  ioc:
    enabled: true
    scan-packages:
      - com.example.components
    lazy-init: false
  
  # AOP 配置
  aop:
    enabled: true
    proxy-target-class: true

环境配置

yaml
# application-dev.yml
lcgyl:
  event:
    async: false  # 开发环境同步执行便于调试

# application-prod.yml
lcgyl:
  event:
    async: true
    thread-pool-size: 20

配置属性类

java
@ConfigurationProperties(prefix = "lcgyl")
public class LcgylProperties {
    
    private boolean enabled = true;
    private PluginProperties plugin = new PluginProperties();
    private EventProperties event = new EventProperties();
    private IocProperties ioc = new IocProperties();
    private AopProperties aop = new AopProperties();
    
    // Getters and Setters
    
    public static class PluginProperties {
        private boolean enabled = true;
        private String directory = "plugins";
        private List<String> scanPackages = new ArrayList<>();
        private boolean autoStart = true;
        // Getters and Setters
    }
    
    public static class EventProperties {
        private boolean enabled = true;
        private boolean async = true;
        private int threadPoolSize = 10;
        private int queueCapacity = 1000;
        // Getters and Setters
    }
}

自动配置

核心自动配置

java
@Configuration
@ConditionalOnProperty(name = "lcgyl.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(LcgylProperties.class)
public class LcgylAutoConfiguration {
    
    @Autowired
    private LcgylProperties properties;
    
    @Bean
    @ConditionalOnMissingBean
    public Container container() {
        Container container = new DefaultContainer();
        container.setLazyInit(properties.getIoc().isLazyInit());
        return container;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public EventBus eventBus() {
        EventProperties eventProps = properties.getEvent();
        return new DefaultEventBus(
            eventProps.isAsync(),
            eventProps.getThreadPoolSize(),
            eventProps.getQueueCapacity()
        );
    }
    
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "lcgyl.plugin.enabled", havingValue = "true")
    public PluginManager pluginManager() {
        PluginProperties pluginProps = properties.getPlugin();
        PluginManager manager = new DefaultPluginManager();
        manager.setPluginDirectory(pluginProps.getDirectory());
        return manager;
    }
}

条件配置

java
@Configuration
public class ConditionalConfiguration {
    
    // 当 Redis 可用时启用缓存
    @Bean
    @ConditionalOnClass(name = "org.springframework.data.redis.core.RedisTemplate")
    @ConditionalOnProperty(name = "lcgyl.cache.type", havingValue = "redis")
    public CacheService redisCacheService(RedisTemplate<String, Object> redisTemplate) {
        return new RedisCacheService(redisTemplate);
    }
    
    // 默认内存缓存
    @Bean
    @ConditionalOnMissingBean(CacheService.class)
    public CacheService memoryCacheService() {
        return new MemoryCacheService();
    }
}

组件扫描

自动扫描

java
@SpringBootApplication
@EnableLcgylFramework
@LcgylComponentScan(basePackages = "com.example")
public class Application {
}

手动注册

java
@Configuration
public class ComponentConfiguration {
    
    @Bean
    public UserService userService(UserRepository userRepository) {
        return new UserServiceImpl(userRepository);
    }
    
    @Bean
    public OrderService orderService(
            OrderRepository orderRepository,
            UserService userService,
            EventBus eventBus) {
        return new OrderServiceImpl(orderRepository, userService, eventBus);
    }
}

事件集成

发布事件

java
@Service
public class OrderService {
    
    @Autowired
    private EventBus eventBus;
    
    @Autowired
    private ApplicationEventPublisher springEventPublisher;
    
    public Order createOrder(Order order) {
        orderRepository.save(order);
        
        // 发布 LCGYL 事件
        eventBus.publish(new OrderCreatedEvent(order));
        
        // 发布 Spring 事件
        springEventPublisher.publishEvent(new OrderCreatedSpringEvent(this, order));
        
        return order;
    }
}

监听事件

java
@Component
public class OrderEventListener {
    
    // 监听 LCGYL 事件
    @Subscribe
    public void onOrderCreated(OrderCreatedEvent event) {
        logger.info("LCGYL 事件: 订单创建 {}", event.getOrder().getId());
    }
    
    // 监听 Spring 事件
    @EventListener
    public void onOrderCreatedSpring(OrderCreatedSpringEvent event) {
        logger.info("Spring 事件: 订单创建 {}", event.getOrder().getId());
    }
    
    // 异步监听
    @Subscribe(async = true)
    public void onOrderCreatedAsync(OrderCreatedEvent event) {
        // 异步处理
    }
    
    // 条件监听
    @EventListener(condition = "#event.order.totalAmount > 1000")
    public void onLargeOrder(OrderCreatedSpringEvent event) {
        // 只处理大额订单
    }
}

事件桥接

java
@Component
public class EventBridge {
    
    @Autowired
    private EventBus lcgylEventBus;
    
    @Autowired
    private ApplicationEventPublisher springPublisher;
    
    // 将 Spring 事件转发到 LCGYL
    @EventListener
    public void bridgeSpringToLcgyl(ApplicationEvent event) {
        if (event instanceof OrderCreatedSpringEvent springEvent) {
            lcgylEventBus.publish(new OrderCreatedEvent(springEvent.getOrder()));
        }
    }
    
    // 将 LCGYL 事件转发到 Spring
    @Subscribe
    public void bridgeLcgylToSpring(OrderCreatedEvent event) {
        springPublisher.publishEvent(new OrderCreatedSpringEvent(this, event.getOrder()));
    }
}

AOP 集成

使用 LCGYL AOP

java
@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        logger.info("调用方法: {}", joinPoint.getSignature().getName());
    }
    
    @Around("@annotation(com.lcgyl.framework.aop.Timed)")
    public Object timed(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed();
        } finally {
            long duration = System.currentTimeMillis() - start;
            logger.info("方法 {} 耗时 {}ms", 
                joinPoint.getSignature().getName(), duration);
        }
    }
}

使用 Spring AOP

java
@Aspect
@Component
public class TransactionAspect {
    
    @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
    public Object handleTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        // 事务处理
        return joinPoint.proceed();
    }
}

插件集成

加载插件

java
@Configuration
@ConditionalOnProperty(name = "lcgyl.plugin.enabled", havingValue = "true")
public class PluginConfiguration {
    
    @Autowired
    private PluginManager pluginManager;
    
    @PostConstruct
    public void loadPlugins() {
        // 扫描并加载插件
        pluginManager.loadPlugins();
        
        // 启动所有插件
        pluginManager.startPlugins();
    }
    
    @PreDestroy
    public void unloadPlugins() {
        pluginManager.stopPlugins();
        pluginManager.unloadPlugins();
    }
}

插件作为 Spring Bean

java
@Component
public class PluginBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
    
    @Autowired
    private PluginManager pluginManager;
    
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 将插件注册为 Spring Bean
        for (Plugin plugin : pluginManager.getPlugins()) {
            BeanDefinition beanDefinition = BeanDefinitionBuilder
                .genericBeanDefinition(plugin.getClass())
                .getBeanDefinition();
            registry.registerBeanDefinition(plugin.getId(), beanDefinition);
        }
    }
}

健康检查

自定义健康指示器

java
@Component
public class LcgylHealthIndicator implements HealthIndicator {
    
    @Autowired
    private PluginManager pluginManager;
    
    @Autowired
    private EventBus eventBus;
    
    @Override
    public Health health() {
        Map<String, Object> details = new HashMap<>();
        
        // 检查插件状态
        int activePlugins = pluginManager.getActivePlugins().size();
        details.put("activePlugins", activePlugins);
        
        // 检查事件总线
        details.put("eventBusStatus", eventBus.isRunning() ? "running" : "stopped");
        
        if (activePlugins > 0 && eventBus.isRunning()) {
            return Health.up().withDetails(details).build();
        } else {
            return Health.down().withDetails(details).build();
        }
    }
}

Actuator 端点

java
@Endpoint(id = "lcgyl")
@Component
public class LcgylEndpoint {
    
    @Autowired
    private PluginManager pluginManager;
    
    @ReadOperation
    public Map<String, Object> info() {
        Map<String, Object> info = new HashMap<>();
        info.put("version", "1.0.0");
        info.put("plugins", pluginManager.getPlugins().stream()
            .map(p -> Map.of("id", p.getId(), "status", p.getStatus()))
            .collect(Collectors.toList()));
        return info;
    }
    
    @WriteOperation
    public void reloadPlugins() {
        pluginManager.reloadPlugins();
    }
}

测试支持

测试配置

java
@SpringBootTest
@TestPropertySource(properties = {
    "lcgyl.plugin.enabled=false",
    "lcgyl.event.async=false"
})
public class ApplicationTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void testUserService() {
        User user = userService.findById(1L);
        assertNotNull(user);
    }
}

Mock 支持

java
@SpringBootTest
public class OrderServiceTest {
    
    @MockBean
    private EventBus eventBus;
    
    @Autowired
    private OrderService orderService;
    
    @Test
    public void testCreateOrder() {
        Order order = new Order();
        orderService.createOrder(order);
        
        verify(eventBus).publish(any(OrderCreatedEvent.class));
    }
}

最佳实践

1. 配置分离

yaml
# application.yml - 通用配置
lcgyl:
  enabled: true

# application-dev.yml - 开发配置
lcgyl:
  event:
    async: false

# application-prod.yml - 生产配置
lcgyl:
  event:
    async: true
    thread-pool-size: 20

2. 条件加载

java
@Configuration
@ConditionalOnProperty(name = "lcgyl.feature.enabled", havingValue = "true")
public class FeatureConfiguration {
    // 只在功能启用时加载
}

3. 优雅关闭

java
@Component
public class GracefulShutdown implements DisposableBean {
    
    @Autowired
    private PluginManager pluginManager;
    
    @Autowired
    private EventBus eventBus;
    
    @Override
    public void destroy() {
        logger.info("开始优雅关闭...");
        pluginManager.stopPlugins();
        eventBus.shutdown();
        logger.info("优雅关闭完成");
    }
}

常见问题

Q: LCGYL 组件和 Spring Bean 如何互相注入?

A: LCGYL 组件自动注册为 Spring Bean,可以使用 @Autowired@Inject 互相注入。

Q: 如何禁用某个自动配置?

A: 使用配置属性或排除注解:

java
@SpringBootApplication(exclude = {PluginAutoConfiguration.class})

yaml
lcgyl:
  plugin:
    enabled: false

Q: 事件是否支持事务?

A: 可以使用 @TransactionalEventListener 在事务提交后发布事件。

下一步

Released under the Apache License 2.0