### 1、与 Springboot 的常用注解比较

|  Solon 3.10.1 | Springboot 2.7.16 / 3.5.4 | 说明 |
| -------- | -------- | -------- |
| [@Inject](/article/326) *     | @Autowired     | 注入Bean（by type）    |
| @Inject("name")     | @Qualifier+@Autowired     | 注入Bean（by name）    |
| @Inject("${name}")     | @Value("${name}") + @ConfigurationProperties(prefix="name")     |注入配置    |
| | | |
| @BindProps(prefix="name")     | @ConfigurationProperties(prefix="name")     | 绑定属性集    |
| | | |
| @Singleton     | @Scope(“singleton”)     | 单例（Solon 默认是单例）     |
| @Singleton(false)     |  /     | 多例（非单例）     |
|  /     | @Scope(“prototype”)     | 原型     |
| | | |
| [@Import](/article/618)     | @Import + @ComponentScan     | 导入组件（一般加在启动类上）     |
| @Import | @PropertySource  | 导入属性源（一般加在启动类上） |
| | | |
| [@Configuration](/article/324) | @Configuration | 配置类 |
| @Bean     | @Bean     | 配置Bean     |
| [@Condition](/article/434)     | @ConditionalOnClass + @ConditionalOnExpression ...     | 配置条件     |
| | | |
| [@Component](/article/602)     | @Component, @Service, @Dao, @Repository ...     | 托管组件     |
| | | |
| @Import | @TestPropertySource | 导入测试属性源 |
| @Rollback | @TestRollback | 执行测试回滚 |
| | | |
| [LifecycleBean](/article/448)     | InitializingBean + DisposableBean     | 组件初始化和销毁     |
| [AppLoadEndEvent](/article/240)     |   ApplicationRunner or CommandLineRunner    | 应用加载后运行     |
| | | |
| <b>Solon 3.10.1</b> | <b>Java EE / Jakarta</b> |  |
| LifecycleBean::start<br/>或 @Init 注解           | @PostConstruct     | 组件初始化     |
| LifecycleBean::stop<br/>或 @Destroy 注解     | @PreDestroy          | 组件销毁     |

* 注1：Method@Bean，只执行一次（只在 @Configuration 里有效）
* 注2：@Inject 的参数注入，只在 Method@Bean 和 Constructor 上有效
* 注3：@Inject 的类注入，只在 @Configuration类 上有效
* 注4：@Import 只在 启动类上 或者 @Configuration类 上有效


### 2、与 Springboot 组件的差别

* 动态代理


|  Solon 3.10.1 | Springboot 2.7.16 / 3.3.2 | 
| -------- | -------- |
| <mark>只对组件的 public 函数“按需”代理（即有拦截注册时）</mark>    | 对组件的 public、protected 函数进行代理     | 


* 容器注册


|  Solon 3.10.1 | Springboot 2.7.16 / 3.3.2 | 
| -------- | -------- |
| <mark>需要配置 name 才会按名字注册（才能按名字获取）</mark>     | 会自动按“类名”作为 name 进行注册     | 


* 作用域




|  Solon 3.10.1 | Springboot 2.7.16 / 3.3.2 | 说明 |
| -------- | -------- | -------- |
| @Singleton     | @Scope(“singleton”)     | 单例（每次注入或获取，是一个唯一实例）     |
| @Singleton(false)     |  /     | 多例（每次注入或获取，是一个新实例）     |
|  /     | @Scope(“prototype”)     | 原型（每次调用方法，是一个新实例）     |
|  /     | @Scope(“request”)     |  每个 web 请求范围，是一个新实例（类似于 context attr）    |
|  /     | @Scope(“session”)     |  每个 web 会话范围，是一个新实例（类似于 session state）     |



### 3、与 Spring Mvc 的比较

* 注解方面的区别

|  Solon 3.10.1 | Springboot 2.7.16 / 3.3.2 | 说明 |
| -------- | -------- | -------- |
| @Controller | @Controller,@RestController | 控制器类 |
| @Remoting |  | 远程控制器类（即 Rpc 服务端） |
| | | |
| [@Mapping](/article/327) | @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 效果：

```java
@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.10.1 | Springboot 2.7.16 / 3.3.2 | 说明 |
| -------- | -------- | -------- |
| Context     | HttpServletRequest + HttpServletResponse     | 请求上下文     |
| SessionState     | HttpSession    | 请求会话状态类     |
| UploadedFile     | MultipartFile     | 文件上传接收类     |
| DownloadedFile     |      | 文件下载输出类     |
| ModelAndView     | ModelAndView     | 模型视图输出类     |



* Solon 适配有：jdkhttp、smarthttp、jetty、undertow、vert.x、netty、websocket 等各种通讯容器。


### 5、Solon 不支持属性设置注入

* 不支持的：

```java
@Component
public class DemoCom {
    private B b;
    
    public void setB(@Inject B b){
        this.b = b;
    }
}
```

* 支持的（字段，或构造器参数，或小豆方法参数）：

```java
@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 可以更自由获取配置

```java
@Component
public class Demo{
    //注入配置
    @Inject("${user.name}")
    private String userName;
    
    //手动获取配置
    private String userName = Solon.cfg().get("user.name");
}
```

### 7、Solon 配置注给结构体

* 相当于 `@ConfigurationProperties` 的效果

```java
@Inject("${user.config}")  
@Configuration
public class UserConfig{
    public String name;
    public List<String> tags;
    ...
}

//别处可以注入复用
@Inject
UserConfig userConfig;
```


### 8、与 Springboot 相似的事务支持 @Transaction

* 采用 Springboot 相同的事件传播机制及隔离级别。但回滚时，不需要指定异常类型

```java
@Controller
public class DemoController{
    @Db
    BaseMapper<UserModel> userService;
    
    @Transaction
    @Mapping("/user/update")
    public void udpUser(long user_id, UserModel user){
        userService.updateById(user);
    }
}
```

### 9、与 Springboot 不同的校验方案 @Valid

* Solon 的方案多了“批量参数校验”，且强调“可见性”（即与处理函数在一起）。同时也支持实体的校验

```java
@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冲突

```java
@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 协同使用

```java
//
// 一个数据主从库的示例
//
@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 请求与响应对象注入

```java
@Mapping("/demo/")
@Controller
public class DemoController {
    @Mapping("hello")
    public void hello(HttpServletRequest req, HttpServletResponse res){
        //...
    }
}
```

* 支持 ServletContainerInitializer 配置

```java
@Configuration
public class DemoConfiguration implements ServletContainerInitializer{
    @Override
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        //...
    }
}
```

* 支持 Servlet api 注解

```java
@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 ）

```java
//[定义接口]，一般情况下不需要加任何注解
//
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 注解支持为例）

```java
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 构建器为例：

```java
Solon.context().beanBuilderAdd(Controller.class, (clz, bw, anno) -> {
    //内部实现，可参考项目源码 //构建器，可以获取类型并进行加工
    new HandlerLoader(bw).load(Solon.global());
});

//效果
@Controller
public class DemoController{
}
```

* 注册'注入器'处理。以注册 @Inject 注入器为例：

```java
Solon.context().beanInjectorAdd(Inject.class, ((fwT, anno) -> {
    //内部实现，可参考项目源码 //注入器，可以根据目标生成需要的数据并赋值
    beanInject(fwT, anno.value(), anno.autoRefreshed());
}));

//效果
@Controller
public class DemoController{
    @Inject
    UserService userService;
}
```

* 注册'拦截器'处理。以注册 @Transaction 拦截器为例：

```java
//拦截器，可以获取执行动作链
Solon.context().beanInterceptorAdd(Tran.class, new TranInterceptor(), 120);

//效果
@Component
public class UserService{
    @Transaction
    public void addUser(User user){
    }
}
```


* 注册'提取器'处理。以注册 @CloudJob 提取器为例：

```java
//内部实现，可参考项目源码 //提取器，可以提取被注解的函数
Solon.context().beanExtractorAdd(CloudJob.class, CloudJobExtractor.instance);

//效果 //提取器只对组件有效
@Component
public class Job{
    @CloudJob
    public void statUserJob(){
    }
}
```



