与 Spring Boot 的区别
前言
这里是指 Solon 生态与 SpringBoot 生态的比较。而非 Solon-Boot(仅是模块) 与 SpringBoot 生态。
Solon-Boot
Solon-Boot 仅表示 Solon 的 “服务端“ 启动模块组(相当于 Solon server bootstrap)。它是个 “功能性” 模块划分概念,跟 Solon-Data,Solon-Net,Solon-Serialization 性质相当。比如:
- solon-boot-jdkhttp,意为启动 jdkhttp-server
- solon-boot-smarthttp,意为启动 smarthttp-server
- solon-boot-jetty,意为启动 jetty-server
- solon-boot-websocket,意为启动 websocket-server
- solon-boot-socketd,意为启动 socketd-server
SpringBoot
SpringBoot 则不同。它表示 Spring 的引导程序(相当于 Spring bootstrap),让 Spring 更方便的使用。它是个架构层次进化概念,相当于让 Spring 上升了一个层次。直接使用 Spring 会比较麻烦的。(来自网络搜索)
1、与 Springboot 的常用注解比较
Solon 3.0.3 | Springboot 2.7.16 / 3.3.2 | 说明 |
---|---|---|
@Inject * | @Autowired | 注入Bean(by type) |
@Inject("name") | @Qualifier+@Autowired | 注入Bean(by name) |
@Inject("${name}") | @Value("${name}") + @ConfigurationProperties(prefix="name") | 注入配置 |
@Singleton | @Scope(“singleton”) | 单例(Solon 默认是单例) |
@Singleton(false) | @Scope(“prototype”) | 非单例 |
@Import | @Import + @ComponentScan | 导入组件(一般加在启动类上) |
@Import | @PropertySource | 导入属性源(一般加在启动类上) |
@Configuration | @Configuration | 配置类 |
@Bean | @Bean | 配置Bean |
@Condition | @ConditionalOnClass + @ConditionalOnProperty ... | 配置条件 |
@Component | @Component,@Service,@Dao,@Repository | 托管组件 |
@Import | @TestPropertySource | 导入测试属性源 |
@Rollback | @TestRollback | 执行测试回滚 |
LifecycleBean | InitializingBean + DisposableBean | 组件初始化和销毁 |
Solon 3.0.3 | Java EE / Jakarta | |
LifecycleBean::start 或 @Init 注解 | @PostConstruct | 组件初始化 |
LifecycleBean::stop 或 @Destroy 注解 | @PreDestroy | 组件销毁 |
- 注1:Method@Bean,只执行一次(只在 @Configuration 里有效)
- 注2:@Inject 的参数注入,只在 Method@Bean 和 Constructor 上有效
- 注3:@Inject 的类注入,只在 @Configuration类 上有效
- 注4:@Import 只在 启动类上 或者 @Configuration类 上有效
2、与 Springboot 组件的差别
- 动态代理
Solon 只对组件的 public 函数进行代理
- 容器注册
Springboot 默认会自动按类名作为 name 进行注册。Solon 需要配置 name 才会按名字注册(才能按名字获取)。
3、与 Spring Mvc 的比较
- 注解方面的区别
Solon 3.0.3 | Springboot 2.7.16 / 3.3.2 | 说明 |
---|---|---|
@Controller | @Controller,@RestController | 控制器类 |
@Remoting | 远程控制器类(即 Rpc 服务端) | |
@Mapping | @RequestMapping,@GetMapping... | 映射(并不完全对等) |
@Param | @RequestParam | 请求参数(并不完全对等) |
@Header | @RequestHeader | 请求头 |
@Body | @RequestBody | 请求体(并不完全对等) |
@Cookie | @CookieValue | 请求小饼 |
@Path | @PathVariable | 请求路径变量 |
@Produces | / | 申明输出内容类型 |
@Consumes | / | 申明输入内容类型 |
- 映射的区别
Solon 的 @Mapping
函数不支持多路径的映射,且只限 public 函数。但是可以通过“本地网关”,为一批 action 添加不同的地址前缀。
- 控制器继承的区别
Solon 控制器继承时,支持基类的 @Mapping
public 函数
4、重要的区别,Solon 不是基于 Servlet 的开发框架
- 与 Springboot 相似的体验,但使用 Context 包装请求上下文(底层为:Context + Handler 架构)。Helloworld 效果:
@SolonMain
public class App{
public static void main(String[] args){
Solon.start(App.class, args);
}
}
@Controller
public class Demo{
@Inject("${app.name}")
String appName;
@Mapping("/")
public Object home(String name){
return appName + ": Hello " + name;
}
}
- 与 Servlet 常见类比较
Solon 3.0.3 | Springboot 2.7.16 / 3.3.2 | 说明 |
---|---|---|
Context | HttpServletRequest + HttpServletResponse | 请求上下文 |
SessionState | HttpSession | 请求会话状态类 |
UploadedFile | MultipartFile | 文件上传接收类 |
DownloadedFile | 文件下载输出类 | |
ModelAndView | ModelAndView | 模型视图输出类 |
- Solon 适配有:jdkhttp、jlhttp、smarthttp、jetty、undertow、vert.x、netty、websocket 等各种通讯容器。
5、Solon 不支持属性设置注入
- 不支持的:
@Component
public class DemoCom {
private B b;
public void setB(@Inject B b){
this.b = b;
}
}
- 支持的(字段,或构造器参数,或小豆方法参数):
@Component
public class DemoCom {
private final A a;
@Inject
private B b;
public Demo(A a){
this.a = a;
}
}
@Configuration
public class DemoConfig{
@Bean
public void a(A a) {
//...
}
}
6、Solon 可以更自由获取配置
@Component
public class Demo{
//注入配置
@Inject("${user.name}")
private String userName;
//手动获取配置
private String userName = Solon.cfg().get("user.name");
}
7、Solon 配置注给结构体
- 相当于
@ConfigurationProperties
的效果
@Inject("${user.config}")
@Configuration
public class UserConfig{
public String name;
public List<String> tags;
...
}
//别处可以注入复用
@Inject
UserConfig userConfig;
8、与 Springboot 相似的事务支持 @Tran
- 采用 Springboot 相同的事件传播机制及隔离级别。但回滚时,不需要指定异常类型
@Controller
public class DemoController{
@Db
BaseMapper<UserModel> userService;
@Tran
@Mapping("/user/update")
public void udpUser(long user_id, UserModel user){
userService.updateById(user);
}
}
9、与 Springboot 不同的较验方案 @Valid
- Solon 的方案多了“批量参数较验”,且强调“可见性”(即与处理函数在一起)。同时也支持实体的较验
@Valid
@Controller
public class DemoController {
@NoRepeatSubmit
@NotNull({"name", "icon", "mobile"}) //在函数这边,可见性更好 //不过显得乱
@Mapping("/valid")
public String test(String name, String icon, @Pattern("13\\d{9}") String mobile) {
return "OK";
}
@Whitelist
@Mapping("/valid/test2")
public String test2() {
return "OK";
}
@Mapping("/valid/test3")
public String test3(@Validated UserModel user) {
return "OK";
}
}
10、基于标签管理的缓存支持 @Cache,与 Springboot 略有不同
- 支持Key的缓存管理。同时增加了基于“标签”的缓存管理,避免不必要的Key冲突
@Controller
public class DemoController{
@Db
BaseMapper<UserModel> userService;
@CacheRemove(tags = "user_${user_id}")
@Mapping("/user/update")
public void udpUser(int user_id, UserModel user){
userService.updateById(user);
}
@Cache(tags = "user_${user_id}")
public UserModel getUser(int user_id){
return userService.selectById(user_id);
}
}
11、相似的 @Bean 设计
- 相似的特性,但可以返回 void。且,需与 @Configuration 协同使用
//
// 一个数据主从库的示例
//
@Configuration
public class Config {
@Bean(name = "db1", typed = true)
public DataSource db1(@Inject("${test.db1}") HikariDataSource dataSource) {
return dataSource;
}
@Bean("db2")
public DataSource db2(@Inject("${test.db2}") HikariDataSource dataSource) {
return dataSource;
}
}
- 使用 @Bean(typed=true) 做为某种类型的默认Bean
12、不基于 Servlet,却很有 Servlet 亲和度。当使用 servlet 相关的组件时(也支持jsp + tld)
- 支持 Servlet 请求与响应对象注入
@Mapping("/demo/")
@Controller
public class DemoController {
@Mapping("hello")
public void hello(HttpServletRequest req, HttpServletResponse res){
//...
}
}
- 支持 ServletContainerInitializer 配置
@Configuration
public class DemoConfiguration implements ServletContainerInitializer{
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
//...
}
}
- 支持 Servlet api 注解
@WebFilter("/demo/*")
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
res.getWriter().write("Hello,我把你过滤了");
}
}
13、专属 Rpc 客户端组件:Nami
- 类似于 Springboot + Feign 的关系,但 Nami 更简洁且支持 socket 通道( Solon 也可以用 Feign )
//[定义接口],一般情况下不需要加任何注解
//
public interface UserService {
UserModel getUser(Integer userId);
}
//[服务端] @Remoting,即为远程组件
//
@Mappin("user")
@Remoting
public class UserServiceImpl implements UserService{
public UserModel getUser(Integer userId){
return ...;
}
}
//[消费端]
//
@Mapping("demo")
@Controller
public class DemoController {
//直接指定服务端地址
@NamiClient("http://localhost:8080/user/")
UserService userService;
//使用负载均衡
@NamiClient(name="local", path="/user/")
UserService userService2;
@Mapping("test")
public void test() {
UserModel user = userService.getUser(12);
System.out.println(user);
user = userService2.getUser(23);
System.out.println(user);
}
}
/**
* 定义一个负载器(可以对接发现服务)
* */
@Component("local")
public class RpcUpstream implements LoadBalance {
@Override
public String getServer() {
return "http://localhost:8080";
}
}
14、Solon 的加强版 Spi 扩展机制 - 具备可编程性
- 新建模块,并实现Plugin接口(以增加 @AuthLogined 注解支持为例)
public class XPluginImpl implements Plugin {
@Override
public void start(AppContext context) {
context.beanInterceptorAdd(AuthLogined.class, new LoginedInterceptor());
}
}
- 增加配置文件
src/main/resources/META-INF/solon/solon.auth.properties
- 增加配置内容,打包发布即可
solon.plugin=org.noear.solon.auth.integration.XPluginImp
15、Ioc/Aop 扩展, 提前注册 + 扫描一次(也是启动快的原因之一)
- 注册‘构建器’处理。以注册 @Controller 构建器为例:
Solon.context().beanBuilderAdd(Controller.class, (clz, bw, anno) -> {
//内部实现,可参考项目源码 //构建器,可以获取类型并进行加工
new HandlerLoader(bw).load(Solon.global());
});
//效果
@Controller
public class DemoController{
}
- 注册'注入器'处理。以注册 @Inject 注入器为例:
Solon.context().beanInjectorAdd(Inject.class, ((fwT, anno) -> {
//内部实现,可参考项目源码 //注入器,可以根据目标生成需要的数据并赋值
beanInject(fwT, anno.value(), anno.autoRefreshed());
}));
//效果
@Controller
public class DemoController{
@Inject
UserService userService;
}
- 注册'拦截器'处理。以注册 @Tran 拦截器为例:
//拦截器,可以获取执行动作链
Solon.context().beanInterceptorAdd(Tran.class, new TranInterceptor(), 120);
//效果
@Component
public class UserService{
@Tran
public void addUser(User user){
}
}
- 注册'提取器'处理。以注册 @CloudJob 提取器为例:
//内部实现,可参考项目源码 //提取器,可以提取被注解的函数
Solon.context().beanExtractorAdd(CloudJob.class, CloudJobExtractor.instance);
//效果 //提取器只对组件有效
@Component
public class Job{
@CloudJob
public void statUserJob(){
}
}