- 核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實現
- BeanFactory 使用控制反轉 (IOC) 模式將應用程序的配置和依賴性規範與實際的應用程序代碼分開
- 不建立對象,可是描述建立它們的方式。在代碼中不直接與對象和服務鏈接,但在配置文件中描述哪個組件須要哪一項服務。容器(在 Spring 框架中是 IOC 容器) 負責將這些聯繫在一塊兒,保持應用程序和對象依賴的鬆散耦合
- 控制權由應用代碼中轉到了外部容器,控制權的轉移,是所謂反轉
- 注入方式
- 服務須要實現專門的接口,經過接口,由對象提供這些服務,能夠從對象查詢依賴性
- 經過 JavaBean 的屬性(例如 setter 方法)分配依賴性(經常使用)
- 依賴性以構造函數的形式提供,不以 JavaBean 屬性的形式公開
- org.springframework.beans 包,這個包一般不是由用戶直接使用,而是由服務器將其用做其餘多數功能的底層中介
- BeanFactory 接口
- 它是工廠設計模式的實現,容許經過名稱建立和檢索對象。BeanFactory 也能夠管理對象之間的關係
- Bean 是被消極加載的,這意味在須要 bean 以前,bean 自己不會被初始化
- 支持兩種對象模型
- ListableBeanFactory
- HierarchicalBeanFactory
- AutowireCapableBeanFactory
- DefaultListableBeanFactory
- Bean定義:完整的描述了在 Spring 的配置文件中你定義的 <bean/> 節點中全部的信息,包括各類子節點,在 Spring 的內部他就被轉化成 BeanDefinition 對象
- Bean解析類
- BeanDefinitionReader
- BeanDefinitionDocumentReader
- XmlBeanDefinitionReader
- Ioc 容器實際上就是 Context 組件結合其餘兩個(Core和BeanFactory)組件共同構建了一個 Bean 關係網
- 構建的入口就在 AbstractApplicationContext 類的 refresh 方法中
- Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息
- Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能
- ApplicationContext
- ConfigurableApplicationContext
- 表示該 Context 是可修改的,也就是在構建 Context 中用戶能夠動態添加或修改已有的配置信息
- 下面又有多個子類,其中最常用的是可更新的 Context,即 AbstractRefreshableApplicationContext 類
- 爲 web 準備的 Context 他能夠直接訪問到 ServletContext
- 全部的資源都被能夠經過 InputStream 這個類來獲取,因此也屏蔽了資源的提供者
- ResourceLoader 接口負責資源的統一加載
- Context 是把資源的加載、解析和描述工做委託給了 ResourcePatternResolver 類來完成,他至關於一個接頭人,他把資源的加載、解析和資源的定義整合在一塊兒便於其餘組件使用
- 經過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。因此,能夠很容易地使 Spring 框架管理的任何對象支持 AOP
- Spring AOP 模塊爲基於 Spring 的應用程序中的對象提供了事務管理服務。經過使用 Spring AOP,不用依賴 EJB 組件,就能夠將聲明性事務管理集成到應用程序中
- AOP(Aspect Orient Programming),也就是面向切面編程
- 面向對象編程(OOP)是從靜態角度考慮程序結構,
面向切面編程(AOP)是從動態角度考慮程序運行過程
- 處理一些具備橫切性質的系統性服務,如事務管理、安全檢查、緩存、對象池管理等
- AOP 其實是由目標類的代理類實現的。AOP 代理實際上是由AOP 框架動態生成的一個對象,該對象可做爲目標對象使用
- AOP 代理包含了目標對象的所有方法,但AOP 代理中的方法與目標對象的方法存在差別,AOP 方法在特定切入點添加了加強處理,並回調了目標對象的方法
- 機制:靜態織入
- 原理:在編譯期,切面直接以字節碼的形式編譯到目標字節碼文件中
- 優勢:對系統無性能影響
- 缺點:靈活性不夠
- 機制:動態代理
- 原理:在運行期,目標類加載後,爲接口動態生成代理類,將切面植入到代理類中
- 優勢:相對於靜態AOP更加靈活
- 缺點:切入的關注點須要實現接口。對系統有一點性能影響
- 表明:JDK動態代理
- 接口 + InvocationHandler + 目標對象 = 代理
- 機制:在運行期,目標類加載後,動態構建字節碼文件生成目標類的子類,將切面邏輯加入到子類中
- 原理:沒有接口也能夠織入
- 優勢:擴展類的實例方法爲final時,則沒法進行織入
- 表明:Cglib動態代理(依賴ASM)
- 接口或類 + MethodInterceptor + 目標對象 = 代理
- 機制:在運行期,目標加載前,將切面邏輯加到目標字節碼裏
- 原理:能夠對絕大部分類進行織入
- 優勢:代碼中若是使用了其餘類加載器,則這些類將不會被織入
- 表明:Javassist
- 機制:在運行期,全部類加載器加載字節碼前,前進行攔截
- 原理:能夠對全部類進行織入
- 表明:Javassit + Instrumentation
- Spring 中AOP 代理由Spring 的IoC 容器負責生成、管理,其依賴關係也由IoC 容器負責管理。所以,AOP 代理能夠直接使用容器中的其餘Bean 實例做爲目標,這種關係可由IoC 容器的依賴注入提供
- Spring 默認使用Java 動態代理來建立AOP 代理, 這樣就能夠爲任何接口實例建立代理了。當須要代理的類不是代理接口的時候, Spring 自動會切換爲使用CGLIB 代理,也可
強制使用CGLIB
- 定義普通業務組件
- 定義切入點,一個切入點可能橫切多個業務組件
- 定義加強處理,加強處理就是在AOP 框架爲普通業務組件織入的處理動做
- 因此進行AOP 編程的關鍵就是定義切入點和定義加強處理。一旦定義了合適的切入點和加強處理,AOP 框架將會自動生成AOP 代理,即:代理對象的方法 = 加強處理 + 被代理對象的方法
- 基於Annotation 的「零配置」方式:使用@Aspect、@Pointcut 等Annotation 來標註切入點和加強處理
- 首先啓用Spring 對@AspectJ 切面配置的支持
- 定義切面Bean
- 當啓動了@AspectJ 支持後,只要在Spring 容器中配置一個帶@Aspect 註釋的Bean, Spring 將會自動識別該Bean 並做爲切面處理
- 定義@Before 加強處理
- 定義@AfterReturning 加強處理
- 定義@AfterThrowing 加強處理
- 定義@After 加強處理
- After 加強處理與AfterReturning 加強處理有點類似,但也有區別
- AfterReturning 加強處理處理只有在目標方法成功完成後纔會被織入
- After加強處理無論目標方法如何結束(保存成功完成和遇到異常停止兩種狀況),它都會被織入
- @Around 加強處理
- 訪問目標方法的參數
- 定義切入點
- 所謂切入點,其實質就是爲一個切入點表達式起一個名稱,從而容許在多個加強處理中重用該名稱
- 一個切入點表達式
- 一個包含名字和任意參數的方法簽名
- 基於XML 配置文件的管理方式:使用Spring 配置文件來定義切入點和加強點
- 使用Spring ProxyFactoryBean建立代理
- 使用 ProxyFactoryBean 來建立 AOP 代理的最重要的優勢之一是 IoC 能夠管理通知和切入點。 這是一個很是的強大的功能,可以實現其餘 AOP 框架很難實現的特定的方法。例如,一個通知自己能夠引用應用對象(除了目標對象,它在任何 AOP 框架中均可以引用應用對象),這徹底得益於依賴注入所提供的可插入性
- ProxyFactoryBean的proxyInterfaces屬性,指明要代理的接口
- ProxyFactoryBean的target屬性,指明要代理的目標類 ,這個目標類實現了上面proxyInterfaces屬性指定的接口
- ProxyFactoryBean的interceptorNames屬性,指明要在代理的目標類中插入的Adivce
- ProxyFactoryBean還有一個proxyTargetClass屬性,若是這個屬性被設定爲「true」,說明 ProxyFactoryBean要代理的不是接口類,而是要使用CGLIB方式來進行代理,後面會詳細講解使用CGLIB方式來進行代理
- 影響了目標物件的行爲定義,直接增 加了目標物件的職責
- JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不一樣數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,而且極大地下降了須要編寫的異常代碼數量(例如打開和關閉鏈接)。Spring DAO 的面向 JDBC 的異常聽從通用的 DAO 異常層次結構
- Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map
- 全部這些都聽從 Spring 的通用事務和 DAO 異常層次結構
- Web 上下文模塊創建在應用程序上下文模塊之上,爲基於 Web 的應用程序提供了上下文。因此,Spring 框架支持與 Jakarta Struts 的集成
- Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工做
- MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現
- 經過策略接口,MVC 框架變成爲高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI
- 事務首先是一系列操做組成的工做單元,該工做單元內的操做是不可分割的,即要麼全部操做都作,要麼全部操做都不作
- ACID
- 即事務是不可分割的最小工做單元,事務內的操做要麼全作,要麼全不作
工做一到五年的java 開發工程師朋友能夠加入咱們Java架構交流羣:760940986 羣內提供 高可用,高併發,spring源碼,mybatis源碼,JVM,大數據,Netty等多個技術知識的架構視頻資料 還有大把大牛在羣內交流以及解答面試指導,問題答疑~~要進來和大牛交流學習提高提高本身嗎~~~~
java
- 在事務執行前數據庫的數據處於正確的狀態,而事務執行完成後數據庫的數據仍是處於正確的狀態,即數據完整性約束沒有被破壞
- 如銀行轉賬,A轉賬給B,必須保證A的錢必定轉給B,必定不會出現A的錢轉了但B沒收到,不然數據庫的數據就處於不一致(不正確)的狀態
- 併發事務執行之間無影響,在一個事務內部的操做對其餘事務是不產生影響,這須要事務隔離級別來指定隔離性
- 事務一旦執行成功,它對數據庫的數據的改變必須是永久的,不會因好比遇到系統故障或斷電形成數據不一致或丟失
- 兩個事務同時更新一行數據,最後一個事務的更新會覆蓋掉第一個事務的更新,從而致使第一個事務更新的數據丟失,這是因爲沒有加鎖形成的
- 在同一事務中,屢次讀取同一數據卻返回不一樣的結果;也就是有其餘事務更改了這些數據
- 不可重複讀的重點是修改
- 一個事務在執行過程當中讀取到了另外一個事務已提交的插入數據;即在第一個事務開始時讀取到一批數據,但此後另外一個事務又插入了新數據並提交,此時第一個事務又讀取這批數據但發現多了一條,即好像發生幻覺同樣
- 幻讀的重點在於新增或者刪除
- 最低隔離級別,一個事務能讀取到別的事務未提交的更新數據,很不安全,可能出現丟失更新、髒讀、不可重複讀、幻讀
- 一個事務能讀取到別的事務提交的更新數據,不能看到未提交的更新數據,不可能可能出現丟失更新、髒讀,但可能出現不可重複讀、幻讀
- 保證同一事務中前後執行的屢次查詢將返回同一結果,不受其餘事務影響,可能出現丟失更新、髒讀、不可重複讀,但可能出現幻讀
- 最高隔離級別,不容許事務併發執行,而必須串行化執行,最安全,不可能出現更新、髒讀、不可重複讀、幻讀
- 隔離級別越高,數據庫事務併發執行性能越差,能處理的操做越少。所以在實際項目開發中爲了考慮併發性能通常使用提交讀隔離級別,它能避免丟失更新和髒讀,儘管不可重複讀和幻讀不能避免,但能夠在可能出現的場合使用悲觀鎖或樂觀鎖來解決這些問題
- 獨佔鎖鎖定的資源只容許進行鎖定操做的程序使用,其它任何對它的操做均不會被接受。執行數據更新命令,即INSERT、 UPDATE或DELETE 命令時,SQL Server 會自動使用獨佔鎖。但當對象上有其它鎖存在時,沒法對其加獨佔鎖。獨佔鎖一直到事務結束才能被釋放
- 共享鎖鎖定的資源能夠被其它用戶讀取,但其它用戶不能修改它。在SELECT 命令執行時,SQL Server 一般會對對象進行共享鎖鎖定。一般加共享鎖的數據頁被讀取完畢後,共享鎖就會當即被釋放
- 更新鎖是爲了防止死鎖而設立的。當SQL Server 準備更新數據時,它首先對數據對象做更新鎖鎖定,這樣數據將不能被修改,但能夠讀取。等到SQL Server 肯定要進行更新數據操做時,它會自動將更新鎖換爲獨佔鎖。但當對象上有其它鎖存在時,沒法對其做更新鎖鎖定
- 悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其餘事務,以及來自外部系統的事務處理)修改持保守態度,所以在整個數據處理過程當中,將數據處於鎖定狀態。悲觀鎖的實現,每每依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,不然,即便在本系統中實現了加鎖機制,也沒法保證外部系統不會修改數據)
- 相對悲觀鎖而言,樂觀鎖機制採起了更加寬鬆的加鎖機制。悲觀鎖大多數狀況下依靠數據庫的鎖機制實現,以保證操做最大程度的獨佔性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷每每沒法承受
- 而樂觀鎖機制在必定程度上解決了這個問題。樂觀鎖,大可能是基於數據版本( Version )記錄機制實現。何謂數據版本?即爲數據增長一個版本標識,在基於數據庫表的版本解決方案中,通常是經過爲數據庫表增長一個 「version」 字段來實現。讀取出數據時,將此版本號一同讀出,以後更新時,對此版本號加一。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如 果提交的數據版本號大於數據庫表當前版本號,則予以更新,不然認爲是過時數據
- 就是普通事務,能保證單臺數據庫上的操做的ACID,被限定在一臺數據庫上
- 涉及兩個或多個數據庫源的事務,即跨越多臺同類或異類數據庫的事務(由每臺數據庫的本地事務組成的),分佈式事務旨在保證這些本地事務的全部操做的ACID,使事務能夠跨越多臺數據庫
- JDBC事務:就是數據庫事務類型中的本地事務,經過Connection對象的控制來管理事務
- JTA事務:JTA指Java事務API(Java Transaction API),是Java EE數據庫事務規範, JTA只提供了事務管理接口,由應用程序服務器廠商(如WebSphere Application Server)提供實現,JTA事務比JDBC更強大,支持分佈式事務
- 本地事務:使用JDBC編程實現事務
- 全局事務:由應用程序服務器提供,使用JTA事務
- 聲明式事務: 經過註解或XML配置文件指定事務信息
- 編程式事務:經過編寫代碼實現事務
- JdbcDataSource
- SessionFactory
- EntityManager
- DataSourceTransactionManager
- HibernateTransactionManager
- JpaTransactionManager
- 每一個Bean有一個代理
- 全部Bean共享一個代理基類
- 每一個Bean用TransactionProxyFactoryBean代理
- 全部Bean都集成TransactionProxyFactoryBean
- 攔截器:TransactionInterceptor
- 根據beanName匹配後進行自動代理: BeanNameAutoProxyCreator
- <tx:advice/>
- <aop:config/>
- BeanPostProcessor是Spring容器的一個擴展點,能夠進行自定義的實例化、初始化、依賴裝配、依賴檢查等流程,便可以覆蓋默認的實例化,也能夠加強初始化、依賴注入、依賴檢查等流程
- BeanFactory <- AbstractBeanFactory <- AbstractAutowireCapableBeanFactory <- DefaultListableBeanFactory:AbstractAutowireCapableBeanFactory.createBean()負責Bean的初始化到消亡週期
- resolveBeanClass(mbd, beanName); 解析Bean class,若class配置錯誤將拋出CannotLoadBeanClassException
- mbd.prepareMethodOverrides(); 準備和驗證配置的方法注入,若驗證失敗拋出BeanDefinitionValidationException
- Object bean = resolveBeforeInstantiation(beanName, mbd)
- 執行InstantiationAwareBeanPostProcessor的實例化的預處理回調方法postProcessBeforeInstantiation(自定義的實例化,如建立代理)
- 執行InstantiationAwareBeanPostProcessor的實例化的後處理回調方法postProcessAfterInitialization(如依賴注入),若是3.1處返回的Bean不爲null才執行
- 若是3處的擴展點返回的bean不爲空,直接返回該bean,後續流程不須要執行
- Object beanInstance = doCreateBean(beanName, mbd, args); 執行spring的建立bean實例的流程
- createBeanInstance(beanName, mbd, args); 實例化Bean
- instantiateUsingFactoryMethod 工廠方法實例化
- 構造器實例化
- 若是以前已經解析過構造器
- autowireConstructor:有參調用autowireConstructor實例化
- instantiateBean:無參調用instantiateBean實例化
- 經過SmartInstantiationAwareBeanPostProcessor 的determineCandidateConstructors 回調方法解析構造器,第二個BeanPostProcessor擴展點,返回第一個解析成功(返回值不爲null)的構造器組
- autowireConstructor:若是(6.2.2.1返回的不爲null,且是有參構造器,調用autowireConstructor實例化
- instantiateBean: 不然調用無參構造器實例化
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName):執行Bean定義的合併
- 執行MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition回調方法,進行bean定義的合併
- addSingletonFactory(beanName, new ObjectFactory())
- SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference,當存在循環依賴時,經過該回調方法獲取及早暴露的Bean實例
- populateBean(beanName, mbd, instanceWrapper);裝配Bean依賴
- InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation;第五個BeanPostProcessor擴展點,在實例化Bean以後,全部其餘裝配邏輯以前執行,若是false將阻止其餘的InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation的執行和從(9.2到(9.5的執行,一般返回true
- autowireByName、autowireByType:根據名字和類型進行自動裝配
- InstantiationAwareBeanPostProcessor的postProcessPropertyValues,完成其餘定製的一些依賴注入,如
- AutowiredAnnotationBeanPostProcessor執行@Autowired註解注入
- CommonAnnotationBeanPostProcessor執行@Resource等註解的注入
- PersistenceAnnotationBeanPostProcessor執行@ PersistenceContext等JPA註解的注入
- RequiredAnnotationBeanPostProcessor執行@Required註解的檢查等等
- checkDependencies:依賴檢查
- applyPropertyValues:應用明確的setter屬性注入
- initializeBean(beanName, exposedObject, mbd); 執行初始化Bean流程
- invokeAwareMethods(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware):調用一些Aware標識接口注入如BeanName、BeanFactory
- BeanPostProcessor的postProcessBeforeInitialization:在調用初始化以前完成一些定製的初始化任務,如:
- BeanValidationPostProcessor完成JSR-303 @Valid註解Bean驗證
- InitDestroyAnnotationBeanPostProcessor完成@PostConstruct註解的初始化方法調用
- ApplicationContextAwareProcessor完成一些Aware接口的注入(如EnvironmentAware、ResourceLoaderAware、ApplicationContextAware),其返回值將替代原始的Bean對象
- invokeInitMethods : 調用初始化方法
- InitializingBean的afterPropertiesSet :調用InitializingBean的afterPropertiesSet回調方法
- 經過xml指定的自定義init-method :調用經過xml配置的自定義init-method
- BeanPostProcessor的postProcessAfterInitialization
- AspectJAwareAdvisorAutoProxyCreator(完成xml風格的AOP配置(<aop:config>)的目標對象包裝到AOP代理對象)
- AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj註解風格(<aop:aspectj-autoproxy> @Aspect)的AOP配置的目標對象包裝到AOP代理對象),其返回值將替代原始的Bean對象
- registerDisposableBeanIfNecessary(beanName, bean, mbd) : 註冊Bean的銷燬方法(只有非原型Bean可註冊)
- DestructionAwareBeanPostProcessor的postProcessBeforeDestruction : 如InitDestroyAnnotationBeanPostProcessor完成@PreDestroy註解的銷燬方法註冊和調用
- DisposableBean的destroy:註冊/調用DisposableBean的destroy銷燬方法
- 經過xml指定的自定義destroy-method : 註冊/調用經過XML指定的destroy-method銷燬方法
- Scope的registerDestructionCallback:註冊自定義的Scope的銷燬回調方法,如RequestScope、SessionScope等
- Spring內置的BeanPostProcessor
- ApplicationContextAwareProcessor
- 容器啓動時會自動註冊
- 注入那些實現ApplicationContextAware、MessageSourceAware、ResourceLoaderAware、EnvironmentAware、
EmbeddedValueResolverAware、ApplicationEventPublisherAware標識接口的Bean須要的相應實例
- 在postProcessBeforeInitialization回調方法中進行實施
- CommonAnnotationBeanPostProcessor
- CommonAnnotationBeanPostProcessor繼承InitDestroyAnnotationBeanPostProcessor,當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊
- 提供對JSR-250規範註解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持、
- 經過@Resource註解進行依賴注入
- postProcessPropertyValues:經過此回調進行@Resource註解的依賴注入
- 用於執行@PostConstruct 和@PreDestroy 註解的初始化和銷燬方法的擴展點
- postProcessBeforeInitialization()將會調用bean的@PostConstruct方法
- postProcessBeforeDestruction()將會調用單例 Bean的@PreDestroy方法(此回調方法會在容器銷燬時調用)
- AutowiredAnnotationBeanPostProcessor
- 當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊
- 提供對JSR-330規範註解的支持和Spring自帶註解的支持
- Spring自帶註解的依賴注入支持,@Autowired和@Value
- determineCandidateConstructors :決定候選構造器
- postProcessPropertyValues :進行依賴注入
- 對JSR-330規範註解的依賴注入支持,@Inject
- RequiredAnnotationBeanPostProcessor
- 當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊
- 提供對@Required註解的方法進行依賴檢查支持
- postProcessPropertyValues:若是檢測到沒有進行依賴注入時拋出BeanInitializationException異常
- PersistenceAnnotationBeanPostProcessor
- 當在配置文件有<context:annotation-config>或<context:component-scan>會自動註冊
- 經過對JPA @javax.persistence.PersistenceUnit和@ javax.persistence.PersistenceContext註解進行依賴注入的支持
- postProcessPropertyValues : 根據@PersistenceUnit/@PersistenceContext進行EntityManagerFactory和EntityManager的支持
- AspectJAwareAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator都是繼承AbstractAutoProxyCreator
- AspectJAwareAdvisorAutoProxyCreator提供對(<aop:config>)聲明式AOP的支持、
- AnnotationAwareAspectJAutoProxyCreator提供對(<aop:aspectj-autoproxy>)註解式(@AspectJ)AOP的支持
- 當使用<aop:config>配置時自動註冊AspectJAwareAdvisorAutoProxyCreator
- 使用<aop:aspectj-autoproxy>時會自動註冊AnnotationAwareAspectJAutoProxyCreator
- predictBeanType:預測Bean的類型,若是目標對象被AOP代理對象包裝,此處將返回AOP代理對象的類型
- postProcessBeforeInstantiation:配置TargetSourceCreator進行自定義TargetSource建立時,會建立代理對象並中斷默認Spring建立流程
- getEarlyBeanReference和postProcessAfterInitialization是兩者選一的,並且單例Bean目標對象只能被加強一次,而原型Bean目標對象可能被包裝屢次
- BeanValidationPostProcessor
- 默認不自動註冊,Spring3.0開始支持
- 提供對JSR-303驗證規範支持
- 根據afterInitialization是false/true決定調用postProcessBeforeInitialization或postProcessAfterInitialization來經過JSR-303規範驗證Bean,默認false
- 如ApplicationContextAwareProcessor會在ApplicationContext容器啓動時自動註冊,而CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor會在當你使用<context:annotation-config>或<context:component-scan>配置時自動註冊
- 只要將BeanPostProcessor註冊到容器中,Spring會在啓動時自動獲取並註冊
- 若是使用BeanFactory實現,非ApplicationContext實現,BeanPostProcessor執行順序就是添加順序
- 若是使用的是AbstractApplicationContext(實現了ApplicationContext)的實現,則經過以下規則指定順序
- PriorityOrdered(繼承了Ordered),實現了該接口的BeanPostProcessor會在第一個順序註冊,標識高優先級順序,即比實現Ordered的具備更高的優先級
- Ordered,實現了該接口的BeanPostProcessor會第二個順序註冊
- XML一般經過DTD、XSD定義,但DTD的表達能力較弱,XSD定義則能力比較強,可以定義類型,出現次數等。自定義標籤須要XSD支持,在實現時使用Namespace擴展來支持自定義標籤
- 工做過程
- Spring經過XML解析程序將其解析爲DOM樹,經過NamespaceHandler指定對應的Namespace的BeanDefinitionParser將其轉換成BeanDefinition
- 再經過Spring自身的功能對BeanDefinition實例化對象
- 編寫XSD文件
- META-INF/spring.schemas :配置XSD文件
- 在解析XML文件時將XSD重定向到本地文件,避免在解析XML文件時須要上網下載XSD文件。經過現實org.xml.sax.EntityResolver接口來實現該功能
- 指定NamespaceHandler(實現org.springframework.beans.factory.xml.NamespaceHandler)接口,或使用org.springframework.beans.factory.xml.NamespaceHandlerSupport的子類
- NamespaceHandler實現中註冊標籤和解析器
- 實現配置 BeanDefinitionParser
- 解析XML,實例構造想要的Bean爲BeanDefinition對象
- Spring PropertyPlaceholderConfigurer配置擴展
- 經過擴展PropertyPlaceholderConfigurer類自定義Spring取配置值的行爲
- 如經過擴展PropertyPlaceholderConfigurer,內部封裝調用ZooKeeper動態配置獲取,從而把ZooKeeper的Name Service集成到現有的Spring容器中
- Spring的Bean默認是單例的(Singleton)
- 簡單工廠模式又稱靜態工廠方法模式。重命名上就能夠看出這個模式必定很簡單。它存在的目的很簡單:定義一個用於建立對象的接口
- 在簡單工廠模式中,一個工廠類處於對產品類實例化調用的中心位置上,它決定哪個產品類應當被實例化, 如同一個交通警察站在來往的車輛流中,決定放行那一個方向的車輛向那一個方向流動同樣
- 組成
- 工廠類角色:這是本模式的核心,含有必定的商業邏輯和判斷邏輯。在Java中它每每由一個具體類實現
- 抽象產品角色:它通常是具體產品繼承的父類或者實現的接口。在Java中由接口或者抽象類來實現
- 具體產品角色:工廠類所建立的對象就是此角色的實例。在java中由一個具體類實現
- 工廠方法模式是簡單工廠模式的進一步抽象化和推廣,工廠方法模式裏再也不只由一個工廠類決定那一個產品類應當被實例化,這個決定被交給抽象工廠的子類去作
- 組成
- 抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現
- 具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以建立對應的具體產品的對象
- 抽象產品角色:它是具體產品繼承的父類或者是實現的接口。在java中通常有抽象類或者接口來實現
- 具體產品角色:具體工廠角色所建立的對象就是此角色的實例。在java中由具體的類來實現
- 工廠方法模式使用繼承自抽象工廠角色的多個子類來代替簡單工廠模式中的「上帝類」。正如上面所說,這樣便分擔了對象承受的壓力;並且這樣使得結構變得靈活 起來——當有新的產品(即暴發戶的汽車)產生時,只要按照抽象產品角色、抽象工廠角色提供的合同來生成,那麼就能夠被客戶使用,而沒必要去修改任何已有的代 碼。能夠看出工廠角色的結構也是符合開閉原則的
- 能夠看出工廠方法的加入,使得對象的數量成倍增加。當產品種類很是多時,會出現大量的與之對應的工廠對象,這不是咱們所但願的。由於若是不能避免這種情 況,能夠考慮使用簡單工廠模式與工廠方法模式相結合的方式來減小工廠類:即對於產品樹上相似的種類(通常是樹的葉子中互爲兄弟的)使用簡單工廠模式來實現
- 簡單工廠和工廠方法模式的比較
- 工廠方法模式和簡單工廠模式在定義上的不一樣是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式能夠容許不少實的工廠類從抽象工廠類繼承下來, 從而能夠在實際上成爲多個簡單工廠模式的綜合,從而推廣了簡單工廠模式
- 反過來說,簡單工廠模式是由工廠方法模式退化而來。設想若是咱們很是肯定一個系統只須要一個實的工廠類, 那麼就不妨把抽象工廠類合併到實的工廠類中去。而這樣一來,咱們就退化到簡單工廠模式了
- 當一個類不知道它所必須建立的對象的類的時候
- 當一個類但願由它的子類來指定它所建立的對象的時候
- 當類將建立對象的職責委託給多個幫助子類中的某一個,而且你但願將哪個幫助子類是代理者這一信息局部化的時候
- 一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部形態的工廠模式都是重要的
- 這個系統有多於一個的產品族,而系統只消費其中某一產品族
- 同屬於同一個產品族的產品是在一塊兒使用的,這一約束必須在系統的設計中體現出來
- 系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於實現
- 簡單工廠模式是由一個具體的類去建立其餘類的實例,父類是相同的,父類是具體的
- 工廠方法模式是有一個抽象的父類定義公共接口,子類負責生成具體的對象,這樣作的目的是將類的實例化操做延遲到子類中完成
- 抽象工廠模式提供一個建立一系列相關或相互依賴對象的接口,而無須指定他們具體的類。它針對的是有多個產品的等級結構。而工廠方法模式針對的是一個產品的等級結構
- 論是簡單工廠模式,工廠方法模式,仍是抽象工廠模式,他們都屬於工廠模式,在形式和特色上也是極爲類似的,他們的最終目的都是爲了解耦。在使用時,咱們沒必要去在乎這個模式到底工廠方法模式仍是抽象工廠模式,由於他們之間的演變經常是使人琢磨不透的。常常你會發現,明明使用的工廠方法模式,當新需求來臨,稍加修改,加入了一個新方法後,因爲類中的產品構成了不一樣等級結構中的產品族,它就變成抽象工廠模式了;而對於抽象工廠模式,當減小一個方法使的提供的產品再也不構成產品族以後,它就演變成了工廠方法模式
- 對其餘對象提供一種代理以控制對這個對象的訪問
- 代理模式的主要做用是爲其餘對象提供一種代理以控制對這個對象的訪問。在某些狀況下,一個對象不想或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用
- 代理模式的思想是爲了提供額外的處理或者不一樣的操做而在實際對象與調用者之間插入一個代理對象
- 代理模式的三個角色
- 抽象角色:聲明真實對象和代理對象的共同接口
- 代理角色:代理對象角色內部含有對真實對象的引用,從而能夠操做真實對象,同時代理對象提供與真實對象相同的接口以便在任什麼時候刻都能代替真實對象。同時,代理對象能夠在執行真實對象操做時,附加其餘的操做,至關於對真實對象進行封裝
- 真實角色:代理角色所表明的真實對象,是咱們最終要引用的對象
- JDK動態代理(JdkDynamicAopProxy )
- JDK動態代理只能針對實現了接口的類生成代理
- 接口 + InvocationHandler + 目標對象 = 代理
- Cglib動態代理(Cglib2AopProxy )
- CGLIB(CODE GENERLIZE LIBRARY)代理是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的全部方法,因此該類或方法不能聲明稱final的
- 若是目標對象沒有實現接口,則默認會採用CGLIB代理
- 接口或類 + MethodInterceptor + 目標對象 = 代理
- 外觀模式,咱們經過外觀的包裝,使應用程序只能看到外觀對象,而不會看到具體的細節對象,這樣無疑會下降應用程序的複雜度,而且提升了程序的可維護性
- 爲了下降複雜性,經常將系統劃分爲若干個子系統。可是如何作到各個系統之間的通訊和相互依賴關係達到最小呢?
- 爲子系統中的一組接口提供一個一致的界面, Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。引入外觀角色以後,用戶只須要直接與外觀角色交互,用戶與子系統之間的複雜關係由外觀角色來實現,從而下降了系統的耦合度
- 當你要爲一個複雜子系統提供一個簡單接口時,子系統每每由於不斷演化而變得愈來愈複雜。大多數模式使用時都會產生更多更小的類
- 這使得子系統更具可重用性,也更容易對子系統進行定製,但這也給那些不須要定製子系統的用戶帶來一些使用上的困難。Facade能夠提供一個簡單的缺省視圖
- 這一視圖對大多數用戶來講已經足夠,而那些須要更多的可定製性的用戶能夠越過Facade層
- 客戶程序與抽象類的實現部分之間存在着很大的依賴性。引入 Facade將這個子系統與客戶以及其餘的子系統分離,能夠提升子系統的獨立性和可移植性
- 當你須要構建一個層次結構的子系統時,使用 Facade模式定義子系統中每層的入口點。若是子系統之間是相互依賴的,你可讓它們僅經過Facade進行通信,從而簡化了它們之間的依賴關係
- 對客戶屏蔽子系統組件,減小了客戶處理的對象數目並使得子系統使用起來更加容易。經過引入外觀模式,客戶代碼將變得很簡單,與之關聯的對象也不多
- 實現了子系統與客戶之間的鬆耦合關係,這使得子系統的組件變化不會影響到調用它的客戶類,只須要調整外觀類便可
- 下降了大型軟件系統中的編譯依賴性,並簡化了系統在不一樣平臺之間的移植過程,由於編譯一個子系統通常不須要編譯全部其餘的子系統。一個子系統的修改對其餘子系統沒有任何影響,並且子系統內部變化也不會影響到外觀對象
- 只是提供了一個訪問子系統的統一入口,並不影響用戶直接使用子系統類
- 不能很好地限制客戶使用子系統類,若是對客戶訪問子系統類作太多的限制則減小了可變性和靈活性
- 在不引入抽象外觀類的狀況下,增長新的子系統可能須要修改外觀類或客戶端的源代碼,違背了「開閉原則」
- Abstract Factory式能夠與Facade模式一塊兒使用以提供一個接口,這一接口可用來以一種子系統獨立的方式建立子系統對象。 Abstract Factory也能夠代替Facade模式隱藏那些與平臺相關的類
- Mediator模式與Facade模式的類似之處是,它抽象了一些已有的類的功能。然而,Mediator的目的是對同事之間的任意通信進行抽象,一般集中不屬於任何單個對象的功能
- Mediator的同事對象知道中介者並與它通訊,而不是直接與其餘同類對象通訊。相對而言,Facade模式僅對子系統對象的接口進行抽象,從而使它們更容易使用;它並不定義新功能,子系統也不知道Facade的存在
- 適配器模式是將一個接口經過適配來間接轉換爲另外一個接口
- 外觀模式的話,其主要是提供一個整潔的一致的接口給客戶端
- 根據「單一職責原則」,在軟件中將一個系統劃分爲若干個子系統有利於下降整個系統的複雜性,一個常見的設計目標是使子系統間的通訊和相互依賴關係達到最小,而達到該目標的途徑之一就是引入一個外觀對象,它爲子系統的訪問提供了一個簡單而單一的入口
- 外觀模式是「迪米特法則」的體現,經過引入一個新的外觀類能夠下降原有系統的複雜度,外觀類充當了客戶類與子系統類之間的「第三者」,同時下降客戶類與子系統類的耦合度。外觀模式就是實現代碼重構以便達到「迪米特法則」要求的一個強有力的武器
- 外觀模式要求一個子系統的外部與其內部的通訊經過一個統一的外觀對象進行,外觀類將客戶端與子系統的內部複雜性分隔開,使得客戶端只須要與外觀對象打交道,而不須要與子系統內部的不少對象打交道
- 外觀模式從很大程度上提升了客戶端使用的便捷性,使得客戶端無須關心子系統的工做細節,經過外觀角色便可調用相關功能
- 不要試圖經過外觀類爲子系統增長新行爲 ,不要經過繼承一個外觀類在子系統中加入新的行爲,這種作法是錯誤的。外觀模式的用意是爲子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行爲,新的行爲的增長應該經過修改原有子系統類或增長新的子系統類來實現,不能經過外觀類來實現
- 在外觀模式中,一般只須要一個外觀類,而且此外觀類只有一個實例,換言之它是一個單例類。在不少狀況下爲了節約系統資源,通常將外觀類設計爲單例類。固然這並不意味着在整個系統裏只能有一個外觀類,在一個系統中能夠設計多個外觀類,每一個外觀類都負責和一些特定的子系統交互,向用戶提供相應的業務功能
- 不要經過繼承一個外觀類在子系統中加入新的行爲,這種作法是錯誤的。外觀模式的用意是爲子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行爲,新的行爲的增長應該經過修改原有子系統類或增長新的子系統類來實現,不能經過外觀類來實現
- 外觀模式創造出一個外觀對象,將客戶端所涉及的屬於一個子系統的協做夥伴的數量減到最少,使得客戶端與子系統內部的對象的相互做用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的「第三者」,下降了客戶類與子系統類之間的耦合度,外觀模式就是實現代碼重構以便達到「迪米特法則」要求的一個強有力的武器
- 外觀模式最大的缺點在於違背了「開閉原則」
- 當增長新的子系統或者移除子系統時須要修改外觀類,能夠經過引入抽象外觀類在必定程度上解決該問題,客戶端針對抽象外觀類進行編程。對於新的業務需求,不修改原有外觀類,而對應增長一個新的具體外觀類,由新的具體外觀類來關聯新的子系統對象,同時經過修改配置文件來達到不修改源代碼並更換外觀類的目的
- Client:建立一個具體命令(ConcreteCommand)對象並肯定其接收者
- Command 命令:聲明瞭一個給全部具體命令類的抽象接口
- ConcreteCommand:具體命令,定義一個接收者和行爲之間的弱耦合;實現execute()方法,負責調用接收者的相應操做。execute()方法一般叫作執行方法
- Invoker 請求者:負責調用命令對象執行請求,相關的方法叫作行動方法
- Receiver 接受者:負責具體實施和執行一個請求。任何一個類均可以成爲接收者,實施和執行請求的方法叫作行動方法
- 命令模式使得發起命令的對象——客戶端,和具體實現命令的對象——接收者對象徹底解耦,也就是說發起命令的對象徹底不知道具體實現對象是誰,也不知道如何實現
- 命令模式把請求封裝起來,能夠動態地對它進行參數化、隊列化和日誌化等操做,從而使得系統更靈活
- 命令模式中的命令對象可以很容易地組合成複合命令,也就是宏命令,從而使系統操做更簡單,功能更強大
- 因爲發起命令的對象和具體的實現徹底解耦,所以擴展新的命令就很容易,只須要實現新的命令對象,而後在裝配的時候,把具體的實現對象設置到命令對象中,而後就可使用這個命令對象,已有的實現徹底不用變化
- 把 Tomcat 中兩個核心組件 Connector 和 Container,比做一對夫妻。男的將接受過來的請求以命令的方式交給女主人。對應到 Connector 和 Container,Connector 也是經過命令模式調用 Container 的
- 模塊
- Connector 做爲抽象請求者(Invoker )
- HttpConnector 做爲具體請求者(Invoker )
- HttpProcessor 做爲命令(Command)
- Container 做爲命令的抽象接受者(Receiver)
- ContainerBase 做爲具體的接受者(Receiver)
- 客戶端就是應用服務器 Server 組件了(Client)
- Server 首先建立命令請求者 HttpConnector 對象,而後建立命令 HttpProcessor 命令對象。再把命令對象交給命令接受者 ContainerBase 容器來處理命令。命令的最終是被 Tomcat 的 Container 執行的。命令能夠以隊列的方式進來,Container 也能夠以不一樣的方式來處理請求,如 HTTP1.0 協議和 HTTP1.1 的處理方式就會不一樣
- 更多例子請看文章「Java設計模式之命令模式」中的遙控器例子
- 系統須要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互
- 命令模式容許請求的一方和接收的一方獨立開來,使得請求的一方沒必要知道接收請求的一方的接口,更沒必要知道請求是怎麼被接收,以及操做是否被執行、什麼時候被執行,以及是怎麼被執行的
- 系統須要在不一樣的時間指定請求、將請求排隊和執行請求
- 系統須要支持命令的撤銷(Undo)操做和恢復(Redo)操做
- 系統須要將一組操做組合在一塊兒,即支持宏命令
- 命令模式的關鍵在於引入了抽象命令接口,且發送者針對抽象命令接口編程,只有實現了抽象命令接口的具體命令才能與接收者相關聯
- 裝飾模式又名包裝(Wrapper)模式。裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關係的一個替代方案
- 裝飾模式以對客戶透明的方式動態地給一個對象附加上更多的責任。換言之,客戶端並不會以爲對象在裝飾前和裝飾後有什麼不一樣。裝飾模式能夠在不使用創造更多子類的狀況下,將對象的功能加以擴展
- 抽象構件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象
- 具體構件(ConcreteComponent)角色:定義一個將要接收附加責任的類
- 裝飾(Decorator)角色:持有一個構件(Component)對象的實例,並定義一個與抽象構件接口一致的接口
- 具體裝飾(ConcreteDecorator)角色:負責給構件對象「貼上」附加的責任
- 若是隻有一個ConcreteComponent類,那麼能夠考慮去掉抽象的Component類(接口),把Decorator做爲一個ConcreteComponent子類
- 若是隻有一個ConcreteDecorator類,那麼就沒有必要創建一個單獨的Decorator類,而能夠把Decorator和ConcreteDecorator的責任合併成一個類。甚至在只有兩個ConcreteDecorator類的狀況下,均可以這樣作
- 裝飾模式與繼承關係的目的都是要擴展對象的功能,可是裝飾模式能夠提供比繼承更多的靈活性。裝飾模式容許系統動態決定「貼上」一個須要的「裝飾」,或者除掉一個不須要的「裝飾」。繼承關係則不一樣,繼承關係是靜態的,它在系統運行前就決定了
- 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,設計師能夠創造出不少不一樣行爲的組合
- 因爲使用裝飾模式,能夠比使用繼承關係須要較少數目的類。使用較少的類,固然使設計比較易於進行。可是,在另外一方面,使用裝飾模式會產生比使用繼承關係更多的對象。更多的對象會使得查錯變得困難,特別是這些對象看上去都很相像
- 裝飾模式在Java語言中的最著名的應用莫過於Java I/O標準庫的設計了
- 因爲Java I/O庫須要不少性能的各類組合,若是這些性能都是用繼承的方法實現的,那麼每一種組合都須要一個類,這樣就會形成大量性能重複的類出現。而若是採用裝飾模式,那麼類的數目就會大大減小,性能的重複也能夠減至最少。所以裝飾模式是Java I/O庫的基本模式
- 結構
- 抽象構件(Component)角色:由InputStream扮演。這是一個抽象類,爲各類子類型提供統一的接口
- 具體構件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等類扮演。它們實現了抽象構件角色所規定的接口
- 抽象裝飾(Decorator)角色:由FilterInputStream扮演。它實現了InputStream所規定的接口
- 具體裝飾(ConcreteDecorator)角色:由幾個類扮演,分別是BufferedInputStream、DataInputStream以及兩個不經常使用到的類LineNumberInputStream、PushbackInputStream
- 裝飾模式和適配器模式都是「包裝模式(Wrapper Pattern)」,它們都是經過封裝其餘對象達到設計的目的的,可是它們的形態有很大區別
- 理想的裝飾模式在對被裝飾對象進行功能加強的同時,要求具體構件角色、裝飾角色的接口與抽象構件角色的接口徹底一致
- 而適配器模式則否則,通常而言,適配器模式並不要求對源對象的功能進行加強,可是會改變源對象的接口,以便和目標接口相符合
- 裝飾模式有透明和半透明兩種,這兩種的區別就在於裝飾角色的接口與抽象構件角色的接口是否徹底一致
- 透明的裝飾模式也就是理想的裝飾模式,要求具體構件角色、裝飾角色的接口與抽象構件角色的接口徹底一致
- 若是裝飾角色的接口與抽象構件角色接口不一致,也就是說裝飾角色的接口比抽象構件角色的接口寬的話,裝飾角色實際上已經成了一個適配器角色,這種裝飾模式也是能夠接受的,稱爲「半透明」的裝飾模式
- 在適配器模式裏面,適配器類的接口一般會與目標類的接口重疊,但每每並不徹底相同。換言之,適配器類的接口會比被裝飾的目標類接口寬
- 半透明的裝飾模式實際上就是處於適配器模式與裝飾模式之間的灰色地帶。若是將裝飾模式與適配器模式合併成爲一個「包裝模式」的話,那麼半透明的裝飾模式倒能夠成爲這種合併後的「包裝模式」的表明
- InputStream類型中的裝飾模式是半透明的
- 現實世界與理論總歸是有一段差距的。純粹的裝飾模式在真實的系統中很難找到。通常所遇到的,都是這種半透明的裝飾模式
- 觀察上面的代碼,會發現最裏層是一個FileInputStream對象,而後把它傳遞給一個BufferedInputStream對象,通過BufferedInputStream處理,再把處理後的對象傳遞給了DataInputStream對象進行處理,這個過程其實就是裝飾器的組裝過程,FileInputStream對象至關於原始的被裝飾的對象,而BufferedInputStream對象和DataInputStream對象則至關於裝飾器
- 適配器模式把一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做
- 適用場景
- 系統須要使用現有的類,而這些類的接口不符合系統的接口
- 想要創建一個能夠重用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在未來引進的類一塊兒工
- 兩個類所作的事情相同或類似,可是具備不一樣接口的時候
- 舊的系統開發的類已經實現了一些功能,可是客戶端卻只能以另外接口的形式訪問,但咱們不但願手動更改原有類的時候
- 使用第三方組件,組件接口定義和本身定義的不一樣,不但願修改本身的接口,可是要使用第三方組件接口的功能
- 目標(Target)角色:這就是所期待獲得的接口。注意:因爲這裏討論的是類適配器模式,所以目標不能夠是類
- 源(Adapee)角色:如今須要適配的接口
- 適配器(Adaper)角色:適配器類是本模式的核心。適配器把源接口轉換成目標接口。顯然,這一角色不能夠是接口,而必須是具體類
- class Adapter extends Adaptee implements Target
- 適配器角色Adapter擴展了Adaptee,同時又實現了目標(Target)接口。因爲Adaptee沒有提供targetMethod()方法,而目標接口又要求這個方法,所以適配器角色Adapter實現了這個方法
- 與類的適配器模式同樣,對象的適配器模式把被適配的類的API轉換成爲目標類的API
- 與類的適配器模式不一樣的是,對象的適配器模式不是使用繼承關係鏈接到Adaptee類,而是使用委派關係鏈接到Adaptee類
- Adaptee類並無targetMethod()方法,而客戶端則期待這個方法。爲使客戶端可以使用Adaptee類,須要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的實例,從而此包裝類可以把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關係,這決定了適配器模式是對象的
- 類適配器使用對象繼承的方式,是靜態的定義方式;而對象適配器使用對象組合的方式,是動態組合的方式
- 對於類適配器,因爲適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類一塊兒工做,由於繼承是靜態的關係,當適配器繼承了Adaptee後,就不可能再去處理 Adaptee的子類了
- 對於對象適配器,一個適配器能夠把多種不一樣的源適配到同一個目標。換言之,同一個適配器能夠把源類和它的子類都適配到目標接口。由於對象適配器採用的是對象組合的關係,只要對象類型正確,是否是子類都無所謂
- 對於類適配器,適配器能夠重定義Adaptee的部分行爲,至關於子類覆蓋父類的部分實現方法
- 對於對象適配器,要重定義Adaptee的行爲比較困難,這種狀況下,須要定義Adaptee的子類來實現重定義,而後讓適配器組合子類。雖然重定義Adaptee的行爲比較困難,可是想要增長一些新的行爲則方便的很,並且新增長的行爲可同時適用於全部的源
- 對於類適配器,僅僅引入了一個對象,並不須要額外的引用來間接獲得Adaptee
- 對於對象適配器,須要額外的引用來間接獲得Adaptee
- 建議儘可能使用對象適配器的實現方式,多用合成/聚合、少用繼承。固然,具體問題具體分析,根據須要來選用實現方式,最適合的纔是最好的
- 更好的複用性: 系統須要使用現有的類,而此類的接口不符合系統的須要。那麼經過適配器模式就可讓這些功能獲得更好的複用
- 更好的擴展性: 在實現適配器功能的時候,能夠調用本身開發的功能,從而天然地擴展系統的功能
- 經過適配器,客戶端能夠調用同一接口,於是對客戶端來講是透明的。這樣作更簡單、更直接、更緊湊
- 複用了現存的類,解決了現存類和複用環境要求不一致的問題
- 將目標類和適配者類解耦,經過引入一個適配器類重用現有的適配者類,而無需修改原有代碼
- 一個對象適配器能夠把多個不一樣的適配者類適配到同一個目標,也就是說,同一個適配器能夠把適配者類和它的子類都適配到目標接口
- 過多的使用適配器,會讓系統很是零亂,不易總體進行把握。好比,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統若是太多出現這種狀況,無異於一場災難。所以若是不是頗有必要,能夠不使用適配器,而是直接對系統進行重構
- Spring aop框架對BeforeAdvice、AfterAdvice、ThrowsAdvice三種通知類型的支持其實是藉助適配器模式來實現的,這樣的好處是使得框架容許用戶向框架中加入本身想要支持的任何一種通知類型,上述三種通知類型是Spring aop框架定義的,它們是aop聯盟定義的Advice的子類型
- AdvisorAdapter是一個適配器接口,它定義了本身支持的Advice類型,而且能把一個Advisor適配成MethodInterceptor
- Adapter
- MethodBeforeAdviceAdapter
- AfterReturningAdviceAdapter
- ThrowsAdviceAdapter
- 責任鏈(Chain of Responsibility )模式
- 責任鏈模式是一種對象的行爲模式。在責任鏈模式裏,不少對象由每個對象對其下家的引用而鏈接起來造成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求
- 發出這個請求的客戶端並不知道鏈上的哪個對象最終處理這個請求,這使得系統能夠在不影響客戶端的狀況下動態地從新組織和分配責任
- 責任鏈多是一條直線、一個環鏈或者一個樹結構的一部分
- 抽象處理者(Handler)角色:定義出一個處理請求的接口。若是須要,接口能夠定義 出一個方法以設定和返回對下家的引用。這個角色一般由一個Java抽象類或者Java接口實現。上圖中Handler類的聚合關係給出了具體子類對下家的引用,抽象方法handleRequest()規範了子類處理請求的操做
- 具體處理者(ConcreteHandler)角色:具體處理者接到請求後,能夠選擇將請求處理掉,或者將請求傳給下家。因爲具體處理者持有對下家的引用,所以,若是須要,具體處理者能夠訪問下家
- 有多個的對象能夠處理一個請求,哪一個對象處理該請求運行時刻自動肯定
- 在不明確指定接收者的狀況下,向多個對象中的一個提交一個請求
- 處理一個請求的對象集合應被動態指定
- 職責鏈模式對於請求的處理是不知道最終處理者是誰,因此是運行動態尋找並指定
- 而命令模式中對於命令的處理時在建立命令是已經顯式或隱式綁定了接收者
- 在 Tomcat 中這種設計模式幾乎被完整的使用,tomcat 的容器設置就是責任鏈模式,從 Engine 到 Host 再到 Context 一直到 Wrapper 都是經過一個鏈傳遞請求
- 繼承java.util.EventObject
- 事件狀態對象,用於listener的相應的方法之中,做爲參數,通常存在與listerner的方法之中
- 具體的事件源,好比說,你點擊一個button,那麼button就是event source,要想使button對某些事件進行響應,你就須要註冊特定的listener
- 繼承 java.util.EventListener
- 對每一個明確的事件的發生,都相應地定義一個明確的Java方法。這些方法都集中定義在事件監聽者(EventListener)接口中。 實現了事件監聽者接口中一些或所有方法的類就是事件監聽者
- Tomcat的ServletContextListener
- Event Object: ServletContextEvent
- Event Listener: ServletContextListener
- Event Source: Container 加載Web 應用程序或容器移除Web 應用程序時
- 監聽 ServletContext 對象的生命週期,實際上就是監聽 Web 應用的生命週期
- 當Servlet 容器啓動或終止Web 應用時,會觸發ServletContextEvent 事件,該事件由ServletContextListener 來處理
- ServletContextListener 接口中定義了處理ServletContextEvent事件的兩個方法
- contextInitialized:當Servlet 容器啓動Web 應用時調用該方法。在調用完該方法以後,容器再對Filter 初始化,而且對那些在Web 應用啓動時就須要被初始化的Servlet 進行初始化
- contextDestroyed:當Servlet 容器終止Web 應用時調用該方法。在調用該方法以前,容器會先銷燬全部的Servlet 和Filter 過濾器
- 在 web.xml 中進行以下配置,以使得監聽器能夠起做用(listener和listener-class)
- Servlet 容器會在啓動或終止 Web 應用時,會調用監聽器的相關方法。在 web.xml 文件中, <listener> 元素用於向容器註冊監聽器
- 在Container 加載Web 應用程序時(例如啓動 Container 以後),會呼叫contextInitialized() ,而當容器移除Web 應用程序時,會呼叫contextDestroyed () 方法
- 當 Web 應用啓動時,Servlet 容器先調用contextInitialized() 方法,再調用lifeInit 的init() 方法;當Web 應用終止時,Servlet 容器先調用lifeInit 的destroy() 方法,再調用contextDestroyed() 方法
- 因而可知,在Web 應用的生命週期中,ServletContext 對象最先被建立,最晚被銷燬
- Spring的ContextLoaderListener
- 本質上是個ServletContextListener
- 監聽器是啓動根IoC容器並把它載入到Web容器的主要功能模塊,也是整個Spring Web應用加載IoC的第一個地方
- ConfigurableWebApplicationContext.refresh()自動裝配ApplicationContext的配置信息
- Spring的ApplicationListener
- ApplicationEvent
- 是事件,它就是媒介,充當介質的做用
- Event Listener ( Observer)
- ApplicationListener
- 須要到容器中註冊。他要關心他所關心的ApplicationEvent
- ApplicationContext(ApplicationEventPublisher)
- ApplicationEventMulticaster
- SUBJECT一個代理。他會管理咱們的 ApplicationListener
- Spring提供了ApplicationEventMulticaster接口,負責管理ApplicationListener和發佈ApplicationEvent。ApplicationContext會把相應的事件相關工做委派給ApplicationEventMulticaster接口實現類來作
- 當ApplicationContext接收到事件後,事件的廣播是Spring內部給咱們作的,不須要了解具體的細節
- 其實在 Spring讀取配置文件以後,利用反射,將全部實現ApplicationListener的Bean找出來,註冊爲容器的事件監聽器
- 當接收到事件的時候,Spring會逐個調用事件配置文件中的監聽器
- ContextClosedEvent:當ApplicationContext被關閉時觸發該事件。容器被關閉時,其管理的全部 單例Bean都被銷燬
- ContextRefreshedEvent: 當ApplicationContext初始化或者刷新時觸發該事件
- ContextStartedEvent: 當容器調用ConfigurableApplicationContext的 Start()方法開始/從新開始容器時觸發該事件
- ContextStoppedEvent: 當容器調用ConfigurableApplicationContext 的Stop()方法中止容器時觸發該事件
- RequestHandleEvent: 在Web應用中,當一個http請求(request)結束觸發該事件
- EventListener是傳統的c/s界面事件模型,分事件源和事件(狀態)角色,事件源要通過事件的包裝、成爲事件的屬性之一再傳遞給事件監聽/處理者,這個事件監聽者就至關於觀察者。我記得好像VB或C#也是這種模型
- Observer模式的模型就簡潔多了,沒有分事件源和事件,兩者合二爲一爲一個角色:被觀察者,從字面語義上也應該這樣,另外一個是觀察者角色
- 就是我上面說的Observer模式比較EventListener的不一樣之處還在於將大部分工做收歸Observable根類實現了、包括定義監聽者隊列、通知方法都實現了,咱們只要繼承、調用和傳值就好了
- 如今想一想多是EventListener監聽機制是從c/s時代就延續下來的,而Observer模式則是和iterator迭代器模式一樣被整合進jdk的,因此如今這兩種功用存在交叉的api會同時存在
- 定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新
- Observer模式的典型應用
- 偵聽事件驅動程序設計中的外部事件
- 偵聽/監視某個對象的狀態變化
- 發佈者/訂閱者(publisher/subscriber)模型中,當一個外部事件(新的產品,消息的出現等等)被觸發時,通知郵件列表中的訂閱者
- 對象之間能夠進行同步通訊
- 能夠同時通知一到多個關聯對象
- 對象之間的關係以鬆耦合的形式組合,互不依賴
- Subject(被觀察者): 被觀察的對象。當須要被觀察的狀態發生變化時,須要通知隊列中全部觀察者對象。Subject須要維持(添加,刪除,通知)一個觀察者對象的隊列列表
- ConcreteSubject: 被觀察者的具體實現。包含一些基本的屬性狀態及其餘操做
- Observer(觀察者): 接口或抽象類。當Subject的狀態發生變化時,Observer對象將經過一個callback函數獲得通知
- ConcreteObserver: 觀察者的具體實現。獲得通知後將完成一些具體的業務邏輯處理
- Spring觀察者模式應用:跟監聽模式相似,參考監聽模式
- 策略模式屬於對象的行爲模式。其用意是針對一組算法,將每個算法封裝到具備共同接口的獨立的類中,從而使得它們能夠相互替換。策略模式使得算法能夠在不影響到客戶端的狀況下發生變化
- 策略模式,又叫算法簇模式,就是定義了不一樣的算法族,而且之間能夠互相替換,此模式讓算法的變化獨立於使用算法的客戶
- 策略模式的好處在於你能夠動態的改變對象的行爲
- 設計原則是把一個類中常常改變或者未來可能改變的部分提取出來,做爲一個接口,而後在類中包含這個對象的實例,這樣類的實例在運行時就能夠隨意調用實現了這個接口的類的行爲
- 策略模式是對算法的包裝,是把使用算法的責任和算法自己分割開來,委派給不一樣的對象管理。策略模式一般把一個系列的算法包裝到一系列的策略類裏面,做爲一個抽象策略類的子類。用一句話來講,就是:「準備一組算法,並將每個算法封裝起來,使得它們能夠互換」
- 策略模式僅僅封裝算法,提供新的算法插入到已有系統中,以及老算法從系統中「退休」的方法,策略模式並不決定在什麼時候使用何種算法。在什麼狀況下使用什麼算法是由客戶端決定的
- 包含三個角色
- Context(上下文):使用不一樣策略的環境,它能夠根據自身的條件選擇不一樣的策略實現類來完成所要的操做。它持有一個策略實例的引用。建立具體策略對象的方法也能夠由他完成
- Strategy( 抽象策略):抽象策略,定義每一個策略都要實現的策略方法
- Concrete Strategy( 具體策略對象):具體策略實現類,實現抽象策略中定義的策略方法
- 策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活,具備更好的維護性和擴展性
- 策略模式一個很大的特色就是各個策略算法的平等性。對於一系列具體的策略算法,你們的地位是徹底同樣的,正由於這個平等性,才能實現算法之間能夠相互替換。全部的策略算法在實現上也是相互獨立的,相互之間是沒有依賴的
- 因此能夠這樣描述這一系列策略算法:策略算法是相同行爲的不一樣實現
- 運行期間,策略模式在每個時刻只能使用一個具體的策略實現對象,雖然能夠動態地在不一樣的策略實現中切換,可是同時只能使用一個
- 常常見到的是,全部的具體策略類都有一些公有的行爲。這時候,就應當把這些公有的行爲放到共同的抽象策略角色Strategy類裏面。固然這時候抽象策略角色必需要用Java抽象類實現,而不能使用接口
- 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承能夠把公共的代碼移到父類裏面,從而避免代碼重複
- 使用策略模式能夠避免使用多重條件(if-else)語句。多重條件語句不易維護,它把採起哪種算法或採起哪種行爲的邏輯與算法或行爲的邏輯混合在一塊兒,通通列在一個多重條件語句裏面,比使用繼承的辦法還要原始和落後
- 客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道算法或行爲的狀況
- 因爲策略模式把每一個具體的策略實現都單獨封裝成爲類,若是備選的策略不少的話,那麼對象的數目就會很可觀
- Spring 中策略模式使用有多個地方,如 Bean 定義對象的建立以及代理對象的建立等
- Spring 的代理方式有兩個 Jdk 動態代理和 CGLIB 代理,這兩個代理方式的使用正是使用了策略模式
- 抽象策略是 AopProxy 接口
- Cglib2AopProxy 和 JdkDynamicAopProxy 分別表明兩種策略的實現方式
- ProxyFactoryBean 就是表明 Context 角色,它根據條件選擇使用 Jdk 代理方式仍是 CGLIB 方式
- 三個類(AopProxyFactory,DefaultAopProxyFactory,ProxyCreatorSupport)主要是來負責建立具體策略對象,ProxyFactoryBean 是經過依賴的方法來關聯具體策略對象的,它是經過調用策略對象的 getProxy(ClassLoader classLoader) 方法來完成操做
- 工廠是建立型模式,它的做用就是建立對象
- 策略是行爲型模式,它的做用是讓一個對象在許多行爲中選擇一種行爲
- 工廠模式是建立型的設計模式,它接受指令,建立出符合要求的實例;它主要解決的是資源的統一分發,將對象的建立徹底獨立出來,讓對象的建立和具體的使用客戶無關。主要應用在多數據庫選擇,類庫文件加載等
- 策略模式是爲了解決的是策略的切換與擴展,更簡潔的說是定義策略族,分別封裝起來,讓他們之間能夠相互替換,策略模式讓策略的變化獨立於使用策略的客戶
- 定義一個操做中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟
- 爲了提升代碼的複用性和系統的靈活性,可使用一種稱之爲模板方法模式的設計模式來對這類狀況進行設計,在模板方法模式中,將實現功能的每個步驟所對應的方法稱爲基本方法(例如「點單」、「吃東西」和「買單」),而調用這些基本方法同時定義基本方法的執行次序的方法稱爲模板方法(例如「請客」)
- 在模板方法模式中,能夠將相同的代碼放在父類中,例如將模板方法「請客」以及基本方法「點單」和「買單」的實現放在父類中
- 而對於基本方法「吃東西」,在父類中只作一個聲明,將其具體實現放在不一樣的子類中,在一個子類中提供「吃麪條」的實現,而另外一個子類提供「吃滿漢全席」的實現
- 好處
- 提升了代碼的複用性
- 還能夠利用面向對象的多態性,在運行時選擇一種具體子類,實現完整的「請客」方法,提升系統的靈活性和可擴展性
- 變化的東西是一段代碼,並且這段代碼會用到原類中的變量,用回調對象
- 咱們去實現這個回調方法,就把變化的東西集中到這裏了
- Spring的JdbcTemplate用的是回調的方式實現模板方法模式
- Façade模式、Adapter模式、Bridge模式與Decorator模式區別
- Façade模式注重簡化接口
- Adapter模式注重轉換接口
- Bridge模式注重分離接口(抽象)與其實現
- Decorator模式注重穩定接口的前提下爲對象擴展功能
工做一到五年的java 開發工程師朋友能夠加入咱們Java架構交流羣:760940986 羣內提供 高可用,高併發,spring源碼,mybatis源碼,JVM,大數據,Netty等多個技術知識的架構視頻資料 還有大把大牛在羣內交流以及解答面試指導,問題答疑~~要進來和大牛交流學習提高提高本身嗎~~~~
程序員