日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

Spring啟動原理和可擴展設計分析

簡述

spring核心是一個容器,但是卻能在它身上像插件一樣集成很多功能,在設計上要做到封閉修改、擴展開放,這一點spring做的很優秀,對開發框架有很好的借鑒和指導意義。

本文通過分析spring的啟動過程來分析spring擴展開放的設計實現,下面主要集中在兩個點來分析:Aware和BeanPostProcessor。spring自身很多擴展功能也都是通過這兩個機制來實現。

原則

spring在啟動過程中會注冊很多回調來實現各種擴展功能,回調的形式最重要的是Aware和BeanPostProcessor。

spring各種不同業務都是一個思路:

  1. 創建不同的ApplicationContext
  2. 不同的ApplicationContext寫死一個Aware類型的BeanPostProcessor
  3. 由寫死的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

  1. ApplicationContextAware
  2. ApplicationEventPublisherAware
  3. ResourceLoaderAware
  4. EmbeddedValueResolverAware
  5. 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

  1. ServletContextAware
  2. 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

  1. web.xml 里的context-param找contextClass
  2. 沒有的話就加載默認: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啟動原理和可擴展設計分析

 

spring mvc

Spring MVC的入口是Controller,那么解析Controller的東西自然就是SpringMVC的入口了。

這個入口就是:

RequestMappingHandlerMapping

這個東西繼承了3個Aware

  1. ApplicationAware(Spring web)
  2. ServletContextAware (Spring web)
  3. 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);
 }
}

分享到:
標簽:Spring
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定