Spring啟動原理和可擴展設計分析
簡述
spring核心是一個容器,但是卻能在它身上像插件一樣集成很多功能,在設計上要做到封閉修改、擴展開放,這一點spring做的很優秀,對開發框架有很好的借鑒和指導意義。
本文通過分析spring的啟動過程來分析spring擴展開放的設計實現,下面主要集中在兩個點來分析:Aware和BeanPostProcessor。spring自身很多擴展功能也都是通過這兩個機制來實現。
原則
spring在啟動過程中會注冊很多回調來實現各種擴展功能,回調的形式最重要的是Aware和BeanPostProcessor。
spring各種不同業務都是一個思路:
- 創建不同的ApplicationContext
- 不同的ApplicationContext寫死一個Aware類型的BeanPostProcessor
- 由寫死的Aware類型BeanPostProcessor來加載特殊業務的各種邏輯
Aware
每當spring容器完成某件事情(如ApplicationContext初始化完成)時都會通知Aware,Aware通常都具有一些setXXX()的方法,如BeanFactoryAware:
public interface BeanFactoryAware extends Aware { void setBeanFactory(BeanFactory beanFactory) throws BeansException; }
BeanPostProcessor
可以對spring掃描到的bean做手腳,初始化前和后
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
Spring 啟動過程
spring容器啟動的模板編排在org.springframework.context.support.AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException { prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //子類通常在這里添加自己需要的BeanPostProcessor postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //查找所有BeanPostProcessor并注冊到容器中,bean初始化時會來調用bpp registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } }
其中AbstractApplicationContext#prepareBeanFactory里注冊ApplicationContext的Aware處理器:
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))
ApplicationContextAwareProcessor里會觸發各種aware
- ApplicationContextAware
- ApplicationEventPublisherAware
- ResourceLoaderAware
- EmbeddedValueResolverAware
- EnvironmentAware
實現Aware的各種bean接收到回調后就能獲取各自想要的東西(ApplicationContext、ResourceLoader等),有了這些東西他們就可以實現自己的個性化邏輯
spring web啟動
下面以spring web為例看看Spring web是如何在spring的基礎上實現擴展的。
spring web的ApplicationContext大多集成自AbstractRefreshableWebApplicationContext
首先,還是那個套路,創建特殊的ApplicationContext,然后寫死一個BeanPostProcessor
AbstractRefreshableWebApplicationContext#postProcessBeanFactory
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); }
ServletContextAwareProcessor處理兩種類型的Aware
- ServletContextAware
- ServletConfigAware
這是上面說的典型的套路
實現了ServletContextAware的bean就這樣獲取到了web上下文,可以做自己的事情了
spring web初始化方式
web.xml + ContextLoaderListener
< listener > < listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class > </ listener > <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:conf/spring/applicationContext.xml</param-value> </context-param>
ContextLoaderListener 初始化WebApplicationContext 判斷啟動哪種WebApplicationContext
- web.xml 里的context-param找contextClass
- 沒有的話就加載默認:spring jar里ContextLoader.properties寫的XmlWebApplicationContext
web.mxl + DispatcherServlet
<servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet>
DispatcherServlet基于Servlet生命周期會在JAVAx.servlet.GenericServlet.init()初始化spring容器
springboot
DispatcherServletAutoConfiguration
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest( this.webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest( this.webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound( this.webMvcProperties.isThrowExceptionIfNoHandlerFound()); return dispatcherServlet; }
Spring MVC原理
接著上面的web原理
Dispatcher
Dispatcher是一個Servlet,是spring web的入口,來看下spring的dispatcher如何處理請求
spring mvc
Spring MVC的入口是Controller,那么解析Controller的東西自然就是SpringMVC的入口了。
這個入口就是:
RequestMappingHandlerMapping
這個東西繼承了3個Aware
- ApplicationAware(Spring web)
- ServletContextAware (Spring web)
- EmbeddedValueResolverAware (Spring context)
是不是很熟悉!
通過Aware,Spring mvc就這么起來了!并且能夠自定義解析各種注解
RequestMappingHandlerMapping
內部維護一個Map<T, HandlerMethod> handlerMethods,T就是Controller的類
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping, EmbeddedValueResolverAware { /** 1. 初始化 */ public void afterPropertiesSet() { initHandlerMethods(); } /** 2. 掃描所有Object的bean,掃描Controller、RequestMapping 3. 掃描每個controller的web請求方法,寫入到handlerMethods里,以后處理請求時用來對應查找 */ protected void initHandlerMethods() { String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ //查找web請求方法 detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); } @Override protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); } /** 4. 處理web請求時負責找到對應的處理方法 */ @Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } /** 組裝HandlerExecutionChain,里面主要包括處理列表: List<HandlerInterceptor> interceptorList; */ return getHandlerExecutionChain(handler, request); } }