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類裡面實現,那麼我們先來看看這個類的層次關係
流程說明
- 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。