Skip to content

最佳实践 - Spring 集成

将 LCGYL Framework 与 Spring Boot 集成的最佳实践。

项目结构

推荐的目录结构

my-spring-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/app/
│   │   │       ├── Application.java          # Spring Boot 主类
│   │   │       ├── config/                   # 配置类
│   │   │       │   ├── LcgylConfig.java
│   │   │       │   └── SecurityConfig.java
│   │   │       ├── controller/               # 控制器
│   │   │       │   └── UserController.java
│   │   │       ├── service/                  # 服务层
│   │   │       │   └── UserService.java
│   │   │       ├── repository/               # 数据访问层
│   │   │       │   └── UserRepository.java
│   │   │       ├── model/                    # 实体类
│   │   │       │   └── User.java
│   │   │       └── dto/                      # 数据传输对象
│   │   │           └── UserDTO.java
│   │   └── resources/
│   │       ├── application.yml               # Spring 配置
│   │       ├── application-dev.yml
│   │       ├── application-prod.yml
│   │       └── static/
│   └── test/
│       └── java/
│           └── com/example/app/
│               └── service/
│                   └── UserServiceTest.java
├── build.gradle
└── README.md

依赖管理

使用 Spring Boot Starter

gradle
dependencies {
    // Spring Boot
    implementation 'org.springframework.boot:spring-boot-starter-web'
    
    // LCGYL Spring Boot Starter
    implementation 'com.lcgyl:lcgyl-framework-spring'
    
    // LCGYL 插件
    implementation 'com.lcgyl:lcgyl-web-plugin'
    implementation 'com.lcgyl:lcgyl-cache-plugin'
    implementation 'com.lcgyl:lcgyl-security-plugin'
}

版本管理

gradle
ext {
    lcgylVersion = '1.0.0'
    springBootVersion = '3.3.5'
}

dependencies {
    implementation platform("org.springframework.boot:spring-boot-dependencies:${springBootVersion}")
    implementation platform("com.lcgyl:lcgyl-framework-dependencies:${lcgylVersion}")
}

配置管理

使用 YAML 配置

yaml
# application.yml
spring:
  application:
    name: my-app
  profiles:
    active: dev

lcgyl:
  plugins:
    web:
      enabled: true
      server:
        port: ${SERVER_PORT:8080}
    data:
      enabled: true
      datasource:
        url: ${DB_URL:jdbc:mysql://localhost:3306/db}
        username: ${DB_USERNAME:root}
        password: ${DB_PASSWORD:password}

多环境配置

yaml
# application-dev.yml
lcgyl:
  plugins:
    web:
      server:
        port: 8080
    data:
      datasource:
        url: jdbc:mysql://localhost:3306/dev_db

# application-prod.yml
lcgyl:
  plugins:
    web:
      server:
        port: 80
    data:
      datasource:
        url: jdbc:mysql://prod-server:3306/prod_db

配置类

java
@Configuration
@EnableLcgyl
@EnableConfigurationProperties(LcgylProperties.class)
public class LcgylConfig {
    
    @Bean
    @ConditionalOnMissingBean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

依赖注入

使用 Spring 注解

java
// ✅ 推荐:使用 Spring 注解
@Service
public class UserService {
    
    private final UserRepository userRepository;
    
    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

// 也可以使用 LCGYL 注解
@Component
public class UserService {
    
    private final UserRepository userRepository;
    
    @Inject
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

混合使用

java
@Service
public class OrderService {
    
    // Spring Bean
    @Autowired
    private UserService userService;
    
    // LCGYL Bean
    @Inject
    private MessageProducer messageProducer;
    
    @Transactional
    public Order createOrder(Order order) {
        // 使用 Spring Bean
        User user = userService.findById(order.getUserId());
        
        // 保存订单
        Order saved = orderRepository.save(order);
        
        // 使用 LCGYL Bean
        messageProducer.send("order.created", saved);
        
        return saved;
    }
}

事务管理

使用 Spring 事务

java
@Service
public class UserService {
    
    // ✅ 推荐:使用 Spring @Transactional
    @Transactional
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    // 指定事务属性
    @Transactional(
        propagation = Propagation.REQUIRES_NEW,
        isolation = Isolation.READ_COMMITTED,
        rollbackFor = Exception.class
    )
    public void complexOperation() {
        // 复杂操作
    }
}

编程式事务

java
@Service
public class OrderService {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public Order createOrder(Order order) {
        return transactionTemplate.execute(status -> {
            try {
                Order saved = orderRepository.save(order);
                inventoryService.decreaseStock(order.getItems());
                return saved;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
    }
}

异常处理

使用 Spring 异常处理

java
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(NotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleNotFound(NotFoundException e) {
        return ErrorResponse.builder()
            .status(404)
            .message(e.getMessage())
            .timestamp(LocalDateTime.now())
            .build();
    }
    
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleBusiness(BusinessException e) {
        return ErrorResponse.builder()
            .status(400)
            .message(e.getMessage())
            .code(e.getCode())
            .timestamp(LocalDateTime.now())
            .build();
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResponse handleGeneral(Exception e) {
        log.error("未处理的异常", e);
        return ErrorResponse.builder()
            .status(500)
            .message("服务器内部错误")
            .timestamp(LocalDateTime.now())
            .build();
    }
}

数据访问

使用 LCGYL JdbcTemplate

java
@Repository
public class UserRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public Optional<User> findById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        return jdbcTemplate.queryForOptional(sql, User.class, id);
    }
    
    @Transactional
    public User save(User user) {
        if (user.getId() == null) {
            String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
            Long id = jdbcTemplate.insert(sql, user.getName(), user.getEmail());
            user.setId(id);
        } else {
            String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
            jdbcTemplate.update(sql, user.getName(), user.getEmail(), user.getId());
        }
        return user;
    }
}

与 Spring Data JPA 共存

java
// Spring Data JPA Repository
@Repository
public interface UserJpaRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

// LCGYL JDBC Repository
@Repository
public class UserJdbcRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public List<User> findByCustomCriteria(Map<String, Object> criteria) {
        // 复杂查询
        String sql = buildDynamicSql(criteria);
        return jdbcTemplate.queryForList(sql, User.class);
    }
}

// Service 层混合使用
@Service
public class UserService {
    
    @Autowired
    private UserJpaRepository jpaRepository;
    
    @Autowired
    private UserJdbcRepository jdbcRepository;
    
    public User findById(Long id) {
        return jpaRepository.findById(id)
            .orElseThrow(() -> new NotFoundException("用户不存在"));
    }
    
    public List<User> search(Map<String, Object> criteria) {
        return jdbcRepository.findByCustomCriteria(criteria);
    }
}

缓存

使用 Spring Cache

java
@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#id")
    public User findById(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new NotFoundException("用户不存在"));
    }
    
    @CachePut(value = "users", key = "#user.id")
    public User update(User user) {
        return userRepository.save(user);
    }
    
    @CacheEvict(value = "users", key = "#id")
    public void delete(Long id) {
        userRepository.delete(id);
    }
}

配置缓存

yaml
lcgyl:
  plugins:
    cache:
      enabled: true
      type: redis
      redis:
        host: localhost
        port: 6379
      # 缓存配置
      caches:
        users:
          ttl: 600
          max-size: 1000

消息队列

使用 LCGYL Messaging

java
@Service
public class OrderService {
    
    @Autowired
    private MessageProducer messageProducer;
    
    @Transactional
    public Order createOrder(Order order) {
        Order saved = orderRepository.save(order);
        
        // 发送消息
        messageProducer.send("order.created", saved);
        
        return saved;
    }
}

@Component
public class OrderListener {
    
    @MessageListener(topic = "order.created")
    public void onOrderCreated(Order order) {
        // 处理订单
        processOrder(order);
    }
}

与 Spring AMQP 共存

java
// LCGYL Messaging
@MessageListener(topic = "order.created")
public void onOrderCreated(Order order) {
    // LCGYL 消息处理
}

// Spring AMQP
@RabbitListener(queues = "order.queue")
public void handleOrder(Order order) {
    // Spring AMQP 消息处理
}

安全

使用 LCGYL Security

java
@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain securityFilterChain() {
        return SecurityFilterChain.builder()
            .authorizeRequests(auth -> auth
                .antMatchers("/public/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .jwt(jwt -> jwt
                .secret("your-secret-key")
                .expiration(86400000)
            )
            .build();
    }
}

在控制器中使用

java
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/me")
    @RequiresAuthentication
    public User getCurrentUser(@CurrentUser User user) {
        return user;
    }
    
    @PostMapping
    @RequiresRole("ADMIN")
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
}

测试

单元测试

java
@SpringBootTest
public class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @MockBean
    private UserRepository userRepository;
    
    @Test
    public void testFindById() {
        // Given
        User user = new User(1L, "John", "john@example.com");
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        
        // When
        User found = userService.findById(1L);
        
        // Then
        assertEquals(found.getId(), 1L);
        assertEquals(found.getName(), "John");
    }
}

集成测试

java
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase
public class UserControllerIntegrationTest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testGetUser() {
        // When
        ResponseEntity<User> response = restTemplate.getForEntity(
            "/api/users/1",
            User.class
        );
        
        // Then
        assertEquals(response.getStatusCode(), HttpStatus.OK);
        assertNotNull(response.getBody());
    }
}

监控

Actuator 集成

yaml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,lcgyl
  endpoint:
    health:
      show-details: always

lcgyl:
  management:
    enabled: true
    metrics:
      enabled: true

自定义健康检查

java
@Component
public class LcgylHealthIndicator implements HealthIndicator {
    
    @Autowired
    private PluginManager pluginManager;
    
    @Override
    public Health health() {
        List<Plugin> plugins = pluginManager.getAllPlugins();
        
        boolean allRunning = plugins.stream()
            .allMatch(Plugin::isRunning);
        
        if (allRunning) {
            return Health.up()
                .withDetail("plugins", plugins.size())
                .withDetail("status", "all running")
                .build();
        } else {
            return Health.down()
                .withDetail("plugins", plugins.size())
                .withDetail("status", "some stopped")
                .build();
        }
    }
}

性能优化

连接池配置

yaml
lcgyl:
  plugins:
    data:
      datasource:
        hikari:
          maximum-pool-size: 20
          minimum-idle: 5
          connection-timeout: 30000
          idle-timeout: 600000
          max-lifetime: 1800000

异步处理

java
@Service
public class NotificationService {
    
    @Async
    public CompletableFuture<Void> sendEmail(String to, String subject, String content) {
        // 发送邮件
        emailSender.send(to, subject, content);
        return CompletableFuture.completedFuture(null);
    }
}

@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("async-");
        executor.initialize();
        return executor;
    }
}

下一步

Released under the Apache License 2.0