
写给正在做技术选型或迁移调研的 Java 开发者
如果你会 Spring Boot,那你已经会了一大半 Solon。Solon 不是 Spring 的分支或封装,它是独立发展的全栈应用开发框架。但在设计哲学上,Solon 遵循了 Java 主流的 IoC、AOP、MVC 范式---- 概念相同,注解名不同。这篇文章把 Spring Boot 到 Solon 的注解映射、配置迁移、关键差异整理成对照表,供迁移参考。
IoC/DI 容器:注解对照
核心原则:Solon 将 Spring 的多个细分注解合并为少数几个核心注解。
组件注册
Solon | Spring Boot | 说明
---|---|---
`@Component` | `@Component` / `@Service` / `@Repository` / `@Dao` | Solon 统一用一个注解
`@Configuration` | `@Configuration` | 完全一致
`@Bean` | `@Bean` | 完全一致
依赖注入
Solon | Spring Boot | 说明
---|---|---
`@Inject` | `@Autowired` | 按类型注入(by type)
`@Inject("name")` | `@Qualifier` + `@Autowired` | 按名称注入(by name)
`@Inject("${key}")` | `@Value("${key}")` | 注入配置值
`@BindProps(prefix="xxx")` | `@ConfigurationProperties(prefix="xxx")` | 绑定属性集
注意:Solon 的 `@Inject` 一个注解兼顾了 Spring 中 `@Autowired`、`@Qualifier`、`@Value` 三个注解的功能。
生命周期与作用域
Solon | Spring Boot | 说明
---|---|---
`@Init` | `@PostConstruct` | 组件初始化回调
`@Destroy` | `@PreDestroy` | 组件销毁回调
`LifecycleBean` | `InitializingBean` + `DisposableBean` | 接口方式控制生命周期
`AppLoadEndEvent` | `ApplicationRunner` / `CommandLineRunner` | 应用启动后执行
`@Singleton`(默认) | `@Scope("singleton")` | 单例(Solon 默认)
`@Singleton(false)` | `@Scope("prototype")` | 多例
`@Condition(...)` | `@ConditionalOnClass` / `@ConditionalOnProperty` 等 | Solon 统一为单一注解
`@Import` | `@Import` + `@ComponentScan` | 导入组件/配置类
Web 层:Controller 改写
注解映射
Solon | Spring Boot | 说明
---|---|---
`@Controller` | `@Controller` / `@RestController` | Solon 默认 JSON 输出
`@Mapping` | `@RequestMapping` | 路由映射
`@Get` + `@Mapping` | `@GetMapping` | GET 方法限定
`@Post` + `@Mapping` | `@PostMapping` | POST 方法限定
`@Put` + `@Mapping` | `@PutMapping` | PUT 方法限定
`@Delete` + `@Mapping` | `@DeleteMapping` | DELETE 方法限定
`@Param` | `@RequestParam` | 请求参数
`@Path` | `@PathVariable` | 路径变量
`@Body` | `@RequestBody` | 请求体
`@Header` | `@RequestHeader` | 请求头
`@Cookie` | `@CookieValue` | Cookie
`@Produces` | --(Spring 无直接等价) | 声明输出类型
`@Consumes` | --(Spring 无直接等价) | 声明输入类型
Before / After 示例
Spring Boot 写法:
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
@PostMapping
public User create(@RequestBody User user) {
return userService.save(user);
}
}Solon 写法:
@Controller
@Mapping("/users")
public class UserController {
@Inject
private UserService userService;
@Get
@Mapping("/{id}")
public User getUser(@Path Long id) {
return userService.findById(id);
}
@Post
@Mapping
public User create(@Body User user) {
return userService.save(user);
}
}关键差异:Context 替代 Servlet API
Solon 不依赖 Servlet 容器,因此 `HttpServletRequest` / `HttpServletResponse` 需替换为 `Context`:
// Spring 写法
public User get(HttpServletRequest request) {
String token = request.getHeader("Token");
String id = request.getParameter("id");
}
// Solon 写法
public User get(Context ctx) {
String token = ctx.header("Token");
String id = ctx.param("id");
// ctx.redirect(url) 重定向
// ctx.render(obj) 渲染
// ctx.remoteIp() 客户端 IP
}⚠️ `Context` 只能在方法参数中注入,不能作为字段注入。
配置文件迁移
文件命名
项目 | Spring Boot | Solon
---|---|---
主配置文件 | `application.yml` | `app.yml`
环境配置文件 | `application-dev.yml` | `app-dev.yml`
激活方式 | `spring.profiles.active=dev` | `solon.env=dev`
常用配置键名对照
含义 | Spring Boot | Solon
---|---|---
应用名 | `spring.application.name` | `solon.app.name`
端口 | `server.port` | `server.port`(不变)
上下文路径 | `server.servlet.context-path` | `server.contextPath`
数据源 | `spring.datasource.url` | `solon.dataSources.db1.url`
日志级别 | `logging.level.com.xx` | `solon.logging.level.com.xx`
环境切换 | `spring.profiles.active` | `solon.env`
⚠️ Solon 配置键名统一使用驼峰命名(`contextPath`),不是短横线(`context-path`)。
数据访问:@Db 一站式注入
多数据源配置(YAML)
solon.dataSources:
db1:
class: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost/test
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: 123456
db2:
url: jdbc:mysql://localhost/order
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: 123456@Db 注入
// Solon 一行搞定多数据源
@Db("db1") UserMapper userMapper;
@Db("db2") OrderMapper orderMapper;对比 Spring Boot 多数据源需要配置:多个 `DataSource` + 多个 `SqlSessionFactory` + 多个 `TransactionManager` + `@MapperScan`... Solon 使用 `@Db`。
ORM 集成
ORM | Spring Boot 依赖 | Solon 依赖
---|---|---
MyBatis | `mybatis-spring-boot-starter` | `mybatis-solon-plugin`
MyBatis-Plus | `mybatis-plus-spring-boot-starter` | `mybatis-plus-solon-plugin`
JPA | `spring-boot-starter-data-jpa` | `solon-data-jpa`
Easy-Query | `easy-query-spring-boot-starter` | `easy-query-solon-plugin`
事务
Solon | Spring Boot | 说明
---|---|---
`@Transaction` | `@Transactional` | 声明式事务
`@Transaction(policy = TranPolicy.requires_new)` | `@Transactional(propagation = Propagation.REQUIRES_NEW)` | 事务传播策略
Solon 的 `@Transaction` 默认遇到任何异常都回滚,无需指定异常类型。
测试迁移
Solon | Spring Boot | 说明
---|---|---
`@SolonTest(App.class)` | `@SpringBootTest` | 测试启动
`@SolonTest(env="test")` | `@ActiveProfiles("test")` | 测试环境
`HttpTester` | `MockMvc` | HTTP 接口测试
`@Rollback` | `@Transactional` + `@Rollback` | 事务回滚
`@Import(profiles=...)` | `@TestPropertySource` | 导入测试属性
HttpTester 用法示例:
@SolonTest(App.class)
public class UserControllerTest extends HttpTester {
@Test
public void testGetUser() {
// GET 请求
String resp = path("/users/1").get();
assertEquals(200, resp.code());
// POST 请求
String json = "{\"name\":\"test\"}";
String resp2 = path("/users").body(json).post();
assertContains(resp2, "test");
}
}其他常见对照
场景 | Spring Boot | Solon
---|---|---
拦截器 | `HandlerInterceptor` | `@Around` 注解或 Solon Filter
定时任务 | `@Scheduled` | `@Scheduled`(同名)+ `@EnableScheduling`
文件上传 | `MultipartFile` | `UploadedFile`(用法一致)
RPC 调用 | `@FeignClient` | `@NamiClient`
注册发现 | `@EnableDiscoveryClient` | 无需注解 ,引入插件自动生效
配置刷新 | `@RefreshScope` | 无需注解 ,配置变更自动感知
迁移检查清单
- POM:`spring-boot-starter-parent` -> `solon-parent`
- POM:`spring-boot-starter-*` -> `solon-*` / `*-solon-plugin`
- 配置:`application.yml` -> `app.yml`(环境文件同理)
- 启动类:`@SpringBootApplication` -> `@SolonMain`
- 启动:`SpringApplication.run()` -> `Solon.start()`
- IoC:`@Autowired` -> `@Inject`
- IoC:`@Service`/`@Repository` -> `@Component`
- Web:`@RestController` -> `@Controller`
- Web:`@RequestMapping` -> `@Mapping`
- Web:`@PathVariable` -> `@Path`
- Web:`HttpServletRequest` -> `Context`
- 配置:`@Value` -> `@Inject("${...}")`
- 数据:`spring.datasource.*` -> `solon.dataSources.*`
- 数据:`@Transactional` -> `@Transaction`
- 测试:`@SpringBootTest` -> `@SolonTest`
- 测试:`MockMvc` -> `HttpTester`
写在最后
这篇对照表覆盖了日常开发中最常用的 90% 场景。Solon 的注解体系并非简单的"换皮",它在统一性(`@Component` / `@Inject` / `@Condition`)和简便性(`@Db` / 无需 `@RefreshScope`)上做了明显的设计取舍。建议迁移前先通读一遍官方对比文档。如有具体的迁移场景未覆盖,欢迎在评论区留言。

被折叠的 条评论
为什么被折叠?



