最佳实践 - 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;
}
}