经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
Solon2 与 Spring Boot 的区别
来源:cnblogs  作者:带刺的坐椅  时间:2023/3/3 8:54:48  对本文有异议

1、与 Springboot 的常用注解比较

Solon 2.2.0 Springboot 2.7.8 说明
@Inject * @Autowired 注入Bean(by type)
@Inject("name") @Qualifier+@Autowired 注入Bean(by name)
@Inject("${name}") @Value("${name}") 注入配置
@Singleton @Scope(“singleton”) 单例(Solon 默认是单例)
@Singleton(false) @Scope(“prototype”) 非单例
@Import @Import + @ComponentScan 配置组件导入或扫描(一般加在启动类上)
@PropertySource @PropertySource 配置属性源(一般加在启动类上)
@Configuration @Configuration 配置类
@Bean @Bean 配置Bean
@Condition @ConditionalOnClass + @ConditionalOnProperty 配置条件
@Controller @Controller,@RestController 控制器类
@Remoting 远程控制器类(即 Rpc 服务端)
@Mapping ... @RequestMapping,@GetMapping... 映射
@Param @RequestParam 请求参数
@Header @RequestHeader 请求头
@Body @RequestBody 请求体
@Cookie @CookieValue 请求Cookie
@Component @Component 普通托管组件
@ProxyComponent @Service,@Dao,@Repository 代理托管组件
@Init * @PostConstruct 组件构造完成并注入后的初始化
@TestPropertySource @TestPropertySource 配置测试属性源
@TestRollback @TestRollback 执行测试回滚
  • Solon 的 @Inject 算是: Spring 的@Value、@Autowired、@Qualifier 三者的结合,但又不完全等价
  • Solon 的 @Import 同时有导入和扫描的功能
  • Solon 的 Bean 生命周期:new() - > @Inject -> afterInjection()- > start() -> stop()
  • 注1:Method@Bean,只执行一次(只在 @Configuration 里有效)
  • 注2:@Inject 的参数注入,只在 Method@Bean 上有效
  • 注3:@Inject 的类注入,只在 @Configuration类 上有效
  • 注4:@Import 只在 主类上 或者 @Configuration类 上有效

2、重要的区别,Solon 不是基于 Servlet 的开发框架

  • 与 Springboot 相似的体验,但使用 Context 包装请求上下文(底层为:Context + Handler 架构)。Helloworld 效果:
  1. @SolonMain
  2. public class App{
  3. public static void main(String[] args){
  4. Solon.start(App.class, args);
  5. }
  6. }
  7. @Controller
  8. public class Demo{
  9. @Inject("${app.name}")
  10. String appName;
  11. @Mapping("/")
  12. public Object home(String name){
  13. return appName + ": Hello " + name;
  14. }
  15. }
  • 与 Servlet 常见类比较
Solon 2.2.0 Springboot 2.7.8 说明
Context HttpServletRequest + HttpServletResponse 请求上下文
SessionState HttpSession 请求会话状态类
UploadedFile MultipartFile 文件上传接收类
DownloadedFile 文件下载输出类
ModelAndView ModelAndView 模型视图输出类
  • Solon 适配有:jdkhttp、jlhttp、smarthttp、jetty、undertow、netty、websocket 等各种通讯容器。

3、Solon 不支持构造函数注入与属性设置注入

  • 不支持的:
  1. @Component
  2. public class Demo{
  3. private A a;
  4. private B b;
  5. public Demo(@Inject A a){
  6. this.a = a;
  7. }
  8. public void setB(@Inject B b){
  9. this.b = b;
  10. }
  11. }
  • 支持的:
  1. @Component
  2. public class Demo{
  3. @Inject
  4. private A a;
  5. @Inject
  6. private B b;
  7. //@Init
  8. //public void initDo(){
  9. // //Solon 的注入是异步的。想要对注入的 bean 进行实始化,需要借用 @Init 函数
  10. //}
  11. }

或者,可以用 @Configuration + @Bean 进行构建。

4、Solon 可以更自由获取配置

  1. @Component
  2. public class Demo{
  3. //注入配置
  4. @Inject("${user.name}")
  5. private String userName;
  6. //手动获取配置
  7. private String userName = Solon.cfg().get("user.name");
  8. }

5、Solon 的 @Component 与 @ProxyComponent 是有区别的

  • @Component 注解的组件,不会被动态代理
    • 不支持拦截处理
    • 支持函数被注解提取
    • 支持形态提取
  • @ProxyComponent 注解的组件,会被动态代理。由 solon.proxy 提供能力实现
    • 支持拦截处理

各有分工,算有是“克制”的体现。

6、与 Springboot 相似的事务支持 @Tran

  • 采用 Springboot 相同的事件传播机制及隔离级别。但回滚时,不需要指定异常类型
  1. @Controller
  2. public class DemoController{
  3. @Db
  4. BaseMapper<UserModel> userService;
  5. @Tran
  6. @Mapping("/user/update")
  7. public void udpUser(long user_id, UserModel user){
  8. userService.updateById(user);
  9. }
  10. }

7、与 Springboot 不同的较验方案 @Valid

  • Solon 的方案更侧重较验参数(及批量较验),且强调可见性(即与处理函数在一起)。同时也支持实体的较验
  1. @Valid
  2. @Controller
  3. public class DemoController {
  4. @NoRepeatSubmit
  5. @NotNull({"name", "icon", "mobile"})
  6. @Mapping("/valid")
  7. public String test(String name, String icon, @Pattern("13\\d{9}") String mobile) {
  8. return "OK";
  9. }
  10. @Whitelist
  11. @Mapping("/valid/test2")
  12. public String test2() {
  13. return "OK";
  14. }
  15. @Mapping("/valid/test3")
  16. public String test3(@Validated UserModel user) {
  17. return "OK";
  18. }
  19. }

8、基于标签管理的缓存支持 @Cache,与 Springboot 略有不同

  • 支持Key的缓存管理。同时增加了基于标签的缓存管理,避免不必要的Key冲突
  1. @Controller
  2. public class DemoController{
  3. @Db
  4. BaseMapper<UserModel> userService;
  5. @CacheRemove(tags = "user_${user_id}")
  6. @Mapping("/user/update")
  7. public void udpUser(int user_id, UserModel user){
  8. userService.updateById(user);
  9. }
  10. @Cache(tags = "user_${user_id}")
  11. public UserModel getUser(int user_id){
  12. return userService.selectById(user_id);
  13. }
  14. }

9、相似的 @Bean 设计

  • 相似的特性。且,需与 @Configuration 协同使用
  1. //
  2. // 一个数据主从库的示例
  3. //
  4. @Configuration
  5. public class Config {
  6. @Bean(name = "db1", typed = true)
  7. public DataSource db1(@Inject("${test.db1}") HikariDataSource dataSource) {
  8. return dataSource;
  9. }
  10. @Bean("db2")
  11. public DataSource db2(@Inject("${test.db2}") HikariDataSource dataSource) {
  12. return dataSource;
  13. }
  14. }
  • 使用 @Bean(typed=true) 做为某种类型的默认Bean

10、支持数据渲染(或输出格式化)的自我控制支持

  • 定制特定场景的控制器基类,负责统一格式化输出
  1. //示例:定制统一输出控制基类,并统一开启验证
  2. //
  3. @Valid
  4. public class ControllerBase implements Render {
  5. @Override
  6. public void render(Object obj, Context ctx) throws Throwable {
  7. if (obj == null) {
  8. return;
  9. }
  10. if (obj instanceof String) {
  11. ctx.output((String) obj);
  12. } else {
  13. if (obj instanceof ONode) {
  14. ctx.outputAsJson(((ONode) obj).toJson());
  15. } else {
  16. if (obj instanceof UapiCode) {
  17. //此处是重点,把一些特别的类型进行标准化转换
  18. //
  19. UapiCode err = (UapiCode) obj;
  20. obj = Result.failure(err.getCode(), UapiCodes.getDescription(err));
  21. }
  22. if (obj instanceof Throwable) {
  23. //此处是重点,把异常进行标准化转换
  24. //
  25. Throwable err = (Throwable) obj;
  26. obj = Result.failure(err.getMessage());
  27. }
  28. ctx.outputAsJson(ONode.stringify(obj));
  29. }
  30. }
  31. }
  32. }

11、不基于 Servlet,却很有 Servlet 亲和度。当使用 servlet 相关的组件时(也支持jsp + tld)

  • 支持 Servlet 请求与响应对象注入
  1. @Mapping("/demo/")
  2. @Controller
  3. public class DemoController {
  4. @Mapping("hello")
  5. public void hello(HttpServletRequest req, HttpServletResponse res){
  6. }
  7. }
  • 支持 ServletContainerInitializer 配置
  1. @Configuration
  2. public class DemoConfiguration implements ServletContainerInitializer{
  3. @Override
  4. public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
  5. //...
  6. }
  7. }
  • 支持 Servlet api 注解
  1. @WebFilter("/demo/*")
  2. public class DemoFilter implements Filter {
  3. @Override
  4. public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
  5. res.getWriter().write("Hello,我把你过滤了");
  6. }
  7. }

12、为服务开发而生的 SockeD 组件,实现 http, socket, websocket 相同的信号处理。

  • 支持 MVC+RPC 开发模式
  1. //[服务端]
  2. @Socket
  3. @Mapping("/demoe/rpc")
  4. @Remoting
  5. public class HelloRpcServiceImpl implements HelloRpcService {
  6. public String hello(String name) {
  7. return "name=" + name;
  8. }
  9. }
  10. //[客户端]
  11. var rpc = SocketD.create("tcp://localhost:28080", HelloRpcService.class);
  12. System.out.println("RPC result: " + rpc.hello("noear"));
  • 支持单链接双向 RPC 开发模式(基于上例扩展)
  1. //[服务端]
  2. @Socket
  3. @Mapping("/demoe/rpc")
  4. @Remoting
  5. public class HelloRpcServiceImpl implements HelloRpcService {
  6. public String hello(String name) {
  7. //
  8. //[服务端] 调用 [客户端] 的 rpc,从而形成单链接双向RPC
  9. //
  10. NameRpcService rpc = SocketD.create(Context.current(), NameRpcService.class);
  11. name = rpc.name(name);
  12. return "name=" + name;
  13. }
  14. }
  • 支持消息发送+监听开发模式
  1. //[服务端]
  2. @ServerEndpoint
  3. public class ServerListener implements Listener {
  4. @Override
  5. public void onMessage(Session session, Message message) {
  6. if(message.flag() == MessageFlag.heartbeat){
  7. System.out.println("服务端:我收到心跳");
  8. }else {
  9. System.out.println("服务端:我收到:" + message);
  10. //session.send(Message.wrapResponse(message, "我收到了"));
  11. }
  12. }
  13. }
  14. //[客户端]
  15. var session = SocketD.createSession("tcp://localhost:28080");
  16. session.send("noear");
  17. //session.sendAndCallback("noear", (rst)->{}); //发送并异步回调
  18. //var rst = session.sendAndResponse("noear"); //发送并等待响应
  19. System.out.println(rst);
  • 支持消息订阅开发模式
  1. //[客户端]
  2. @ClientEndpoint(uri = "tcp://localhost:28080")
  3. public class ClientListener implements Listener {
  4. @Override
  5. public void onMessage(Session session, Message message) {
  6. //之后,就等着收消息
  7. System.out.println("客户端2:我收到了:" + message);
  8. }
  9. }

13、专属 Rpc 客户端组件:Nami

  • 类似于 Springboot + Feign 的关系,但 Nami 更简洁且支持 socket 通道( Solon 也可以用 Feign )
  1. //[定义接口],一般情况下不需要加任何注解
  2. //
  3. public interface UserService {
  4. UserModel getUser(Integer userId);
  5. }
  6. //[服务端] @Remoting,即为远程组件
  7. //
  8. @Mappin("user")
  9. @Remoting
  10. public class UserServiceImpl implements UserService{
  11. public UserModel getUser(Integer userId){
  12. return ...;
  13. }
  14. }
  15. //[消费端]
  16. //
  17. @Mapping("demo")
  18. @Controller
  19. public class DemoController {
  20. //直接指定服务端地址
  21. @NamiClient("http://localhost:8080/user/")
  22. UserService userService;
  23. //使用负载
  24. @NamiClient(name="local", path="/user/")
  25. UserService userService2;
  26. @Mapping("test")
  27. public void test() {
  28. UserModel user = userService.getUser(12);
  29. System.out.println(user);
  30. user = userService2.getUser(23);
  31. System.out.println(user);
  32. }
  33. }
  34. /**
  35. * 定义一个负载器(可以对接发现服务)
  36. * */
  37. @Component("local")
  38. public class RpcUpstream implements LoadBalance {
  39. @Override
  40. public String getServer() {
  41. return "http://localhost:8080";
  42. }
  43. }

14、Solon 的加强版 Spi 扩展机制 - 具备可编程性

  • 新建模块,并实现Plugin接口(以增加 @ProxyComponent 注解支持为例)
  1. public class XPluginImp implements Plugin {
  2. @Override
  3. public void start(AopContext context) {
  4. context.beanBuilderAdd(ProxyComponent.class, (clz, bw, anno) -> {
  5. BeanProxy.binding(bw);
  6. });
  7. }
  8. }
  • 增加配置文件
  1. src/main/resources/META-INF/solon/solon.aspect.properties
  • 增加配置内容,打包发布即可
  1. solon.plugin=org.noear.solon.aspect.XPluginImp

15、Solon 内部的事件总线 EventBus 的妙用

  • 通过事件总线收集异常
  1. //[收集异常](不建议业务使用)
  2. EventBus.push(err);
  3. //[订阅异常]
  4. EventBus.subscribe(Throwable.class,(event)->{
  5. event.printStackTrace();
  6. });
  7. //或通过SolonApp订阅
  8. app.onEvent(Throwable.class, (err)->{
  9. err.printStackTrace();
  10. });
  11. //或通过组件订阅
  12. @Component
  13. public class ErrorListener implements EventListener<Throwable> {
  14. @Override
  15. public void onEvent(Throwable err) {
  16. err.printStackTrace();
  17. }
  18. }
  • 通过事件总线扩展配置对象
  1. //
  2. // 插件开发时,较常见
  3. //
  4. SqlManagerBuilder builder = new SqlManagerBuilder(ds);
  5. EventBus.push(builder);

16、Aop 扩展,扫描一次 + 注册处理(也是启动快的原因之一)

  • 注册‘构建器’处理。以注册 @Controller 构建器为例:
  1. Solon.context().beanBuilderAdd(Controller.class, (clz, bw, anno) -> {
  2. //内部实现,可参考项目源码 //构建器,可以获取类型并进行加工
  3. new HandlerLoader(bw).load(Solon.global());
  4. });
  5. //效果
  6. @Controller
  7. public class DemoController{
  8. }
  • 注册'注入器'处理。以注册 @Inject 注入器为例:
  1. Solon.context().beanInjectorAdd(Inject.class, ((fwT, anno) -> {
  2. //内部实现,可参考项目源码 //注入器,可以根据目标生成需要的数据并赋值
  3. beanInject(fwT, anno.value(), anno.autoRefreshed());
  4. }));
  5. //效果
  6. @Controller
  7. public class DemoController{
  8. @Inject
  9. UserService userService;
  10. }
  • 注册'拦截器'处理。以注册 @Tran 拦截器为例:
  1. //拦截器,可以获取执行动作链
  2. Solon.context().beanAroundAdd(Tran.class, new TranInterceptor(), 120);
  3. //效果
  4. @ProxyComponent
  5. public class UserService{
  6. @Tran
  7. public void addUser(User user){
  8. }
  9. }
  • 注册'提取器'处理。以注册 @CloudJob 提取器为例:
  1. //内部实现,可参考项目源码 //提取器,可以提取被注解的函数
  2. Solon.context().beanExtractorAdd(CloudJob.class, CloudJobExtractor.instance);
  3. //效果 //提取器只对组件有效
  4. @Component
  5. public class Job{
  6. @CloudJob
  7. public void statUserJob(){
  8. }
  9. }

原文链接:https://www.cnblogs.com/noear/p/17170438.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号