Spring啟動原理和可擴展設計分析
簡述
spring核心是一個容器,但是卻能在它身上像插件一樣集成很多功能,在設計上要做到封閉修改、擴展開放,這一點spring做的很優(yōu)秀,對開發(fā)框架有很好的借鑒和指導意義。
本文通過分析spring的啟動過程來分析spring擴展開放的設計實現(xiàn),下面主要集中在兩個點來分析:Aware和BeanPostProcessor。spring自身很多擴展功能也都是通過這兩個機制來實現(xiàn)。
原則
spring在啟動過程中會注冊很多回調來實現(xiàn)各種擴展功能,回調的形式最重要的是Aware和BeanPostProcessor。
spring各種不同業(yè)務都是一個思路:
- 創(chuàng)建不同的ApplicationContext
- 不同的ApplicationContext寫死一個Aware類型的BeanPostProcessor
- 由寫死的Aware類型BeanPostProcessor來加載特殊業(yè)務的各種邏輯
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里會觸發(fā)各種aware
- ApplicationContextAware
- ApplicationEventPublisherAware
- ResourceLoaderAware
- EmbeddedValueResolverAware
- EnvironmentAware
實現(xiàn)Aware的各種bean接收到回調后就能獲取各自想要的東西(ApplicationContext、ResourceLoader等),有了這些東西他們就可以實現(xiàn)自己的個性化邏輯
spring web啟動
下面以spring web為例看看Spring web是如何在spring的基礎上實現(xiàn)擴展的。
spring web的ApplicationContext大多集成自AbstractRefreshableWebApplicationContext
首先,還是那個套路,創(chuàng)建特殊的ApplicationContext,然后寫死一個BeanPostProcessor
AbstractRefreshableWebApplicationContext#postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
}
ServletContextAwareProcessor處理兩種類型的Aware
- ServletContextAware
- ServletConfigAware
這是上面說的典型的套路
實現(xiàn)了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);
}
}






