1. 程式人生 > >Spring原始碼分析解讀

Spring原始碼分析解讀

Spring原始碼分析解讀

如何檢視原始碼

Spring原始碼下載https://github.com/spring-projects/spring-framework/tags?after=v3.1.0.RC1

原始碼結構組織

Build-spring-framework是整個Spring原始碼的構建目錄,裡面是專案的構建指令碼,如果要自己動手構建Spring,可以進入這個目錄使用ANT進行構建。

l  org.springframework.context是IoC容器的原始碼目錄

l  org.springframework.aop是AOP實現的原始碼目錄

l  org.springframework.jdbc是JDBC的原始碼部分

l  org.springframework.orm是O/R Mapping對應的原始碼實現部分

 

 

SpringIOC原始碼分析

IOC初始化

1、 XmlBeanFactory(屌絲IOC)的整個流程

2、 FileSystemXmlApplicationContext 的IOC容器流程

1、高富帥IOC解剖

2、 設定資源載入器和資源定位

3、AbstractApplicationContext的refresh函式載入Bean定義過程:

4、AbstractApplicationContext子類的refreshBeanFactory()方法:

5、AbstractRefreshableApplicationContext子類的loadBeanDefinitions方法:

6、AbstractBeanDefinitionReader讀取Bean定義資源:

7、資源載入器獲取要讀入的資源:

8、XmlBeanDefinitionReader載入Bean定義資源:

9、DocumentLoader將Bean定義資源轉換為Document物件:

10、XmlBeanDefinitionReader解析載入的Bean定義資原始檔:

11、DefaultBeanDefinitionDocumentReader對Bean定義的Document物件解析:

12、BeanDefinitionParserDelegate解析Bean定義資原始檔中的<Bean>元素:

13、BeanDefinitionParserDelegate解析<property>元素:

14、解析<property>元素的子元素:

15、解析<list>子元素:

16、解析過後的BeanDefinition在IoC容器中的註冊:

17、DefaultListableBeanFactory向IoC容器註冊解析後的BeanDefinition:

IOC體系

BeanFactory

         Spring Bean的建立是典型的工廠模式,這一系列的Bean工廠,也即IOC容器為開發者管理物件間的依賴關係提供了很多便利和基礎服務,在Spring中有許多的IOC容器的實現供使用者選擇和使用,其相互關係如下:

 

 

BeanFactory 

 BeanFactory定義了 IOC 容器的最基本形式,並提供了 IOC 容器應遵守的的最基本的介面,也就是Spring IOC 所遵守的最底層和最基本的程式設計規範。在  Spring 程式碼中, BeanFactory 只是個介面,並不是 IOC容器的具體實現,但是 Spring 容器給出了很多種實現,如 DefaultListableBeanFactory  XmlBeanFactory ApplicationContext 等,都是附加了某種功能的實現。

public interface BeanFactory {

//這裡是對FactoryBean的轉義定義,因為如果使用bean的名字檢索FactoryBean得到的物件是工廠生成的物件,  

  //如果需要得到工廠本身,需要轉義    

    //轉義符“&”用來獲取FactoryBean本身

String FACTORY_BEAN_PREFIX = "&";

//根據bean的名字進行獲取bean的例項,這是IOC最大的抽象方法

Object getBean(String name) throws BeansException;

//根據bean的名字和Class型別進行獲取Bean的例項,和上面方法不同的是,bean名字和Bean 的class型別不同時候會爆出異常

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

<T> T getBean(Class<T> requiredType) throws BeansException;

Object getBean(String name, Object... args) throws BeansException;

//檢測這個IOC容器中是否含有這個Bean

boolean containsBean(String name);

//判斷這個Bean是不是單利

 

boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

//判斷這個Bean是不是原型

boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

//查詢指定的bean的名字和Class型別是不是指定的Class型別

boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException;

//這裡對得到bean例項的Class型別

Class<?> getType(String name) throws NoSuchBeanDefinitionException;

//這裡得到bean的別名,如果根據別名檢索,那麼其原名也會被檢索出來 

String[] getAliases(String name);

}

BeanDefinition 

這個介面,可以理解為xml bean元素的資料載體。通過對比xml bean標籤的屬性列表和BeanDefinition的屬性列表一看便知。

我的理解,是解析XML的過程,就是 xml <bean>元素內容 轉換為BeanDefinition物件的過程。而且這個介面,支援層級,對應物件的繼承。

有一個類BeanDefinitionHolder,BeanDefinitionHolder,根據名稱或者別名持有beanDefinition,它承載了name和BeanDefinition的對映資訊。

BeanWarpper:

提供對標準javabean的分析和操作方法:單個或者批量獲取和設定屬性值,獲取屬性描述符,查詢屬性的可讀性和可寫性等。支援屬性的巢狀設定,深度沒有限制。

AbstractRefreshableApplicationContext的refreshBeanFactory()這個方法

protected final void refreshBeanFactory() throws BeansException {

if (hasBeanFactory()) {

destroyBeans();

closeBeanFactory();

}

try {

DefaultListableBeanFactory beanFactory = createBeanFactory();//建立IOC容器

beanFactory.setSerializationId(getId());

customizeBeanFactory(beanFactory);

loadBeanDefinitions(beanFactory);//載入loadBeanDefinitions

synchronized (this.beanFactoryMonitor) {

this.beanFactory = beanFactory;

}

}

catch (IOException ex) {

throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);

}

}

public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {  實現

/**

 * Loads the bean definitions via an XmlBeanDefinitionReader.

 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader

 * @see #initBeanDefinitionReader

 * @see #loadBeanDefinitions

 */

@Override

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

// Create a new XmlBeanDefinitionReader for the given BeanFactory.

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);



// Configure the bean definition reader with this context's

// resource loading environment.

beanDefinitionReader.setResourceLoader(this);

beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));



// Allow a subclass to provide custom initialization of the reader,

// then proceed with actually loading the bean definitions.

initBeanDefinitionReader(beanDefinitionReader);

loadBeanDefinitions(beanDefinitionReader);

}

先呼叫本類裡面的loadBeanDefinitions

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

Resource[] configResources = getConfigResources();

if (configResources != null) {

reader.loadBeanDefinitions(configResources);

}

String[] configLocations = getConfigLocations();

if (configLocations != null) {

reader.loadBeanDefinitions(configLocations);

}

}



委託給reader.loadBeanDefinitions(configLocation);    XmlBeanDefinitionReader
通過XmlBeanDefinitionReader來讀取。下面看一下XmlBeanDefinitionReader這個方法,但其實並不在這個類實現這個方法,而是在它的基類裡面AbstractBeanDefinitionReader

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {

Assert.notNull(locations, "Location array must not be null");

int counter = 0;

for (String location : locations) {

counter += loadBeanDefinitions(location);

}

return counter;

}

進入到loadBeanDefinitions

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

Assert.notNull(encodedResource, "EncodedResource must not be null");

if (logger.isInfoEnabled()) {

logger.info("Loading XML bean definitions from " + encodedResource.getResource());

}



Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

if (currentResources == null) {

currentResources = new HashSet<EncodedResource>(4);

this.resourcesCurrentlyBeingLoaded.set(currentResources);

}

if (!currentResources.add(encodedResource)) {

throw new BeanDefinitionStoreException(

"Detected cyclic loading of " + encodedResource + " - check your import definitions!");

}

try {

InputStream inputStream = encodedResource.getResource().getInputStream();//獲取IO

try {

InputSource inputSource = new InputSource(inputStream);

if (encodedResource.getEncoding() != null) {

inputSource.setEncoding(encodedResource.getEncoding());

}

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());//這個方法從流中讀取

}

finally {

inputStream.close();

}

}

catch (IOException ex) {

throw new BeanDefinitionStoreException(

"IOException parsing XML document from " + encodedResource.getResource(), ex);

}

finally {

currentResources.remove(encodedResource);

if (currentResources.isEmpty()) {

this.resourcesCurrentlyBeingLoaded.remove();

}

}

}

進入到doLoadBeanDefinitions  Resource IO封裝

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

throws BeanDefinitionStoreException {

try {

int validationMode = getValidationModeForResource(resource);

Document doc = this.documentLoader.loadDocument(

inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());

return registerBeanDefinitions(doc, resource); //解析XML

}

catch (BeanDefinitionStoreException ex) {

throw ex;

}

catch (SAXParseException ex) {

throw new XmlBeanDefinitionStoreException(resource.getDescription(),

"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);

}

catch (SAXException ex) {

throw new XmlBeanDefinitionStoreException(resource.getDescription(),

"XML document from " + resource + " is invalid", ex);

}

catch (ParserConfigurationException ex) {

throw new BeanDefinitionStoreException(resource.getDescription(),

"Parser configuration exception parsing XML from " + resource, ex);

}

catch (IOException ex) {

throw new BeanDefinitionStoreException(resource.getDescription(),

"IOException parsing XML document from " + resource, ex);

}

catch (Throwable ex) {

throw new BeanDefinitionStoreException(resource.getDescription(),

"Unexpected exception parsing XML document from " + resource, ex);

}

}

進入到registerBeanDefinitions

/**

 * Register the bean definitions contained in the given DOM document.

 * Called by <code>loadBeanDefinitions</code>.

 * <p>Creates a new instance of the parser class and invokes

 * <code>registerBeanDefinitions</code> on it.

 * @param doc the DOM document

 * @param resource the resource descriptor (for context information)

 * @return the number of bean definitions found

 * @throws BeanDefinitionStoreException in case of parsing errors

 * @see #loadBeanDefinitions

 * @see #setDocumentReaderClass

 * @see BeanDefinitionDocumentReader#registerBeanDefinitions

 */

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

// Read document based on new BeanDefinitionDocumentReader SPI.

BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

int countBefore = getRegistry().getBeanDefinitionCount();

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

return getRegistry().getBeanDefinitionCount() - countBefore;

}

documentReader.registerBeanDefinitionsXML解析

/**

 * Parses bean definitions according to the "spring-beans" DTD.

 * <p>Opens a DOM Document; then initializes the default settings

 * specified at <code><beans></code> level; then parses

 * the contained bean definitions.

 */

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {

this.readerContext = readerContext;



logger.debug("Loading bean definitions");

Element root = doc.getDocumentElement();



BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);



preProcessXml(root);

parseBeanDefinitions(root, delegate);

postProcessXml(root);

}

-----遍歷節點

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

if (delegate.isDefaultNamespace(root)) {

NodeList nl = root.getChildNodes();

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

if (node instanceof Element) {

Element ele = (Element) node;

if (delegate.isDefaultNamespace(ele)) {

parseDefaultElement(ele, delegate); //預設解析

}

else {

delegate.parseCustomElement(ele);

}

}

}

}

else {

delegate.parseCustomElement(root);

}

}

---判斷解析類

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {

if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {

importBeanDefinitionResource(ele);//import型別

}

else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {

processAliasRegistration(ele);//別名方式

}

else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {

processBeanDefinition(ele, delegate);//bean解析方式

}

}

 

Bean的解析方式

進入到 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);   使用反射初始化類

public AbstractBeanDefinition parseBeanDefinitionElement(

Element ele, String beanName, BeanDefinition containingBean) {



this.parseState.push(new BeanEntry(beanName));



String className = null;

if (ele.hasAttribute(CLASS_ATTRIBUTE)) {

className = ele.getAttribute(CLASS_ATTRIBUTE).trim();

}



try {

String parent = null;

if (ele.hasAttribute(PARENT_ATTRIBUTE)) {

parent = ele.getAttribute(PARENT_ATTRIBUTE);

}

AbstractBeanDefinition bd = createBeanDefinition(className, parent);



parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));



parseMetaElements(ele, bd);

parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

parseReplacedMethodSubElements(ele, bd.getMethodOverrides());



parseConstructorArgElements(ele, bd);

parsePropertyElements(ele, bd);

parseQualifierElements(ele, bd);



bd.setResource(this.readerContext.getResource());

bd.setSource(extractSource(ele));



return bd;

}

catch (ClassNotFoundException ex) {

error("Bean class [" + className + "] not found", ele, ex);

}

catch (NoClassDefFoundError err) {

error("Class that bean class [" + className + "] depends on not found", ele, err);

}

catch (Throwable ex) {

error("Unexpected failure during bean definition parsing", ele, ex);

}

finally {

this.parseState.pop();

}



return null;

}

進入到AbstractBeanDefinition bd = createBeanDefinition(className, parent);

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)

throws ClassNotFoundException {



return BeanDefinitionReaderUtils.createBeanDefinition(

parentName, className, this.readerContext.getBeanClassLoader());

}

進入到BeanDefinitionReaderUtils.createBeanDefinition

public static AbstractBeanDefinition createBeanDefinition(

String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {



GenericBeanDefinition bd = new GenericBeanDefinition();

bd.setParentName(parentName);

if (className != null) {

if (classLoader != null) {

bd.setBeanClass(ClassUtils.forName(className, classLoader));//使用java反射機制初始化

}

else {

bd.setBeanClassName(className);

}

}

return bd;

}

 

 

Bean生命週期分析

1.Spring對Bean進行例項化(相當於程式中的new Xx())

2.Spring將值和Bean的引用注入進Bean對應的屬性中

3.如果Bean實現了BeanNameAware介面,Spring將Bean的ID傳遞給setBeanName()方法 
(實現BeanNameAware清主要是為了通過Bean的引用來獲得Bean的ID,一般業務中是很少有用到Bean的ID的)

4.如果Bean實現了BeanFactoryAware介面,Spring將呼叫setBeanDactory(BeanFactory bf)方法並把BeanFactory容器例項作為引數傳入。 
(實現BeanFactoryAware 主要目的是為了獲取Spring容器,如Bean通過Spring容器釋出事件等)

5.如果Bean實現了ApplicationContextAwaer介面,Spring容器將呼叫setApplicationContext()方法,把bean所在的應用上下文的引用傳入. 
(作用與BeanFactory類似都是為了獲取Spring容器,不同的是Spring容器在呼叫setApplicationContext方法時會把它自己作為setApplicationContext 的引數傳入,而Spring容器在呼叫setBeanDactory前需要程式設計師自己指定(注入)setBeanDactory裡的引數BeanFactory )

6.如果Bean實現了BeanPostProcess介面,Spring將呼叫它們的postProcessBeforeInitialization(預初始化)方法 
(作用是在Bean例項建立成功後對進行增強處理,如對Bean進行修改,增加某個功能)

7.如果Bean實現了InitializingBean介面,Spring將呼叫它們的afterPropertiesSet方法,作用與在配置檔案中對Bean使用init-method宣告初始化的作用一樣,都是在Bean的全部屬性設定成功後執行的初始化方法。

8.如果Bean實現了BeanPostProcess介面,Spring將呼叫它們的postProcessAfterInitialization(後初始化)方法(作用與6的一樣,只不過6是在Bean初始化前執行的,而這個是在Bean初始化後執行的,時機不同 )

9.此時,bean已經準備就緒,可以被程式使用了,Bean將一直駐留在應用上下文中給應用使用,直到應用上下文被銷燬

10.如果Bean實現了DispostbleBean介面,Spring將呼叫它的destory方法,作用與在配置檔案中對Bean使用destory-method屬性的作用一樣,都是在Bean例項銷燬前執行的方法。

@Component 

public class UserEntity implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean,DisposableBean {

private String userName;

private Integer age = null;

public UserEntity() {

System.out.println("無慘建構函式.....");

}


public UserEntity(String userName, Integer age) {

System.out.println("我是有參建構函式 userName:" + userName + ",age:" + age);

this.userName = userName;

this.age = age;

}


public String getUserName() {


return userName;

}


public void setUserName(String userName) {

this.userName = userName;

}



public Integer getAge() {



return age;

}



public void setAge(Integer age) {



this.age = age;

}



@Override

public String toString() {

return "UserEntity [userName=" + userName + ", age=" + age + "]";

}



public void setBeanName(String name) {

System.out.println("BeanName:" + name);

}



public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

System.out.println("setBeanFactory");

}



public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

System.out.println("setApplicationContext");

}



public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

System.out.println("postProcessBeforeInitialization bean初始化之前" + beanName);

return bean;



}



public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

System.out.println("postProcessAfterInitialization bean初始化之後" + beanName);

return bean;



}

    public void init(){

     System.out.println("init()");

    }

public void afterPropertiesSet() throws Exception {

System.out.println("afterPropertiesSet");

}



public void destroy() throws Exception {

 System.out.println("destroy 銷燬bean");

    

}



}

ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("spring003.xml");

UserEntity user = (UserEntity) app.getBean("userEntity");

app.destroy();

 

SpringAop原始碼分析

AOP簡介

概念

切面(Aspect) :官方的抽象定義為“一個關注點的模組化,這個關注點可能會橫切多個物件”。
連線點(Joinpoint) :程式執行過程中的某一行為。
通知(Advice) :“切面”對於某個“連線點”所產生的動作。
切入點(Pointcut) :匹配連線點的斷言,在AOP中通知和一個切入點表示式關聯。
目標物件(Target Object) :被一個或者多個切面所通知的物件。
AOP代理(AOP Proxy) 在Spring AOP中有兩種代理方式,JDK動態代理和CGLIB代理。

通知(Advice)型別
前置通知(Before advice) :在某連線點(JoinPoint)之前執行的通知,但這個通知不能阻止連線點前的執行。ApplicationContext中在<aop:aspect>裡面使用<aop:before>元素進行宣告。
後通知(After advice) :當某連線點退出的時候執行的通知(不論是正常返回還是異常退出)。ApplicationContext中在<aop:aspect>裡面使用<aop:after>元素進行宣告。
返回後通知(After return advice) :在某連線點正常完成後執行的通知,不包括丟擲異常的情況。ApplicationContext中在<aop:aspect>裡面使用<after-returning>元素進行宣告。
環繞通知(Around advice) :包圍一個連線點的通知,類似Web中Servlet規範中的Filter的doFilter方法。可以在方法的呼叫前後完成自定義的行為,也可以選擇不執行。ApplicationContext中在<aop:aspect>裡面使用<aop:around>元素進行宣告。
丟擲異常後通知(After throwing advice) : 在方法丟擲異常退出時執行的通知。 ApplicationContext中在<aop:aspect>裡面使用<aop:after-throwing>元素進行宣告。

切入點表示式 :如execution(* com.spring.service.*.*(..))

特點

1、降低模組之間的耦合度

2、使系統容易擴充套件

3、更好的程式碼複用。

流程說明

1)AOP標籤的定義解析劉徹骨肯定是從NamespaceHandlerSupport的實現類開始解析的,這個實現類就是AopNamespaceHandler。至於為什麼會是從NamespaceHandlerSupport的實現類開始解析的,這個的話我想讀者可以去在回去看看Spring自定義標籤的解析流程,裡面說的比較詳細。

2)要啟用AOP,我們一般會在Spring裡面配置<aop:aspectj-autoproxy/>  ,所以在配置檔案中在遇到aspectj-autoproxy標籤的時候我們會採用AspectJAutoProxyBeanDefinitionParser解析器

3)進入AspectJAutoProxyBeanDefinitionParser解析器後,呼叫AspectJAutoProxyBeanDefinitionParser已覆蓋BeanDefinitionParser的parser方法,然後parser方法把請求轉交給了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去處理

4)進入AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法後,先呼叫AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,裡面在轉發呼叫給registerOrEscalateApcAsRequired,註冊或者升級AnnotationAwareAspectJAutoProxyCreator類。對於AOP的實現,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根據@point註解定義的切點來代理相匹配的bean。

5)AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法處理完成之後,接下來會呼叫useClassProxyingIfNecessary() 處理proxy-target-class以及expose-proxy屬性。如果將proxy-target-class設定為true的話,那麼會強制使用CGLIB代理,否則使用jdk動態代理,expose-proxy屬性是為了解決有時候目標物件內部的自我呼叫無法實現切面增強。

6)最後的呼叫registerComponentIfNecessary 方法,註冊組建並且通知便於監聽器做進一步處理。

 

建立AOP代理

上面說到AOP的核心邏輯是在AnnotationAwareAspectJAutoProxyCreator類裡面實現,那麼我們先來看看這個類的層次關係

流程說明

  1. spring 容器啟動,每個bean的例項化之前都會先經過AbstractAutoProxyCreator類的postProcessAfterInitialization()這個方法,然後接下來是呼叫wrapIfNecessary方法。

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

if (bean != null) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);

if (!this.earlyProxyReferences.contains(cacheKey)) {

return wrapIfNecessary(bean, beanName, cacheKey);

}

}

return bean;

}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

if (this.targetSourcedBeans.contains(beanName)) {

return bean;

}

if (this.nonAdvisedBeans.contains(cacheKey)) {

return bean;

}

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {

this.nonAdvisedBeans.add(cacheKey);

return bean;

}

 

// Create proxy if we have advice.

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

if (specificInterceptors != DO_NOT_PROXY) {

this.advisedBeans.add(cacheKey);

Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

this.proxyTypes.put(cacheKey, proxy.getClass());

return proxy;

}

 

this.nonAdvisedBeans.add(cacheKey);

return bean;

}

建立代理物件

protected Object createProxy(

Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

 

ProxyFactory proxyFactory = new ProxyFactory();

// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.

proxyFactory.copyFrom(this);

 

if (!shouldProxyTargetClass(beanClass, beanName)) {

// Must allow for introductions; can't just set interfaces to

// the target's interfaces only.

Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);

for (Class<?> targetInterface : targetInterfaces) {

proxyFactory.addInterface(targetInterface);

}

}

 

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

for (Advisor advisor : advisors) {

proxyFactory.addAdvisor(advisor);

}

 

proxyFactory.setTargetSource(targetSource);

customizeProxyFactory(proxyFactory);

 

proxyFactory.setFrozen(this.freezeProxy);

if (advisorsPreFiltered()) {

proxyFactory.setPreFiltered(true);

}

 

return proxyFactory.getProxy(this.proxyClassLoader);

}

 

 

 

SpringMVC執行流程

 

Spring MVC工作流程圖

 

圖一

 

圖二 

 

Spring工作流程描述

      1. 使用者向伺服器傳送請求,請求被Spring 前端控制Servelt DispatcherServlet捕獲;

      2. DispatcherServlet對請求URL進行解析,得到請求資源識別符號(URI)。然後根據該URI,呼叫HandlerMapping獲得該Handler配置的所有相關的物件(包括Handler物件以及Handler物件對應的攔截器),最後以HandlerExecutionChain物件的形式返回;

      3. DispatcherServlet 根據獲得的Handler,選擇一個合適的HandlerAdapter。(附註:如果成功獲得HandlerAdapter後,此時將開始執行攔截器的preHandler(...)方法

       4.  提取Request中的模型資料,填充Handler入參,開始執行Handler(Controller)。 在填充Handler的入參過程中,根據你的配置,Spring將幫你做一些額外的工作:

      HttpMessageConveter: 將請求訊息(如Json、xml等資料)轉換成一個物件,將物件轉換為指定的響應資訊

      資料轉換:對請求訊息進行資料轉換。如String轉換成Integer、Double等

      資料根式化:對請求訊息進行資料格式化。 如將字串轉換成格式化數字或格式化日期等

      資料驗證: 驗證資料的有效性(長度、格式等),驗證結果儲存到BindingResult或Error中

      5.  Handler執行完成後,向DispatcherServlet 返回一個ModelAndView物件;

      6.  根據返回的ModelAndView,選擇一個適合的ViewResolver(必須是已經註冊到Spring容器中的ViewResolver)返回給DispatcherServlet ;

      7. ViewResolver 結合Model和View,來渲染檢視

      8. 將渲染結果返回給客戶端。

 

Spring工作流程描述

    為什麼Spring只使用一個Servlet(DispatcherServlet)來處理所有請求?

     詳細見J2EE設計模式-前端控制模式

    Spring為什麼要結合使用HandlerMapping以及HandlerAdapter來處理Handler?

    符合面向物件中的單一職責原則,程式碼架構清晰,便於維護,最重要的是程式碼可複用性高。如HandlerAdapter可能會被用於處理多種Handler。