常见问题
常见问题与解决方案。
Nebula 框架常见问题 (FAQ)
本文档收集了使用 Nebula 框架时的常见问题和解决方案
目录
入门问题
Q1: Nebula 框架适合什么场景?
A: Nebula 框架适合以下场景:
✅ 适合: - 微服务架构 - 中大型企业应用 - 高并发系统 - 需要快速开发的项目 - 票务、电商、社交等业务系统
❌ 不太适合: - 简单的单体应用(可以用,但可能过重) - 超小型项目(几个接口) - 对框架有深度定制需求的项目
Q2: Nebula 与 Spring Boot 的关系?
A: Nebula 是基于 Spring Boot 3.x 构建的企业级框架:
Spring Boot 3.x(基础)
↓
Nebula Framework(增强)
↓
您的业务应用
Nebula 提供: - 开箱即用的常用功能 - 统一的配置和约定 - 企业级最佳实践 - 完整的技术栈集成
您仍然可以: - 使用所有 Spring Boot 特性 - 添加其他 Spring 组件 - 自定义配置
Q3: 需要什么基础才能使用 Nebula?
A: 建议掌握以下技术:
必需: - Java 基础(Java 17+) - Spring Boot 基础 - Maven/Gradle 基础
推荐: - Spring Cloud 微服务 - MyBatis/MyBatis-Plus - Redis 缓存 - RabbitMQ 消息队列
Starter 选择
Q4: 应该选择哪个 Starter?
A: 根据项目类型选择:
| 项目类型 | 推荐 Starter | 说明 |
|---|---|---|
| API 契约 | nebula-starter-api |
只定义接口,无实现 |
| 单体应用 | nebula-starter-all |
包含所有功能 |
| Web 应用 | nebula-starter-web |
适合前后端分离 |
| 微服务 | nebula-starter-service |
微服务间通信 |
| AI 应用 | nebula-starter-ai |
集成 AI 能力 |
| 极简应用 | nebula-starter-minimal |
最小依赖集 |
详细指南:Starter 选择指南
Q5: 可以同时使用多个 Starter 吗?
A: 不建议同时使用多个 Starter,因为它们之间可能存在依赖冲突。
正确做法:
<!-- 只选择一个 Starter -->
<dependency>
<groupId>com.andy.nebula</groupId>
<artifactId>nebula-starter-web</artifactId>
</dependency>
如需额外功能:
<!-- 添加单独的功能模块 -->
<dependency>
<groupId>com.andy.nebula</groupId>
<artifactId>nebula-search-elasticsearch</artifactId>
</dependency>
配置问题
Q6: 配置文件怎么写?
A: Nebula 统一使用 nebula 前缀:
# application.yml
nebula:
# 数据访问
data:
persistence:
enabled: true
cache:
enabled: true
type: redis
# 安全认证
security:
jwt:
enabled: true
secret: your-secret-key
# RPC 通信
rpc:
grpc:
enabled: true
port: 9090
配置优先级:
1. 命令行参数 (--nebula.xxx=yyy)
2. application-{profile}.yml
3. application.yml
4. 默认配置
详细配置:查看各模块的 CONFIG.md
Q7: 如何区分开发和生产环境配置?
A: 使用 Spring Profile:
# application.yml(通用配置)
spring:
application:
name: my-app
nebula:
data:
persistence:
enabled: true
---
# application-dev.yml(开发环境)
nebula:
data:
cache:
type: caffeine # 本地缓存
---
# application-prod.yml(生产环境)
nebula:
data:
cache:
type: redis # Redis 缓存
security:
jwt:
secret: ${JWT_SECRET} # 从环境变量读取
启动时指定:
# 开发环境
java -jar app.jar --spring.profiles.active=dev
# 生产环境
java -jar app.jar --spring.profiles.active=prod
数据访问
Q8: 如何配置多数据源?
A: Nebula 支持多数据源配置:
nebula:
data:
persistence:
datasources:
master:
url: jdbc:mysql://localhost:3306/main
username: root
password: password
slave:
url: jdbc:mysql://localhost:3307/main
username: readonly
password: password
代码使用:
@Service
public class UserService {
@DS("master") // 指定数据源
public void createUser(User user) {
userMapper.insert(user);
}
@DS("slave")
public List<User> listUsers() {
return userMapper.selectList(null);
}
}
Q9: 如何处理分页查询?
A: MyBatis-Plus 内置分页支持:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public IPage<User> getUsers(int page, int size) {
Page<User> pageParam = new Page<>(page, size);
return userMapper.selectPage(pageParam, null);
}
}
自定义查询分页:
public IPage<UserVO> searchUsers(SearchDTO dto) {
Page<User> page = new Page<>(dto.getPage(), dto.getSize());
QueryWrapper<User> query = new QueryWrapper<>();
query.like("username", dto.getKeyword());
IPage<User> result = userMapper.selectPage(page, query);
// 转换为 VO
return result.convert(this::toVO);
}
缓存问题
Q10: 缓存不生效怎么办?
A: 检查以下几点:
1. 配置是否启用:
nebula:
data:
cache:
enabled: true # 确保启用
type: redis
2. 是否添加注解:
@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User getById(Long id) {
return userMapper.selectById(id);
}
}
3. 方法是否被代理:
// ❌ 错误:同类调用不会触发缓存
public class UserService {
public User getUser(Long id) {
return this.getById(id); // 不会缓存
}
@Cacheable(value = "users", key = "#id")
public User getById(Long id) {
return userMapper.selectById(id);
}
}
// ✅ 正确:通过注入调用
@Service
public class UserController {
@Autowired
private UserService userService;
public User getUser(Long id) {
return userService.getById(id); // 会缓存
}
}
4. Redis 连接是否正常:
# 检查 Redis 连接
redis-cli ping
# 应返回: PONG
Q11: 如何清空缓存?
A: 使用 @CacheEvict 注解:
@Service
public class UserService {
// 更新时清空单个缓存
@CacheEvict(value = "users", key = "#user.id")
public void updateUser(User user) {
userMapper.updateById(user);
}
// 清空所有用户缓存
@CacheEvict(value = "users", allEntries = true)
public void clearAllCache() {
// 清空逻辑
}
}
消息队列
Q12: 如何发送和接收消息?
A: 使用 Nebula 消息抽象:
发送消息:
@Service
public class OrderService {
@Autowired
private MessagePublisher messagePublisher;
public void createOrder(Order order) {
// 保存订单
orderMapper.insert(order);
// 发送消息
OrderCreatedEvent event = new OrderCreatedEvent(order);
messagePublisher.publish("order.created", event);
}
}
接收消息:
@Component
public class OrderEventListener {
@MessageHandler(topic = "order.created")
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("订单创建: {}", event.getOrderId());
// 处理业务逻辑
}
}
Q13: 消息消费失败怎么办?
A: Nebula 提供多种失败处理策略:
1. 自动重试:
nebula:
messaging:
rabbitmq:
consumer:
max-retries: 3
retry-interval: 5000 # 5秒
2. 死信队列:
@MessageHandler(
topic = "order.created",
deadLetterTopic = "order.created.dlq"
)
public void handleOrderCreated(OrderCreatedEvent event) {
// 处理逻辑
}
3. 手动确认:
@MessageHandler(
topic = "order.created",
ackMode = AckMode.MANUAL
)
public void handleOrderCreated(OrderCreatedEvent event, MessageContext context) {
try {
// 处理逻辑
context.ack(); // 手动确认
} catch (Exception e) {
context.nack(); // 拒绝消息
}
}
RPC 通信
Q14: 如何调用远程服务?
A: Nebula 支持 HTTP 和 gRPC 两种方式:
HTTP RPC:
@Service
public class OrderService {
@Autowired
@RpcClient(service = "user-service")
private UserApi userApi;
public Order createOrder(CreateOrderDTO dto) {
// 调用远程用户服务
User user = userApi.getById(dto.getUserId());
// 创建订单逻辑
Order order = new Order();
order.setUserId(user.getId());
return order;
}
}
gRPC:
@Service
public class OrderService {
@GrpcClient("user-service")
private UserServiceGrpc.UserServiceBlockingStub userStub;
public Order createOrder(CreateOrderDTO dto) {
// gRPC 调用
UserResponse response = userStub.getUser(
UserRequest.newBuilder()
.setId(dto.getUserId())
.build()
);
// 创建订单逻辑
return new Order();
}
}
Q15: RPC 调用超时怎么办?
A: 配置超时时间和重试策略:
nebula:
rpc:
http:
connect-timeout: 5000 # 连接超时 5秒
read-timeout: 10000 # 读取超时 10秒
max-retries: 3 # 最多重试 3 次
grpc:
deadline: 10 # gRPC 超时 10秒
针对特定接口:
@RpcClient(
service = "user-service",
timeout = 30000 // 30秒超时
)
private UserApi userApi;
服务发现
Q16: 服务注册失败怎么办?
A: 检查 Nacos 配置:
1. Nacos 是否启动:
# 检查 Nacos 是否运行
curl http://localhost:8848/nacos/
2. 配置是否正确:
nebula:
discovery:
nacos:
enabled: true
server-addr: localhost:8848
namespace: dev # 命名空间
group: DEFAULT_GROUP # 分组
3. 网络是否连通:
# 测试网络连接
telnet localhost 8848
4. 查看日志:
# 应用日志
tail -f logs/app.log
# Nacos 日志
tail -f nacos/logs/naming-server.log
安全认证
Q17: 如何实现 JWT 认证?
A: Nebula 内置 JWT 支持:
1. 配置:
nebula:
security:
jwt:
enabled: true
secret: your-very-secure-secret-key-at-least-256-bits
expiration: 86400 # 24小时
2. 登录生成 Token:
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private JwtTokenProvider tokenProvider;
@PostMapping("/login")
public Result<LoginVO> login(@RequestBody LoginDTO dto) {
// 验证用户名密码
User user = authService.authenticate(dto);
// 生成 Token
String token = tokenProvider.createToken(user.getId(), user.getRoles());
return Result.success(new LoginVO(token));
}
}
3. 验证 Token:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/me")
@RequiresAuthentication // 需要认证
public Result<UserVO> getCurrentUser() {
Long userId = SecurityContext.getUserId();
User user = userService.getById(userId);
return Result.success(toVO(user));
}
}
Q18: 如何实现 RBAC 权限控制?
A: 使用 @RequiresPermission 注解:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@GetMapping
@RequiresPermission("order:view")
public Result<List<OrderVO>> listOrders() {
// 查询订单
}
@PostMapping
@RequiresPermission("order:create")
public Result<OrderVO> createOrder(@RequestBody CreateOrderDTO dto) {
// 创建订单
}
@DeleteMapping("/{id}")
@RequiresPermission("order:delete")
public Result<Void> deleteOrder(@PathVariable Long id) {
// 删除订单
}
}
权限数据模型:
User (用户)
↓ N:N
Role (角色)
↓ N:N
Permission (权限)
↓
Resource (资源)
性能优化
Q19: 如何提升系统性能?
A: 多方面优化:
1. 使用多级缓存:
nebula:
data:
cache:
type: multi-level
l1:
type: caffeine
max-size: 1000
l2:
type: redis
ttl: 3600
2. 启用数据库连接池:
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
3. 使用异步处理:
@Service
public class NotificationService {
@Async
public void sendEmail(String to, String content) {
// 异步发送邮件
}
}
4. 批量操作:
// ❌ 逐条插入
for (User user : users) {
userMapper.insert(user);
}
// ✅ 批量插入
userService.saveBatch(users);
5. 索引优化:
-- 为常用查询字段添加索引
CREATE INDEX idx_username ON users(username);
CREATE INDEX idx_created_at ON orders(created_at);
Q20: 如何监控性能?
A: 集成 Spring Boot Actuator:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
访问监控端点:
- 健康检查:http://localhost:8080/actuator/health
- 性能指标:http://localhost:8080/actuator/metrics
- Prometheus:http://localhost:8080/actuator/prometheus
错误处理
Q21: 如何统一处理异常?
A: Nebula 提供全局异常处理:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
log.error("业务异常: {}", e.getMessage());
return Result.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
log.error("系统错误", e);
return Result.fail(ErrorCode.SYSTEM_ERROR, "系统错误");
}
}
自定义业务异常:
public class OrderNotFoundException extends BusinessException {
public OrderNotFoundException(Long orderId) {
super(ErrorCode.ORDER_NOT_FOUND, "订单不存在: " + orderId);
}
}
部署运维
Q22: 如何打包部署?
A: 使用 Maven 打包:
# 打包
mvn clean package -DskipTests
# 生成的 JAR 位于
target/your-app-<version>.jar
运行:
java -jar target/your-app-<version>.jar
Docker 部署:
FROM openjdk:21-jdk-slim
COPY target/your-app-<version>.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 构建镜像
docker build -t your-app:<version> .
# 运行容器
docker run -d -p 8080:8080 your-app:<version>
Q23: 如何配置日志?
A: 使用 Logback 配置:
<!-- src/main/resources/logback-spring.xml -->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
<logger name="com.andy.nebula" level="DEBUG" />
</configuration>
更多问题?
如果您的问题没有在此列出,可以:
- 查阅文档:完整文档
- 查看示例:示例项目
- 提交 Issue:GitHub Issues
- 加入讨论:GitHub Discussions
最后更新: 2025-11-20
文档版本: v1.0