Spring设计模式 & Spring Security & Spring Jpa
😉 本文共2283字,阅读时间约8min
Spring设计模式
- 工厂 : Spring 使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 - 代理 : Spring AOP 功能的实现。
- 单例 : Spring 中的 Bean 默认都是单例的。
- 装饰者 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
- 适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
。
工厂模式
-
Spring的
ApplicationContext
与BeanFactory
中的getBean()
都可以视为工厂方法,它隐藏了bean的创建过程与具体实现。- 其他的工厂模式:
@Bean
标注的方法,主要封装了第三方Bean的创建过程。
- 其他的工厂模式:
-
好处:
- 隐藏内部实现:Spring IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。
单例模式
Spring 中 bean 的默认作用域就是 singleton(单例)的。
区分单例模式和Spring Singleton
- 单例模式:确保一个类只有一个实例
- Spring Singleton Bean:并非实现了单例模式,只能保证每个容器内相同id的bean是单实例的
单例模式好处
- 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
- 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
Spring如何实现单例模式
Spring 实现单例,是基于ConcurrentHashMap(线程安全) 实现单例注册表,先到map里检查是否存在bean,如果没有,将其注册到按理注册表。
AOP代理模式
典型实现有JDK和Cglib的代理模式
代理模式和装饰器模式的区别
装饰器模式注重的是功能增强,避免子类继承方式进行功能扩展,而代理模式更注重对目标的访问。值得注意,代理模式更像是一个入口,比如AOP代理,做功能增强的是那些通知才对,而代理可以在某些条件不满足时不做通知。
适配器模式
什么是适配器模式?
将一个类的接口适配成用户所期待的
// 源
public class Cat {
public void makeSound(){
System.out.println("猫猫:喵喵喵。。。。。。。。。。。。。");
}
}
// 目标
public interface OurFriend {
void speak();
}
// 适配器
public class CatFriend extends Cat implements OurFriend{
@Override
public void speak() {
super.makeSound();
}
}
- 好处:
- 避免调用类要根据不同的实现写一堆if-else
- 避免违反开闭原则,新增一个实现类,调用类就得修改if-else
Spring MVC中的适配器模式
-
在 Spring MVC 中,
DispatcherServlet
根据请求信息调用HandlerMapping
,解析请求对应的Handler
。 -
解析到对应的
Handler
(也就是我们平常说的Controller
控制器)后,开始由HandlerAdapter
适配器处理。 -
HandlerAdapter
作为期望接口,具体的适配器实现类用于对目标类进行适配,Controller
作为需要适配的类。
因为Controller的实现各种各样。1、@RequestMapping标注的实现 2、传统的基于Controller接口(注意不是@Controller注解)的实现 ……。他们的处理方法都不一样,必须适配为HandlerAdapter接口。
Spring IOC中的适配器模式
DisposableBeanAdapter
,因为bean销毁方式多种多样,因此都要适配为DisposableBeanAdapter来统一。
销毁方式多种多样,有基于注解的,基于方法的,基于DisposableBean接口的等等,必须适配为对DisposableBean来统一调用销毁方法。
装饰者模式
什么是装饰器模式
装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
其主要缺点是:装饰器模式会增加许多子类,过度使用会增加程序得复杂性。
设计一个 Decorator 套在原有代码外面。
Decorator继承于Component【IS A关系】, 继承的目的是使用装饰者和被装饰都拥有相同的接口。这样用户可以统一的把它们看作成Component,操作起来没有不同。(比如加了调料的咖啡还是咖啡)
此外,组合的关系是HAS A,目的是做增强。
- 例子:
- 其实在 JDK 中就有很多地方用到了装饰者模式,比如
InputStream
家族,InputStream
类下有FileInputStream
(读取文件)、BufferedInputStream
(增加缓存,使读取文件速度大大提升)等子类都在不修改InputStream
代码的情况下扩展了它的功能。
- 其实在 JDK 中就有很多地方用到了装饰者模式,比如
Spring DataSource中的装饰器模式
Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下动态切换不同的数据源?这个时候就要用到装饰者模式(这一点我自己还没太理解具体原理)。Spring 中用到的包装器模式在类名上含有 Wrapper
或者 Decorator
。这些类基本上都是动态地给一个对象添加一些额外的职责
Spring Security
用处
- 登录验证JWT机制 + 权限控制
- 对密码进行加密:
- 如果我们需要保存密码这类敏感数据到数据库的话,需要先加密再保存。
- Spring Security 提供了多种加密算法的实现,开箱即用,非常方便。
JWT
JWT和session最重要的区别?
- JWT不需要存储,而是在服务端根据前端传回的token进行解密比对处理
- session是在用户登录之后,给浏览器返回一个sessionid,另外在服务器端同时存储sessionid及必要的用户信息,在用户使用cookie把sessionid传回服务端,服务端基于sessionid去数据库查询,若查到则表示用户还在活跃期,同时也可以获取到存储的必要用户信息。
什么是JWT
为啥不用redis?
优点是多台服务器都是使用 redis 来存取 token,不存在不共享的问题,所以容易扩展。
缺点是每次请求都需要查一下redis,会造成 redis 的压力,还有增加了请求的耗时,每个已登录的用户都要保存一个 token 在 redis,也会消耗 redis 的存储空间。
jwt和redis token对比
如果项目并不大,jwt 是个好选择,天然的去中心化模式,会话状态由令牌本身自解释,简单粗暴。
但是缺点也很明显,如题所示,一旦下发便不受服务端控制,如果发生 Token 泄露,服务器也只能任其蹂躏,在其未过期期间不能有任何措施。
常见的做法是从 jwt 上再封装一层,提供一个类似黑名单的机制,每次访问系统时先检查此 jwt 令牌是否已经被拉黑。
此模式虽然暂时解决了问题,但是此时你会发现,项目架构又回到了传统 Session 模型中,对 jwt 来讲属于自断招牌。
so use redis please!
Spring Data JPA
JPA是什么?
- JPA 与 Hibernate什么关系:
- JPA 是 一个标准的接口
- Hibernate 是 JPA 的一个实现
- JPA作用:使得应用程序以统一的方式访问持久层
- ORM、API、findby的查询语法
- 这些框架能防sql注入
如何使用 JPA 在数据库中非持久化一个字段?
@transient
实体之间的关联关系注解有哪些?
@OneToOne
: 一对一。@ManyToMany
:多对多。@OneToMany
: 一对多。@ManyToOne
:多对一。
利用 @ManyToOne
和 @OneToMany
也可以表达多对多的关联关系。
个人使用体验,JPA面对动态的复杂SQL模型的创建(因为可能要复用),非常麻烦,Specification能用的语法也很有限,看了一遍也找不到能满足要求的。有时候只能写好几个几乎一样的sql,很浪费。