接到1个Spring Boot项目后我自己学习了这些
前言
导师终于肯放手让我做项目了!!!
作为一个初出茅庐的小牛犊,以下内容只是作为对自己浅薄匮乏小脑袋瓜的补充,并还在不断完善中。。。打算接下来学习设计模式,并会逐步把进度同步在这里哒~~~
Spring Boot
- 开发基于REST的服务,使用JSON作为数据交换格式
- Bean装配默认规则是根据Application类所在的包位置从上往下扫描! “Application类”是指SpringBoot项目入口类。
- @GetMapping(value = “/hello”)代替@RequestMapping(value=”/hello”,method= RequestMethod.GET)、
@ResponseBody
将 Controller
的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到HTTP 响应(Response)对象的 body 中,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的情况比较多。
@Controller +@ResponseBody= @RestController
@RestController
只返回对象,对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务。
@Api
用在类上,该注解将一个Controller(Class)标注为一个swagger资源(API)。在默认情况下,Swagger-Core只会扫描解析具有@Api注解的类,而会自动忽略其他类别资源(JAX-RS endpoints,Servlets等等)的注解。该注解包含以下几个重要属性:
- tags:API分组标签。具有相同标签的API将会被归并在一组内展示。
- value:如果tags没有定义,value将作为Api的tags使用
- description:API的详细描述,在1.5.X版本之后不再使用,但实际发现在2.0.0版本中仍然可以使用
@Bean&&@Component
-
目的:均为注册bean到Spring容器中。
-
@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。通过类路径扫描来自动侦测以及自动装配到Spring容器中。
-
@Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。
-
当我们引用第三方库中的类需要装配到Spring容器时,只能通过@Bean来实现
-
//这里只能用@Bean @Bean public OneService getService(status) { case (status) { when 1: return new serviceImpl1(); when 2: return new serviceImpl2(); when 3: return new serviceImpl3(); } }
Spring IoC
参考:SpringIoC有什么好处
控制反转(Inversion of Control) 是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入(Dependency Injection)。以汽车,车身,底盘,轮胎举例。
- 易维护;有利于不同组的协同合作和单元测试。
- 控制反转容器(IoC Container):
- 可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码),而不用每次初始化一辆车都要亲手去写那一大段初始化的代码。
- 在创建实例的时候不需要了解其中的细节
Spring AOP
- 基于动态代理
- JDK Proxy:要代理的对象,实现了某个接口
- Cglib:对象没有实现接口,用 Cglib 生成一个被代理对象的子类来作为代理
- AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。**
Spring事务
参考:我是如何在面试别人Spring事务时“套路”对方的
- 通过注解来使用事务的方式叫 声明式事务;与之相反,自己写代码来开启和提交事务,叫编程式事务。
- 假设目标类中方法a标记事务注解@Transactional,方法b不标记,b调用a,在代理类中调用b,会有事务吗?不会。分析如下:
- 代理类和目标类的类型要兼容,对外接口一致。所以目标类实现的接口,代理类也要实现。
- 代理类在把执行流程代理给目标类的过程中,可以添加一些行为代码,如开启事务、提交事务等。
- 代理类是系统生成的,对带注解的方法进行事务增强,没有注解的方法原样调用。
- 目标类没有事务的方法之间的调用仅仅是目标对象本身的普通方法调用。
- CGLIB代理下假设有这样一个类,它里面包含public方法,protected方法,private方法,package方法,final方法,static方法,我都给它们加上事务注解,哪些方法会有事务呢?答:public,而且必须在代理类外部调用。分析如下:
- 只能通过继承的方式生成一个子类来充当代理,而且和父类在同一个包下。
- 必须在代理类里重写带注解方法以添加开启事务、提交事务的代码。从这个角度来说,private方法不能被继承,final方法不能被重写,static方法和继承不相干,所以它们3个的事务不起作用。
- 而且Spring选择让protected方法和package方法不支持事务,所以只有public方法支持事务。
Spring MVC
参考:Spring常见问题总结(补充版)
把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。
流程解析:
- 客户端(浏览器)发送请求,直接请求到
DispatcherServlet
。 DispatcherServlet
根据请求信息调用HandlerMapping
,解析请求对应的Handler
。- 解析到对应的
Handler
(也就是我们平常说的Controller
控制器)后,开始由HandlerAdapter
适配器处理。 HandlerAdapter
会根据Handler
来调用真正的处理器开处理请求,并处理相应的业务逻辑。- 处理器处理完业务后,会返回一个
ModelAndView
对象,Model
是返回的数据对象,View
是个逻辑上的View
。 ViewResolver
会根据逻辑View
查找实际的View
。DispaterServlet
把返回的Model
传给View
(视图渲染)。- 把
View
返回给请求者(浏览器)
后台控制层获取参数方式
参考:SpringMVC注解@RequestParam全面解析
- request.getParameter("name")
- 用注解@RequestParam直接获取。
涉及到的设计模式
- 工厂设计模式 : Spring使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 - 代理设计模式 : Spring AOP 功能的实现。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的。
- 模板方法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。 - 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
。
H2数据库
就H2而言,只要Spring Boot在类路径中看到H2,它就会自动配置类似于下面所示的数据源:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Spring Data JPA
参考:JPA提供的函数
参考:JPA方法名解析流程
lombok
参考:Lombok 看这篇就够了
Serializable序列化
参考:Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释
-
时机
- 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
- 当你想用套接字在网络上传送对象的时候;
- 当你想通过RMI传输对象的时候;
-
serialVersionUID
- 是唯一可以被序列化和反序列化的static值。
- 实现这个Serializable 接口后,必须给 serialVersionUID 赋值。该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。
-
transient修饰的属性不被序列化
-
实现代码
//序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/flyPig.txt"))); oos.writeObject(flyPig); System.out.println("FlyPig 对象序列化成功!"); oos.close(); //反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("d:/flyPig.txt"))); FlyPig person = (FlyPig) ois.readObject(); System.out.println("FlyPig 对象反序列化成功!");