谈谈Spring中都用到了那些设计模式

2023-12-25 19:03:50 浏览数 (2)

写作目的

看看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常用模式--------装饰者模式 - 简书

0 人点赞