{"id":15159291,"url":"https://github.com/blanexie/yao","last_synced_at":"2026-01-24T23:01:16.701Z","repository":{"id":43848724,"uuid":"255073700","full_name":"blanexie/Yao","owner":"blanexie","description":"一个依赖注入的框架， 整合netty 提供类似springMvc的能力。 整合mybatis提供类似mybatis-spring的能力。","archived":false,"fork":false,"pushed_at":"2022-09-08T01:11:29.000Z","size":866,"stargazers_count":2,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-19T19:38:36.157Z","etag":null,"topics":["hutool","java","mybatis","netty"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blanexie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-12T12:05:00.000Z","updated_at":"2021-06-21T07:16:52.000Z","dependencies_parsed_at":"2022-08-31T08:41:53.477Z","dependency_job_id":null,"html_url":"https://github.com/blanexie/Yao","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/blanexie/Yao","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blanexie%2FYao","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blanexie%2FYao/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blanexie%2FYao/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blanexie%2FYao/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blanexie","download_url":"https://codeload.github.com/blanexie/Yao/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blanexie%2FYao/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28738979,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T22:12:27.248Z","status":"ssl_error","status_checked_at":"2026-01-24T22:12:10.529Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hutool","java","mybatis","netty"],"created_at":"2024-09-26T21:02:40.366Z","updated_at":"2026-01-24T23:01:15.850Z","avatar_url":"https://github.com/blanexie.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"@[TOC](目录)\n# [Yao框架](https://github.com/blanexie/Yao)\n\u003e 每次看spring的源码都是难以看进去， 但是平时都会通过各种各样的博客文章中大致理解了spring的基本原理。 同时我也萌生了自己实现一个类似框架的想法，于是便有了这个项目。虽然是重复造轮子，但是写这个项目的过程中我对于spring的实现也有了更深的了解吧。\n\n\u003e 虽然我只是无人气的小博主， 但是我还是在我的在这里推下我的框架，因为梦想还是要有的，万一这个框架哪天火了呢!\n\n[博客地址](https://blog.csdn.net/leisurelen/article/details/106265817) ： https://blog.csdn.net/leisurelen/article/details/106265817\n\n**本项目使用的是java11版本的基础上开发，不能保证在小于java11的版本上能正常运行 ** \n\n\n想学习spring的，又难以看进去源码的， 可以看看我的这个项目， \n  欢迎star和留言。有疑问请留言， 我很乐意与你们一起探讨技术问题。 这个项目我会坚持更新的，希望大家能给与我支持。 \n## 项目地址\n[https://github.com/blanexie/Yao](https://github.com/blanexie/Yao)\n\n\n##  使用示例\n\n可以参照我的项目源码中的example模块来使用\n\n\u003e 说明除了下面示例的方式， 还可以使用FactoryBean接口和@Bean注解方法的方式将bean放入容器中\n\n### 导入maven包\n\n```xml\n\u003c!-- 依赖注入的核心包， 提供基本的依赖注入功能  --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003exyz.xiezc\u003c/groupId\u003e\n    \u003cartifactId\u003exioc\u003c/artifactId\u003e\n    \u003cversion\u003e2.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```xml\n\u003c!--  整合mybatis的包  --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003exyz.xiezc\u003c/groupId\u003e\n    \u003cartifactId\u003exorm\u003c/artifactId\u003e\n    \u003cversion\u003e2.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```xml\n\u003c!--  数据源链接池  --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003emysql\u003c/groupId\u003e\n    \u003cartifactId\u003emysql-connector-java\u003c/artifactId\u003e\n    \u003cversion\u003e8.0.20\u003c/version\u003e\n \u003c/dependency\u003e\n \u003cdependency\u003e\n  \u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n  \u003cartifactId\u003edruid\u003c/artifactId\u003e\n     \u003cversion\u003e1.1.22\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```xml\n\u003c!--  整合netty的包, 提供了基本的http能力和websocket支持  --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003exyz.xiezc\u003c/groupId\u003e\n    \u003cartifactId\u003exweb\u003c/artifactId\u003e\n    \u003cversion\u003e2.2\u003c/version\u003e\n\u003c/dependency\u003e\n\n```\n\n### 定义一个启动类\n\n```java\npackage xyz.xiezc.example;\n\n\nimport xyz.xiezc.ioc.starter.Xioc;\nimport xyz.xiezc.ioc.starter.annotation.Configuration;\nimport xyz.xiezc.ioc.starter.annotation.Cron;\nimport xyz.xiezc.ioc.starter.annotation.EnableCron;\nimport xyz.xiezc.ioc.starter.orm.annotation.MapperScan;\n\nimport java.time.LocalTime;\n\n@MapperScan({\"xyz.xiezc.example.web.mapper\"})  //扫描mapper包\n@Configuration\n@EnableCron  //启用定时任务\npublic class Application {\n\n    /**\n     * 每3秒执行一次。\u003cbr\u003e\n     * 表达式每部分的意思如下：\n     * 秒 分 时 日 月 星期\n     */\n    @Cron(\"*/3 * * * * *\")\n    public void cronTest() {\n        System.out.println(\"定时任务执行: \" + LocalTime.now());\n    }\n\n    public static void main(String[] args) {\n        Xioc.run(Application.class);\n    }\n}\n\n```\n\n###  定义一个Controller放入容器中\n\n```java\npackage xyz.xiezc.example.web.controller;\n\nimport cn.hutool.json.JSONUtil;\nimport xyz.xiezc.example.web.common.TestAopspect;\nimport xyz.xiezc.example.web.entity.Album;\nimport xyz.xiezc.example.web.mapper.AlbumMapper;\nimport xyz.xiezc.example.web.service.TestService;\nimport xyz.xiezc.ioc.starter.annotation.Aop;\nimport xyz.xiezc.ioc.starter.annotation.Inject;\nimport xyz.xiezc.ioc.starter.orm.common.example.Example;\nimport xyz.xiezc.ioc.starter.starter.web.annotation.Controller;\nimport xyz.xiezc.ioc.starter.starter.web.annotation.GetMapping;\nimport xyz.xiezc.ioc.starter.starter.web.entity.WebContext;\n\nimport java.util.List;\nimport java.util.Map;\n\n@Aop(TestAopspect.class)\n@Controller(\"/\")\npublic class TestController {\n\n    @Inject\n    AlbumMapper albumMapper;\n  \t/**\n  \t *  支持list注入， 会将符合TestService类型的bean都注入到这个list中\n  \t*/\n    @Inject\n    TestService[] testServices;\n\n    @GetMapping(\"/get.json\")\n    public String get() {\n        return testServices.length + \"\";\n    }\n\n    @GetMapping(\"/test.json\")\n    public String get(String param) {\n        WebContext webContext = WebContext.get();\n        //\n        Example build = Example.of(Album.class)\n                .andEqualTo(Album::getId, 3537) //支持类似mybatis-plus的lambda的使用方式\n                .build();\n        List\u003cAlbum\u003e albums = albumMapper.selectByExample(build);\n        //获取session信息\n        Map\u003cString, Object\u003e session = webContext.getSession();\n        session.put(\"param\", param);\n        return JSONUtil.toJsonStr(albums);\n    }\n}\n\n```\n\n### 定义一个实体类\n\n```java\nimport lombok.Data;\nimport Column;\nimport Id;\nimport Table;\n\nimport java.io.Serializable;\nimport java.time.LocalDateTime;\n\n@Data\n@Table(\"t_album\")\npublic class Album implements Serializable {\n    @Id\n    Integer id;\n    @Column\n    String title;\n    @Column\n    String publishTime;\n    @Column\n    String type;\n    @Column\n    LocalDateTime createTime;\n    @Column\n    Integer coverId;\n    @Column\n    Integer see;\n}\n```\n\n### 定义一个Mapper接口\n\n```java\nimport BaseMapper;\n/**\n* BaseMapper 中内置了很多的方法\n*/\npublic interface AlbumMapper extends BaseMapper\u003cAlbum\u003e {\n  \n}\n```\n\n### 定义一个websocket的controller\n\n```java\nimport io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;\nimport io.netty.handler.codec.http.websocketx.TextWebSocketFrame;\nimport io.netty.handler.codec.http.websocketx.WebSocketFrame;\nimport WebSockerController;\nimport WebSocketFrameHandler;\n\n@WebSockerController(\"/websocket\")\npublic class WebSocketHandler implements WebSocketFrameHandler {\n\n    @Override\n    public WebSocketFrame handleTextWebSocketFrame(TextWebSocketFrame textWebSocketFrame) {\n        String text = textWebSocketFrame.text();\n        TextWebSocketFrame textWebSocketFrame1 = new TextWebSocketFrame(\"resp:\" + text);\n        return textWebSocketFrame1;\n    }\n\n    @Override\n    public WebSocketFrame handleBinaryWebSocketFrame(BinaryWebSocketFrame binaryWebSocketFrame) {\n        return null;\n    }\n}\n\n```\n\n### 配置文件\n\n```properties\n### web服务的端口\nxweb.server.port=8443\n### 静态文件的目录\nxweb.static.path=/static\n\n## 是否启用ssl\nxweb.server.ssl.enable = false\n##  证书链文件， .crt后缀的文件。启用ssl后这个文件必须存在\nxweb.server.ssl.certChainFile.Path=\n## 私钥文件， .pem后缀的文件。启用ssl后这个文件必须存在\nxweb.server.ssl.privatekeyFile.Path=\n\n\n#----------------------------------------------------------------------------------------------------------------\n## 基本配置信息\n# JDBC URL，根据不同的数据库，使用相应的JDBC连接字符串\nurl =jdbc:mysql://localhost:8306/daily\n# 用户名，此处也可以使用 user 代替\nusername = root\n# 密码，此处也可以使用 pass 代替\npassword = 123456\n# JDBC驱动名，可选（Hutool会自动识别）\n# driver = com.mysql.jdbc.Driver\n# 是否在日志中显示执行的SQL\nshowSql = true\n# 是否格式化显示的SQL\nformatSql = true\n\n\n#----------------------------------------------------------------------------------------------------------------\n## 连接池配置项\n\n## ---------------------------------------------------- Druid\n# 初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时\ninitialSize = 0\n# 最大连接池数量\nmaxActive = 8\n# 最小连接池数量\nminIdle = 0\n# 获取连接时最大等待时间，单位毫秒。配置了maxWait之后， 缺省启用公平锁，并发效率会有所下降， 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。\nmaxWait = 0\n# 是否缓存preparedStatement，也就是PSCache。 PSCache对支持游标的数据库性能提升巨大，比如说oracle。 在mysql5.5以下的版本中没有PSCache功能，建议关闭掉。作者在5.5版本中使用PSCache，通过监控界面发现PSCache有缓存命中率记录， 该应该是支持PSCache。\npoolPreparedStatements = false\n# 要启用PSCache，必须配置大于0，当大于0时， poolPreparedStatements自动触发修改为true。 在Druid中，不会存在Oracle下PSCache占用内存过多的问题， 可以把这个数值配置大一些，比如说100\nmaxOpenPreparedStatements = -1\n# 用来检测连接是否有效的sql，要求是一个查询语句。 如果validationQuery为null，testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。\nvalidationQuery = SELECT 1\n# 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。\ntestOnBorrow = true\n# 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能\ntestOnReturn = false\n# 建议配置为true，不影响性能，并且保证安全性。 申请连接的时候检测，如果空闲时间大于 timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。\ntestWhileIdle = false\n# 有两个含义： 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据，详细看testWhileIdle属性的说明\ntimeBetweenEvictionRunsMillis = 60000\n# 物理连接初始化的时候执行的sql\nconnectionInitSqls = SELECT 1\n# 属性类型是字符串，通过别名的方式配置扩展插件， 常用的插件有： 监控统计用的filter:stat  日志用的filter:log4j 防御sql注入的filter:wall\nfilters = stat,wall\n# 类型是List\u003ccom.alibaba.druid.filter.Filter\u003e， 如果同时配置了filters和proxyFilters， 是组合关系，并非替换关系\nproxyFilters =\n\n```\n![在这里插入图片描述](https://img-blog.csdnimg.cn/20200605172338301.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xlaXN1cmVsZW4=,size_16,color_FFFFFF,t_70)\n\n## Xioc 小型的依赖注入框架， \n### 目前支持的注解详解\n* @Component 被注解的类放入容器成为bean，可以注解类和方法。 \n* @Configuration 被注解的类放入容器成为bean, 只能注解类。\n* @Inject 注解字段，是的字段从容器中注入bean。 \n* @Bean 方法注解， 只能配合@Configuration注解通过方法来生产bean\n* @BeanScan 类注解， 只能配合@Configuration一起使用，用来标注框架扫描的包路径\n* @Init 方法注解，  被注解的方法在所在bean初始化完成后调用， 方法必须无参 \n* @Value 字段注解。  将配置中的内容注入到字段中， 类型转换参照Hutool的类型转换工具。 \n* @EventListener 类注解， 被注解的方类必须有无参构造方法，且实现ApplicationListener接口， 注解中必须设置处理的时间名称。\n* @Cron 方法注解， 被注解的方法会作为定时任务执行\n* @EnableCron 在启动类上的注解， 只有这个注解存在， @Cron 注解才会起作用\n\n### 目前支持功能列表如下\n* 所有的bean都是单例模式\n* 基本的扫描注入类，  \n* 支持方法注入bean\n* 支持注入配置，配置文件使用Hutool的setting\n* 支持类似springboot的starter一样的导入包引入对应功能的方法\n\u003e 需要导入的starter包必须在xyz.xiezc.ioc.starter包下放上一个@Configuration注解的类。 并且可以配合@BeanScan一起使用\n* 支持bean初始化后调用的init方法\n* 支持基本的事件处理器\n* 支持配置注入\n\n### 缺陷待完善\n* AOP功能需要在被切的类上面增加注解， 但是AOP的意义就在于不用修改被切类从而达到切面的目的\n\n\n\n## xweb 整合netty支持web的框架\n### 支持的注解\n* @Controller  参考SpringMvc\n* @GetMapping  参考SpringMvc\n* @PostMapping  参考SpringMvc\n* @RequestBody  参考SpringMvc\n* @WebSockerController  被注解的类必须实现WebSocketFrameHandler接口， 从而来实现websocket. 这个注解的value值就是websocket的连接的url\n\n### 说明\n* 默认静态文件目录是 `classPath：static/` ，在这个目录下面的文件会作为静态文件。可以在配置文件中指定 `xweb.static.path` 作为静态文件。\n* 请求路径只有在controller中找不到后才会进入静态文件目录下查找。\n* GET和POST请求只返回application/json格式的内容，不返回其他类型。这样已经够用了， 现在几乎都是前后端分离的项目。\n\n### 待改进\n* 只支持GET和Post请求\n* Post请求只默认提供支持的ContentType类型只有 \"application/json\" ，\"multipart/form-data\" ， \n\"application/x-www-form-urlencoded\"和从url中获取参数的Default几种类型，但是提供了扩展接口。 \n只要实现HttpMessageConverter接口，并将实现类放入容器中，就可以了。\n\n###  配置文件 \n参考上面使用示例中的配置文件\n\n\n\n## XORM 整合mybatis方便查询的项目 \n### 支持的注解\n* @Column 标注在实体类中， 可以通过value 指定数据库字段的名称。 \n* @Id 标注在实体类中， 可以通过value 指定数据库字段的名称。 \n* @MapperScan 一定要标注在启动类中， value指定项目中的mybatis的mapper接口的地址\n* @Table 标注在实体类上， 标识这个类对应一个数据库表\n\n### 支持的配置文件的配置 \n* mybatis.configLocation 指定自定义的mybatis的配置文件地址\n* mybatis.mapperLocations 指定自定义的mapper.xml文件的路径\n* mybatis.typeAliasesPackage 参考mybatis-spring\n* mybatis.typeHandlersPackage 参考mybatis-spring\n\n### 数据源的配置\n\u003e 本框架中数据源的使用是完全使用hutool中的数据源的方式\n#### 基本配置\n```shell script\n\n## 基本配置信息\n# JDBC URL，根据不同的数据库，使用相应的JDBC连接字符串\nurl = jdbc:mysql://127.0.0.1:8306/daily\n# 用户名，此处也可以使用 user 代替\nusername = root\n# 密码，此处也可以使用 pass 代替\npassword = 123456\n# JDBC驱动名，可选（Hutool会自动识别）\ndriver = com.mysql.cj.jdbc.Driver\n\n```\n#### 支持如下的数据源\n1. HikariCP\n2. Druid\n3. Tomcat\n4. Dbcp\n5. C3p0\n  \n本框架句自动识别数据源以及自动注入配置文件中的连接池配置（包括数据库连接配置），如果引入了多种数据源的jar包。 本框架会按照上面的顺序来检测引入数据源包，检测到则会自动构建数据源。如果没有检测到数据源包， 就会使用内置的简单数据源(性能问题， 不推荐线上使用)\n\n以druid为例， 我们看下如何使用\n\n1. 先引入druid的包\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.alibaba\u003c/groupId\u003e\n    \u003cartifactId\u003edruid\u003c/artifactId\u003e\n    \u003cversion\u003e${druid.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n2. 再在配置文件中增加如下\n```properties\n\n#----------------------------------------------------------------------------------------------------------------\n## 基本配置信息\n# JDBC URL，根据不同的数据库，使用相应的JDBC连接字符串\nurl = jdbc:mysql://\u003chost\u003e:\u003cport\u003e/\u003cdatabase_name\u003e\n# 用户名，此处也可以使用 user 代替\nusername = 用户名\n# 密码，此处也可以使用 pass 代替\npassword = 密码\n# JDBC驱动名，可选（Hutool会自动识别）\ndriver = com.mysql.jdbc.Driver\n# 是否在日志中显示执行的SQL\nshowSql = true\n# 是否格式化显示的SQL\nformatSql = true\n\n\n#----------------------------------------------------------------------------------------------------------------\n## 连接池配置项\n\n## ---------------------------------------------------- Druid\n# 初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时\ninitialSize = 0\n# 最大连接池数量\nmaxActive = 8\n# 最小连接池数量\nminIdle = 0\n# 获取连接时最大等待时间，单位毫秒。配置了maxWait之后， 缺省启用公平锁，并发效率会有所下降， 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。\nmaxWait = 0\n# 是否缓存preparedStatement，也就是PSCache。 PSCache对支持游标的数据库性能提升巨大，比如说oracle。 在mysql5.5以下的版本中没有PSCache功能，建议关闭掉。作者在5.5版本中使用PSCache，通过监控界面发现PSCache有缓存命中率记录， 该应该是支持PSCache。\npoolPreparedStatements = false\n# 要启用PSCache，必须配置大于0，当大于0时， poolPreparedStatements自动触发修改为true。 在Druid中，不会存在Oracle下PSCache占用内存过多的问题， 可以把这个数值配置大一些，比如说100\nmaxOpenPreparedStatements = -1\n# 用来检测连接是否有效的sql，要求是一个查询语句。 如果validationQuery为null，testOnBorrow、testOnReturn、 testWhileIdle都不会其作用。\nvalidationQuery = SELECT 1\n# 申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。\ntestOnBorrow = true\n# 归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能\ntestOnReturn = false\n# 建议配置为true，不影响性能，并且保证安全性。 申请连接的时候检测，如果空闲时间大于 timeBetweenEvictionRunsMillis，执行validationQuery检测连接是否有效。\ntestWhileIdle = false\n# 有两个含义： 1) Destroy线程会检测连接的间隔时间 2) testWhileIdle的判断依据，详细看testWhileIdle属性的说明\ntimeBetweenEvictionRunsMillis = 60000\n# 物理连接初始化的时候执行的sql\nconnectionInitSqls = SELECT 1\n# 属性类型是字符串，通过别名的方式配置扩展插件， 常用的插件有： 监控统计用的filter:stat  日志用的filter:log4j 防御sql注入的filter:wall\nfilters = stat\n# 类型是List\u003ccom.alibaba.druid.filter.Filter\u003e， 如果同时配置了filters和proxyFilters， 是组合关系，并非替换关系\nproxyFilters = \n```\n\n3. 开始你的表演， 写你最熟悉的mapper代码\n\n\n\n\n### 说明  \n* 目前没有实现事务的功能， 还不支持事务。\n* Mapper接口必须实现xyz.xiezc.ioc.starter.orm.common.BaseMapper接口，BaseMapper接口提供了基本的方便的查询的方法，十分方便。\n* 可以不用谢mapper.xml文件。 只有到BaseMapper接口不满足需求的时候可以加上xml文件，\nmapper.xml文件的默认路径是classPath:mapper/ 。 也可以通过配置文件mybatis.mapperLocations来指定\n\n### 本框架待改进的地方\n* 实现事务的管理功能， 可以参考spring的事务管理实现 \n\n\n\n## 参考项目\n[hutool](https://github.com/looly/hutool)\n\u003e hutool 这真的是一个很好的工具包项目， 全面而有强大， 依赖少。 本框架大量依赖这个工具包\n\n[blade](https://github.com/lets-blade/blade)\n\u003e blade是和本项目类似的框架。我的整合netty中的代码参考这个项目很多\n\n**spring**\n\n**netty**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblanexie%2Fyao","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblanexie%2Fyao","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblanexie%2Fyao/lists"}