写作目的
看看Spring和SpringMVC源码还是有必要的,而且里面用了很多经典的设计模式,所以从源码角度分析一下Spring中的设计模式。
源码下载
ChaiRongD/Demooo - Gitee.com
ChaiRongD/Demooo - Gitee.com
设计模式
工厂设计模式
Spring使用工厂模式可以通过 ApplicationContext
创建和获取 bean 对象。其实这里就有一个问题,ApplicationContext和BeanFactory有什么关系呢?其实这个问题可以从源码中看出来。
下面是获取ioc容器的context,根据名称获取Bean,这段代码大家都比较熟悉
代码语言:javascript复制 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
Student bean = (Student) context.getBean("student");
bean.speak();
其实你跟跟进去getBean方法,你就会大吃一惊,是核心还是beanFactory。
代码语言:javascript复制@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
单例设计模式
Spring中Bean默认都是单例的,既然是单例的,那存在哪呢,其实是存在一个map里。其实一共使用了三个map,又称作三级缓存。
代码语言:javascript复制//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是单例的,但是也存在线程不安全的情况。如下面代码所示。
代码语言:javascript复制@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()方法,这个地方就是模版方法模式
代码语言:javascript复制AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
代码语言:javascript复制public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
观察者模式
观察者模式的一个落地实现是listener,Spring也有Listener
多线程在Spring中的使用_CBeann的博客-CSDN博客
适配器模式
SpringMVC中有一个核心的servlet就是DispatcherServlet,该方法里有一个Servlet有一个方式是doDispatch,先获取HanderMethod(就是有@GetMapping的方法),然后在获取适配器Adapter,这说明有好几种HanderMethod,其实实现controller有三种方式
代码语言:javascript复制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 {
}
}
装饰者模式
其实我看源码没有看到,主要原因是自己水平还有待提高,所以有些看不太懂,这里找了一篇文章,做为补充。
(10)spring常用模式--------装饰者模式 - 简书
参考
面试官:“谈谈Spring中都用到了那些设计模式?”。 - 知乎
Spring中用到了哪些设计模式? - murphy_gb - 博客园
controller的三种实现方式_chuhuai8266的博客-CSDN博客
(10)spring常用模式--------装饰者模式 - 简书