谈谈Spring中都用到了那些设计模式
写作目的
看看Spring和SpringMVC源码还是有必要的,而且里面用了很多经典的设计模式,所以从源码角度分析一下Spring中的设计模式。
源码下载
https://gitee.com/cbeann/Demooo/tree/master/spring-demo
https://gitee.com/cbeann/Demooo/tree/master/springmvc-demo-app
设计模式
工厂设计模式
Spring使用工厂模式可以通过 ApplicationContext
创建和获取 bean 对象。其实这里就有一个问题,ApplicationContext和BeanFactory有什么关系呢?其实这个问题可以从源码中看出来。
下面是获取ioc容器的context,根据名称获取Bean,这段代码大家都比较熟悉
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
Student bean = (Student) context.getBean("student");
bean.speak();
其实你跟跟进去getBean方法,你就会大吃一惊,是核心还是beanFactory。
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
单例设计模式
Spring中Bean默认都是单例的,既然是单例的,那存在哪呢,其实是存在一个map里。其实一共使用了三个map,又称作三级缓存。
//DefaultSingletonBeanRegistry
/** 三级缓存(存放的是可以使用的Bean) */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 一级缓存(存放的是BeanFacory对象) */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 二级缓存(存放的是经过代理的获取不需要代理的对象,此时对象的属性还有部分没有被填充) */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从三级缓存冲获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//从一级缓存中获取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
虽然Bean是单例的,但是也存在线程不安全的情况。如下面代码所示。
@Controller
public class HelloController {
int num = 0;
@GetMapping("add")
public void add(){
num++;
}
}
代理设计模式
Spring中代理模式中使用的最经典的是AOP,这里跟源码就比较麻烦了,其实这里的知识点有jdk动态代理和cglib代理,这俩有什么区别,经典题。
1 jdk代理的类要有接口,cglib代理则不需要
2 cglib代理的时候生成的代理类生成速度慢,但是调用速度快,jdk反之。
模板方法模式
在获取context的地方有一个refresh()方法,这个地方就是模版方法模式
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
观察者模式
观察者模式的一个落地实现是listener,Spring也有Listener
https://blog.csdn.net/qq_37171353/article/details/113940911
适配器模式
SpringMVC中有一个核心的servlet就是DispatcherServlet,该方法里有一个Servlet有一个方式是doDispatch,先获取HanderMethod(就是有@GetMapping的方法),然后在获取适配器Adapter,这说明有好几种HanderMethod,其实实现controller有三种方式
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取handlerMethod,就是我们自己写个@GetMapper的方法
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取handlerMethod 的是适配器Adapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
}
catch (Throwable err) {
}
catch (Exception ex) {
}
catch (Throwable err) {
}
finally {
}
}
装饰者模式
其实我看源码没有看到,主要原因是自己水平还有待提高,所以有些看不太懂,这里找了一篇文章,做为补充。
https://www.jianshu.com/p/8f6ebeee1ae6
参考
https://zhuanlan.zhihu.com/p/66790602
https://www.cnblogs.com/kyoner/p/10949246.html
https://blog.csdn.net/chuhuai8266/article/details/100757333
https://www.jianshu.com/p/8f6ebeee1ae6
还没有评论,来说两句吧...