开发框架学习笔记
- 一.Spring SpringMVC SpringBoot
- 三者的联系
- SpringMVC工作原理
- 二.SpringBoot的学习
- 2.1 注解
- 2.1.1 SpringBoot的核心注解
- 2.1.2 配置导入注解(简化Spring配置写XML的痛苦)
- @Configuration和@Bean(`人为`注册Spring 的 Bean)
- @Import(补)
- @ImportResource(补)
- @Autowired@Qualifier和 @Resource(name="name",type="type")(获取Bean)
- @Inject(用的少,补)
- 2.1.3业务层功能
- @Component
- @ResponseBody
- @Controller @ResonanceBody和@RestController
- @Service
- @Repository(补)
- @RequestMapping
- @Value
- @PathVariable
- @Profiles
- @ConfigurationProperties
- 2.1.4 全局异常处理(补)
- @ControllerAdvice
- @ExceptionHandler(Exception.class)
- 2.2 IOC和AOP
- IOC
- AOP
- MybatisPlus
- 三.手动实现一个简易版Spring框架(包含以前没有Spring时怎么发请求)
- 四.开发常用工具Lombok
- 4.0说在前面(如何快速使用Lombok)
- 4.1了解Lombok
- 4.2Lombok的作用一:减少代码冗余
- 4.3Lombok的作用二:方便打日志
- 4.4Lombok使用方法(各个注解作用)
- 4.5Lombok原理
- JsonUtil
- BeanUtil
- StringUtil
- 代码习惯
- 快捷方式
一.Spring SpringMVC SpringBoot
三者的联系
MVC是一种设计框架, 市面上也有很多其他的MVC web框架,但是SpringMVC是佼佼者
- 总结: springboot是spring的升级, springMVC是一种MVC框架(MVC框架的作用看下图)
SpringMVC工作原理
这里我的理解是handler可能是前端发ajax请求的那段代码?还是说是后端各种controller类和其RequestMapping(‘URL’)的一个集合?
- 总结
相关参考文档如下:
MVC思想及SpringMVC设计理念
Spring MVC+ Spring + Mybatis “三大框架”介绍
SpringMVC—Handler到底是个什么?及流程详解
二.SpringBoot的学习
2.1 注解
本文基于这篇博客加上一些我个人的理解, 有一个很全的思维导图可以点击这个链接获取
2.1.1 SpringBoot的核心注解
@SpringBootApplication
通常用在启动类上,申明让spring boot自动给程序进行必要的配置,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:
- @SpringBootConfiguration(补)
组合了 @Configuration 注解,实现配置文件的功能。
- @EnableAutoConfiguration(补)
打开自动配置的功能,也可以关闭某个自动配置的选项。
如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class });
- @ComponentScan
Spring组件扫描功能,让spring Boot扫描到@Configuration
和一些@Component
(@Service, @Controller, @Repository都是基于@Component)标注的类并把它加入到程序上下文。
2.1.2 配置导入注解(简化Spring配置写XML的痛苦)
@Configuration和@Bean(人为
注册Spring 的 Bean)
为什么说是人为呢, 因为代码中有new的动作
- @Configuration: 等同于spring的XML配置文件,使用Java代码可以检查类型安全。指出该类是
Bean 配置的信息源
,相当于Spring的XML中的,一般加在主类上。 - 相当于XML中的,放在方法的上面,而不是类,意思是产生一个bean,并交给spring管理;
为啥不直接将@Component或者基于@Component的@Service\@Controller\@Repository标注在该类上,直接交给SpringBoot管理呢?
:
因为许多第三方的库我们是没法直接去修改它的源代码的(即没法直接在第三方库的类上添加注解
), 当我们需要使用第三方库又不想手动创建对象的时候(手动创建对象还要自己去释放)就可以:- 手写一个配置类加上@Configuration
- 配置类中声明一个方法返回第三方库的对象即可,
- 最后给这个方法加上@Bean注解
@Import(补)
用来导入其他配置类;
@ImportResource(补)
用来加载xml配置文件;
@Autowired@Qualifier和 @Resource(name=“name”,type=“type”)(获取Bean)
- @Autowired:自动导入依赖的bean,自动导入依赖的bean。
byType方式
(因此如果一个Service接口有两个实现类的时候,就必须使用@Resource了(支持byName)
)。把配置好的Bean拿来用,完成属性、方法的组装,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。当加上(required=false)时,就算找不到bean也不报错; - @Resource:没有括号内内容的话,默认byName,与@Autowired干类似的事;
@Inject(用的少,补)
等价于默认的@Autowired,只是没有required属性;
2.1.3业务层功能
@Component
泛指组件,当组件不好归类的时候(因为@Service@Controller@Repository都有明确的业务场景),我们可以使用这个注解进行标注;
@ResponseBody
@ResponseBody这个注解@RestController自带了一般不用写, 现在都是前后端分离的, 肯定直接用@RestController
表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,用于构建RESTful的api
。在使用@RequestMapping后,返回值通常解析为跳转路径,加上@Responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@Responsebody后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用;
@Controller @ResonanceBody和@RestController
- Controller: 用于定义控制器类,在spring项目中由控制器负责将用户发来的URL请求转发到对应的服务接口(service层),一般这个注解在类中,通常方法需要配合注解@RequestMapping;
- @Controller 用于定义一个控制器类,它通常用于处理用户的HTTP请求,并返回相应的
视图(View)
。 @Controller类中的方法可以直接通过返回String跳转到JSP、HTML等模版页面。Spring会根据视图名解析出实际的视图,通常是一个HTML页面。
- 在方法上加
@ResponseBody注解
,也可以返回实体对象的JSON数据。 - 方法上的 @RequestMapping 或者其他映射注解(如 @GetMapping、@PostMapping 等)用于将特定的请求映射到相应的处理方法。
- @Controller 用于定义一个控制器类,它通常用于处理用户的HTTP请求,并返回相应的
- @RestController:用于标注控制层组件(如struts中的action),是@ResponseBody和@Controller的合集;
@RestController注解等价于@ResponseBody + @Controller。表示该控制器中的所有方法都返回数据而不是视图
。- 将每个方法的返回值直接作为 HTTP 响应的内容,而不经过视图解析器。@RestController类中的所有方法只能返回String、Object、Json等实体对象,不能跳转到模版页面。
- @RestContoller类中相当于所有方法都自带@ResponseBody,会自动将方法的返回值转换为JSON格式的响应体返回给客户端。但也可以通过其他注解(如 @ResponseBody)来改变返回的数据格式。
- @RestController如果想和@Controller一样跳转页面的话,可以使用ModelAndView进行封装。
@Service
一般用于修饰service层的组件;
@Repository(补)
用于标注数据访问组件,即DAO组件;
@RequestMapping
提供路由信息,负责URL到Controller中的具体函数的映射;
该注解包含以下6个属性:(常用value)
params:指定request中必须包含某些参数值是,才让该方法处理;
headers:指定request中必须包含某些指定的header值,才能让该方法处理请求;
value:指定请求的实际地址,指定的地址可以是URI Template 模式;
method:指定请求的method类型, GET、POST、PUT、DELETE等;
consumes:指定处理请求的提交内容类型(Content-Type),如application/json,text/html;
produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。
@Value
注入 application.properties 或 application.yml 配置的属性的值;
@PathVariable
路径变量,参数与大括号里的名字一样要相同;
@Profiles
Spring Profiles 提供了一种隔离应用程序配置的方式,并让这些配置只能在特定的环境下生效。任何@Component或@Configuration都能被@Profile标记,从而限制加载它的时机;
@ConfigurationProperties
Spring Boot将尝试校验外部的配置,默认使用JSR-303(如果在classpath路径中)。你可以轻松的为你的@ConfigurationProperties 类添加JSR-303 javax.validation约束注解;
2.1.4 全局异常处理(补)
@ControllerAdvice
包含@Component,可以被扫描到,统一处理异常;
@ExceptionHandler(Exception.class)
2.2 IOC和AOP
IOC
IOC的实现方法通过三.手动实现一个简易版Spring框架
这一节中的推荐视频我总结一下我的看法(我比较菜, 就通俗易懂点):我看了视频后, 发现IOC就是一个对象的ContainerMap
这个Map填充的过程如下:
- Java通过包扫描(递归调用自己最终将该Spring项目下所有的类名得到一个集合)
- 遍历这个集合的类名, 通过反射判断其是否被
添加Bean相关的注解标注
, (添加Bean相关的注解有(Component\Configuration+Bean…)), 然后将被标注了这些类以Key-Value的形式放入container中
- key就是
注解中value的值
- value就是
这些类的对象的实例
- key就是
AOP
MybatisPlus
为什么这里可以直接用save呢,他怎么知道我查的哪个表?
这是因为继承了mybatisplus中的ServiceImpl类,并指定了当前类用到的mapper接口UserMapper和对应的entity实体类user
三.手动实现一个简易版Spring框架(包含以前没有Spring时怎么发请求)
本节内容是看这个视频学习的, 本节以前没有Spring时怎么发请求
这一部分内容略了, 大概就是通过MyServlet extend HttpServlet
+ 写XML注明每个路径对应哪个Servlet实现的
, 想了解的可以看上面那个视频
简易版Spring框架步骤:
- 加载配置文件, 得到第二步中包扫描的路径
- 包扫描所有的类(IO流+递归调用自己最终将该Spring项目下所有的类名存入一个集合中)
- 遍历这个集合的类名, 通过
反射
判断其是否被添加Bean相关的注解标注
, (添加Bean相关的注解有(Component\Configuration+Bean…)), 然后将被标注了这些类以Key-Value的形式放入container中
- key就是
注解中value的值
- value就是
这些类的对象的实例
- key就是
- 之前已经用一个MyDispatcherServlet拦截了所有的路径请求, 在这个大类中用一个handlerMapping存储下来
所有请求的路径
和对应的类的方法名
即- Key是请求的路径
- Value是该路径对应的类的方法名
之后通过HttpRequest对象拿到对应的请求路径(URL)将这个URL和handlerMapping中的Key进行遍历比对:- 比对失败:返回404
- 比对成功:取出对应的参数进行赋值, 然后
反射
调用对应Controller的方法
四.开发常用工具Lombok
4.0说在前面(如何快速使用Lombok)
- 最简单的办法在maven中加入如下依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<scope>provided</scope>
</dependency>
- 老版本的idea需要安装Lombok插件(否则写代码的时候会报错),并且打开设置中的
enable annotation processing
(否则idea不识别Lombok的注解)但是新版本(21开始吧)idea已经自带Lombok插件了;这里引出来一个问题:为什么要idea要装插件?
因为idea本质上是一个可视化的编辑器, java编译器会根据Lombok的注解修改语法树,最终结果是被注解标记的java类生成的字节码文件中会包含Lombok生成的代码, 但是我们写代码的时候出于源码阶段还没编译呢, idea当然识别不出来Lombok的注解生成一些get set方法了
4.1了解Lombok
官网解释
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing(香料,调味剂) up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
提取关键词:Java 库、自动插件、提高效率、再也不编写get、equals等方法、使用注解
4.2Lombok的作用一:减少代码冗余
使用Lombok前:即使idea提供了快捷键cmd + n手动快捷生成get/set/equals/hashCode/toString方法,但表多了后还是很麻烦
使用后效果:加注解,减少代码冗余
4.3Lombok的作用二:方便打日志
日志和传统打印操作相比的好处是
日志是可插拔的, 日后上线
的时候可以在配置文件中动态的开关,但是sout的内容需要手动
去一个个文件中寻找并删除
- 小技巧@Sl4j打日志的时候不仅仅可以直接打印,还可以用如下这种占位符的方法打印变量
/**
* 实现log4j的符号{}打印
*/
@Test
public void print2(){
Person person1 = new Person("chen",123,"man");
Person person2 = new Person("li",234,"women");
System.out.println("=====================================================");
//Person类用Lombok实现了toString()方法
logger.info("This is a debug message,person1={},person2={}",person1,person2);
System.out.println("=====================================================");
}
4.4Lombok使用方法(各个注解作用)
- @Data:生成该类的get/set/equals/hashCode/toString方法
- @Sl4j:自动在该类中生成一个private Logger log = LoggerFactory.getLogger(this.getClass());即log对象, 我们可以通过log.info()\log.debug()\log.warning()…多种方式打日志
- @Log:支持Log4j、Slf4j,日志功能,
具体Log4j没用过, 后面来补
- @Accesors(chain = true):
平常给一个对象赋值的时候我们需要person1.setAge(6);person1.setName(‘张三’); 使用这个注解后直接person1.setAge(6).setName('张三');
进行链式编程; - @Builder:使用此注解进行对象的构建,函数式编程/链式编程,省去逐行字段set。
CarLombok build = CarLombok.builder().id(1).type(“string”).price(88.8).level(‘a’).build();
System.out.println(build.toString()); - @AllArgsConstructor:生成该类的全部参数的构造函数,
不能生成部分参数的构造函数
,如果想要生成部分参数的构造函数还是需要手动生成的;如果加上这个注解后相当于类中增加了一个全部参数的构造函数, 因此之前其他代码中用无参构造函数new的对象可能会报错, 我们还需要手动加上@NoArgsConstructor;即@AllArgsConstructor和@NoArgsConstructor一般一起使用
一般不用全部参数的构造方法, 我们习惯自己new完一个对象用set方法去赋值
- @NoArgsConstructor:生成无参构造函数
- @RequiredArgsConstructor:生成指定类型(final ,@NonNull)
- @Getter和@Setter
- 可以为单个成员变量设置get方法
- 可以为所有成员变量设置get、set方法 。同时可以为某个成员变量设置其他权限(默认public)、或设置取消get/set方法
- 无法为static设置get/set方法,只为final类型设置get方法
- @ToString等: 生成该类的get() set() tostring()方法
ToString只能加在类上,自动生成ToString方法,使用exclude排除多个字段,of必须包含哪些字段。
- @EqualsAndHashCode
生成equals方法、canEqual(判断是否属于Car类)、hashCode方法。也可以进行相等比较的排除,指定。
例如:@EqualsAndHashCode(exclude = {“字段1”,“字段2”})
- @NonNull
可以加在成员变量前,也可以加在方法参数前。用来指定某个字段不能为空 - val:类比JS中的val(弱引用类型),在编译阶段确定类型,简化操作
使用 val map = new HashMap<String, String>();
替换 Map<String, String> map = new HashMap<>(); - @Cleanup:对资源流进行清理
@Cleanup InputStream in = new FileInputStream(“filepath”);
@Cleanup OutputStream out = new FileOutputStream(“filepath2”);
4.5Lombok原理
本节内容涉及java编译过程大家可以去了解一下, 同时还有一些注解相关的API;
学习注解就一定要学习java的反射, 有关注解和反射的知识可以查看我的另一篇博客
- 没错, 上篇那个博客啥都没, hhh 待补!!!, 不过你可以查看下面这些内容
下面的内容都是从这个视频学的, 这个视频后半部分还讲解了Spring是如何通过注解实现对象的代理的, 但是我只是知道它执行的顺序, 还没有彻底搞懂反射, 等我补完反射就来补SpringBoot项目的启动流程
为什么说注解也是一个类呢?
Java规范:JSR 269(Java Specification Requests) 插件化注解处理API(Pluggable Annotation Processing API)
JDK6提供的特性,在 Javac编译期(SOURCE标识)利用注解,在字节码文件中生成get、set等方法
Java编译器执行过程:
查看编译后的字节码文件:
- 为什么说Lombok在源码阶段不生效, 他只是在java编译的时候在字节码文件中生成get\set方法
以@Data为例,我们查看它的源码发现:
JsonUtil
- Json <> Bean, 例如 将一个对象以string字符串的方式存储到redis的string中
BeanUtil
- Bean<>Map, 例如将一个对象以hashmap键值对的形式存储到redis的hash中
- JsonObject<>BeanUtil
StringUtil
- isNotBlank:判断一个String是否为空(空是指"“或” "这种)
代码习惯
- 所有常量均定义宏
写宏的时候 用下划线区分BEGIN_TIMESTAMP
- 凡是自动拆箱都可能导致空指针(比如返回的是Boolean, 但是这是个null, 那么没办法拆箱成boolean了)
public boolean{
Boolean success = ...
//return success;
return Boolean.TRUE.equals(success);
}
- 少些嵌套
if(success) { try{}catch{}finally{} } .... 改成 if(!sucess) { ... } try{}catch{}finally{}
- 注释
快捷方式
soutv:打印一个value
fori:循环
cmd + n插入构造函数, 重写方法,实现方法等