Solon 是一个相似Springboot的微型开发框架,也是一个不基于Servlet的开发框架。项目从2018年启动以来,参考过大量前人做品;历时两年,3500屡次的commit;内核保持0.1m的身材,超高的Web跑分,良好的使用体验。java
Solon 强调:克制 + 简洁 + 开放的原则;力求:更小、更快、更自由的体验。git
内核0.1m,最小Web开发单位0.2m(相比Springboot项目包,小到能够乎略不计了)。github
具用户反映,某些项目切换到Solon后,能够缩减到原来10%的包大小。web
本机helloworld测试,启动最快可达0.09s,Qps可达12万之多。可参考:《helloworld_wrk_test》。spring
// 除了注入模式以外,还能够按需手动 // //手动获取配置 String userName = Solon.cfg().get("user.name"); Properties dbcfg = Solon.cfg().getProp("db"); //手动获取容器里的Bean UserService userService = Aop.get(UserService.class); //手动监听http post请求 Solon.global().post("/user/update", x-> userService.updateById(x.paramMap()));
能够用solon-web这样的快速开发集成包。也能够按项目须要选择不一样的插件组装,好比:为非Solon项目添加solon.boot.jlhttp,0.2m便可让项目实现http+rpc开发;还能够用MVC开发Socket应用。api
Solon 1.2.12 | Springboot 2.3.3 | 说明 |
---|---|---|
@Inject * | @Autowired | 注入Bean(by type) |
@Inject("name") | @Qualifier+@Autowired | 注入Bean(by name) |
@Inject("${name}") | @Value("${name}") | 注入配置 |
@Component | @Component | 托管组件 |
@Singleton | @Scope(“singleton”) | 单例(Solon 默认是单例) |
@Singleton(false) | @Scope(“prototype”) | 非单例 |
@Init * | @PostConstruct | 构造完成并注入后的初始化 |
@Configuration | @Configuration | 配置类 |
@Bean | @Bean | 配置组件 |
@Mapping | @RequestMapping,@GetMapping... | 映射 |
@Param | @RequestParam | 请求参数 |
@Controller | @Controller,@RestController | 控制器类 |
@Service | @Service | 服务类 |
@Dao | @Dao | 数据访问类 |
@Controller public class App{ public static void main(String[] args){ Solon.start(App.class, args); } @Inject("${app.name}") String appName; @Mapping("/") public Object home(Context c, @Param(defaultValue="noear") String name){ return appName + ": Hello " + name; } }
@Controller public class DemoController{ @Db BaseMapper<UserModel> userService; @Tran @Mapping("/user/update") public void udpUser(long user_id, UserModel user){ userService.updateById(user); } }
@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"; } }
@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); } }
// // 一个数据主从库的示例 // @Configuration public class Config { //申明 db2 是 db1 为的从库 @Bean(value = "db1", attrs = { "slaves=db2" }) public DataSource db1(@Inject("${test.db1}") HikariDataSource dataSource) { return dataSource; } @Bean("db2") public DataSource db2(@Inject("${test.db2}") HikariDataSource dataSource) { return dataSource; } }
//示例:定制统一输出控制基类,并统一开启验证 // @Valid public class ControllerBase implements Render { @Override public void render(Object obj, Context ctx) throws Throwable { if (obj == null) { return; } if (obj instanceof String) { ctx.output((String) obj); } else { if (obj instanceof ONode) { ctx.outputAsJson(((ONode) obj).toJson()); } else { if (obj instanceof UapiCode) { //此处是重点,把一些特别的类型进行标准化转换 // UapiCode err = (UapiCode) obj; obj = Result.failure(err.getCode(), UapiCodes.getDescription(err)); } if (obj instanceof Throwable) { //此处是重点,把异常进行标准化转换 // Throwable err = (Throwable) obj; obj = Result.failure(err.getMessage()); } ctx.outputAsJson(ONode.stringify(obj)); } } } }
@Configuration public class DemoConfiguration implements ServletContainerInitializer{ @Override public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException { //... } }
@WebFilter("/demo/*") public class DemoFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { res.getWriter().write("Hello,我把你过滤了"); } }
//[服务端] @Mapping(value = "/demoe/rpc", method = MethodType.SOCKET) @Component(remoting = true) public class HelloRpcServiceImpl implements HelloRpcService { public String hello(String name) { return "name=" + name; } } //[客户端] var rpc = SocketD.create("tcp://localhost:28080", HelloRpcService.class); System.out.println("RPC result: " + rpc.hello("noear"));
//[服务端] @Mapping(value = "/demoe/rpc", method = MethodType.SOCKET) @Component(remoting = true) public class HelloRpcServiceImpl implements HelloRpcService { public String hello(String name) { // //[服务端] 调用 [客户端] 的 rpc,从而造成单连接双向RPC // NameRpcService rpc = SocketD.create(Context.current(), NameRpcService.class); name = rpc.name(name); return "name=" + name; } }
//[服务端] @ServerEndpoint public class ServerListener implements Listener { @Override public void onMessage(Session session, Message message) { if(message.flag() == MessageFlag.heartbeat){ System.out.println("服务端:我收到心跳"); }else { System.out.println("服务端:我收到:" + message); //session.send(Message.wrapResponse(message, "我收到了")); } } } //[客户端] var session = SocketD.createSession("tcp://localhost:28080"); session.send("noear"); //session.sendAndCallback("noear", (rst)->{}); //发送并异常回调 //var rst = session.sendAndResponse("noear"); //发送并等待响应 System.out.println(rst);
//[客户端] @ClientEndpoint(uri = "tcp://localhost:28080") public class ClientListener implements Listener { @Override public void onMessage(Session session, Message message) { //以后,就等着收消息 System.out.println("客户端2:我收到了:" + message); } }
//[定义接口],通常状况下不须要加任何注解 // public interface UserService { UserModel getUser(Integer userId); } //[服务端] Component.remoting = true,即为组件开启远程服务 // @Mappin("user") @Component(remoting = true) 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("local:/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"; } }
public class XPluginImp implements Plugin { @Override public void start(SolonApp app) { Aop.context().beanBuilderAdd(Service.class, (clz, bw, anno) -> { bw.proxySet(BeanProxyImp.global()); Aop.context().beanRegister(bw, "", true); }); } }
src/main/resources/META-INF/solon/solon.extend.aspect.properties
solon.plugin=org.noear.solon.extend.aspect.XPluginImp
//[收集异常] EventBus.push(err); //[订阅异常] EventBus.subscribe(Throwable.class,(event)->{ event.printStackTrace(); }); //或经过SolonApp订阅 app.onEvent(Throwable.class, (err)->{ err.printStackTrace(); }); //或经过组件订阅 @Component public class ErrorListener implements EventListener<Throwable> { @Override public void onEvent(Throwable err) { err.printStackTrace(); } }
// // 插件开发时,较常见 // SqlManagerBuilder builder = new SqlManagerBuilder(ds); EventBus.push(builder);