2020年5月

本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。

1) 概述

  • 分层
  • Full-stack
  • 轻量级
  • 提供依赖注入和事务管理

1.1) 发展历程

  • 1997 IBM 提出 EJB 思想
  • 1998 SUN 指定开发标准规范 EJB1.0
  • 1999 EJB 1.1 发布
  • 2001 EJB 2.0 发布
  • 2003 EJB 2.1 发布
  • 2006 EJB 3.0 发布
  • Rod johnsonn(Spring 之父)
    • 2002 Expert One-to-One J2EE Design and Development
      阐述了 J2EE 使用 EJB 开发设计的有点以及解决方案
    • 2004 Expert One-to-One J2EE Development without EJB
      阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)

1.2) 特点

  • IOC 解耦合
  • AOP 面向切面
  • 声明式事务
  • 对 JUnit 的测试支持
  • 整合第三方框架成本低
  • 设计模式源码教科书

1.3) 架构

404

2) 核心思想

2.1) IOC(Inversion of Control)

解决了传统开发需要手动频繁创建接口对象的问题
将控制权交给 Spring 解耦,且维护对象之间的依赖关系。
想使用对象只需要声明它从 Spring 取就好了,如声明一个接口,让 Spring 来管理使用哪个实现

2.2) DI(Dependancy Injection)

那么何为依赖注入呢,实际上 IOC 和 DI 描述的都是同一种思想,只是角度不同。
IOC 对象的角度分析,DI 为容器角度

2.2) AOP(Aspect oriented Programming)

AOP 是从 OOP(Object oriented Programming) 发展过来的,OOP 即封装继承多态,

本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。

最近不知道为啥 OpenWrt 多播炸了,公司内网单线限速太慢。
想切手机热点,又有访问内网服务的需求,就可以用简单路由表实现:

sudo route delete 0.0.0.0 # Remote 掉默认路由
sudo route add -net 0.0.0.0 172.20.10.1 # 默认路由设成外网网卡设备网关
sudo route add 172.16.6.0/24 192.168.1.1 # 公司内网地址指向内网网卡网关
sudo route add 172.16.7.0/24 192.168.1.1 # 公司内网地址指向内网网卡网关

完成,MacOS 记得把 Network 管理中,Set Service Order 里设置成外网网卡优先
完毕。

[Meting]
[Music title="盗将行(翻自 花粥)" author="须臾aow/花世" url="https://mirrors.wars.cat/files/djx.mp3" pic="https://blog.wars.cat/usr/themes/moeka/img/warscat.jpg" lrc="https://mirrors.wars.cat/files/djx.lrc"/]
[/Meting]

本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。

MyBatis 的插件基于拦截器思想,基于动态代理实现,我们可以对 MyBatis 中以下四大组件中的 method 进行拦截

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)
3.1.7.1) 介绍:

我们可以通过实现 Interceptor 接口,实现和重写接口中的三个扩展方法:

  1. intercept(Invocation invocation):此接口为主扩展方法,invocation.proceed() 可以继续运行被拦截的方法,使我们可以在前后扩展。
  2. Object plugin(Object target):是的它就是上一节我们分析原理时执行的 plugin 函数,此函数是一个默认方法,可以重写它对创建代理时扩展。
  3. setProperties(Properties properties):在 SqlMapConfig.xml 中声明插件的 plugin 标签定义的参数,会传递到 properties 中。
3.1.7.2) 栗子:

定义:

@Intercepts({@Signature(
        type = Executor.class, method = "update",
        args = {MappedStatement.class, Object.class}
)})
public class ExampleInterceptor implements Interceptor {

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    /* Before process */ Object result = invocation.proceed(); /* After process */
    return result;
  }
}

声明:

<plugins>
  <plugin interceptor="cat.wars.ExampleInterceptor"></plugin>
</plugins>
3.1.7.3) 原理:

Configuration 中创建四大组件时都会调用 interceptorChain.pluginAll 方法来扩展,如 ParameterHandler
,从而返回一个重重代理对象

Configuratoin

  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    // Create instance
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    // 将创建的 instance 交给 Interceptor Chain,执行完 pluginAll 后会返回一个重重(loop)代理对象
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler; // 返回代理对象
  }

InterceptorChain

public Object pluginAll(Object target) {
  for (Interceptor interceptor : interceptors) {
    target = interceptor.plugin(target); // 执行定义的 plugin 实现动态代理
  }
  return target;
}

本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。

本文参考官方文档节选翻译, 对开发中对SpringMVC常用类, 做一个简单的整理, 勉强充当一个参考文档
关于更详细的文档请参考: https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html

1) 方法参数

本节介绍SpringMVC, Controller中方法的参数用法

类型 desc
可注入类型
WebRequest, NativeWebRequest MVC的请求参数包装, 用于手动获取请求参数
javax.servlet.ServletRequest, javax.servlet.ServletResponse Servlet原生请求响应, 可继承项目的BaseController, 调用getXXX获取
javax.servlet.http.HttpSession Servlet原生Session, 可继承项目的BaseController, 调用getXXX获取
java.util.Map,org.springframework.ui.Model,org.springframework.ui.ModelMap 通常用于节约需要传给模板的Model的构建代码, 如new HashMap()
注解
@PathVariable 获取URI中变量, 项目规范必须写上value对应请求参数名, 如@PathVariable("name")
@MatrixVariable 获取URI中为key-value格式的数据, 参考文档
@RequestParam 获取query或form类型请求参数, 详见@RequestParam
@RequestHeader 获取请求头中的参数, 可不设置value映射Map, 支持将逗号分隔的字符串转换成列表或List
@CookieValue 获取Cookie中的参数
@RequestBody 读取请求体并转换为一个Object, 通常用于转换JSON, 支持的转换类型参考HttpMessageConverter接口的实现
@RequestPart 主要用于文件上传型接口, 用法通常为如下获取文件元数据和文件: @RequestPart("meta-data") MetaData metadata,@RequestPart("file-data") MultipartFile file

@RequestParam

将query(?name=a&age=1)或form(表单提交)类型请求参数绑定到方法参数
简单参数例子

@Controller
@RequestMapping("/pets")
public class EditPetForm {

    @GetMapping
    public String setupForm(
        @RequestParam("petId") int petId // 获取GET请求中的URI中petId参数或, form表单提交中的petId参数
    ) {}
}

文件上传获取MultipartFile例子

@Controller
public class FileUpload {

    @PostMapping("/upload")
    public UploadImageResult upload( 
        @RequestParam("file") MultipartFile multipartFile
        , @RequestParam String fileTag
        , @RequestParam String businessKey
        , @RequestParam(required = false) String metadata
    ) {
        return service.upload(multipartFile, fileTag, businessKey, metadata);
    }
}
  1. 获取query/form参数时, 此注解是可选的, 除非你的param名和请求参数名不对应, 可用注解中的value标注绑定参数
  2. 如将参数类型声明为数组或List,可以为同一参数名称解​​析多个参数值。
  3. 如果将@RequestParam注释声明为Map<String, String>或MultiValueMap<String, String>,而在注释中未指定参数名称, 则会把请求中的所有query/form参数填充进Map中

2) 方法返回值

本节介绍SpringMVC, Controller中方法的返回值类型用法

类型 desc
@ResponseBody 将响应的Object转换为一个消息, 通常用于转换对象为JSON, 支持的转换类型参考HttpMessageConverter接口的实现, 此注解也支持标注类, 但是如需要标注类, 更推荐另一个注解@RestController, @RestController = @Controller + @ResponseBody
String 指定需要渲染的模板/视图名称,通常返回一个Freemarker模板结合Model渲染页面
View 指定需要渲染的视图, 功能如String, 通常用于返回此接口的实现类, 扩展同时使用多个模板引擎
java.util.Map, org.springframework.ui.Model 交给模板引擎的数据, 通常用于一个Method给另一个Method传数据
ModelAndView 指定要渲染的视图和视图需要的数据
void 通常用于手动使用ServletResponse/OutputStream响应数据的情况
Title - Artist
0:00