Java面試總結匯總,整理了包括Java重點知識,以及經常使用開源框架,歡迎你們閱讀。文章可能有錯誤的地方,由於我的知識有限,歡迎各位大佬指出!文章持續更新中......java
ID 標題 地址 1 設計模式面試題(總結最全面的面試題) juejin.cn/post/684490… 2 Java基礎知識面試題(總結最全面的面試題) juejin.cn/post/684490… 3 Java集合面試題(總結最全面的面試題) juejin.cn/post/684490… 4 JavaIO、BIO、NIO、AIO、Netty面試題(總結最全面的面試題) juejin.cn/post/684490… 5 Java併發編程面試題(總結最全面的面試題) juejin.cn/post/684490… 6 Java異常面試題(總結最全面的面試題) juejin.cn/post/684490… 7 Java虛擬機(JVM)面試題(總結最全面的面試題) juejin.cn/post/684490… 8 Spring面試題(總結最全面的面試題) juejin.cn/post/684490… 9 Spring MVC面試題(總結最全面的面試題) juejin.cn/post/684490… 10 Spring Boot面試題(總結最全面的面試題) juejin.cn/post/684490… 11 Spring Cloud面試題(總結最全面的面試題) juejin.cn/post/684490… 12 Redis面試題(總結最全面的面試題) juejin.cn/post/684490… 13 MyBatis面試題(總結最全面的面試題) juejin.cn/post/684490… 14 MySQL面試題(總結最全面的面試題) juejin.cn/post/684490… 15 TCP、UDP、Socket、HTTP面試題(總結最全面的面試題) juejin.cn/post/684490… 16 Nginx面試題(總結最全面的面試題) juejin.cn/post/684490… 17 ElasticSearch面試題 18 kafka面試題 19 RabbitMQ面試題(總結最全面的面試題) juejin.cn/post/684490… 20 Dubbo面試題(總結最全面的面試題) juejin.cn/post/684490… 21 ZooKeeper面試題(總結最全面的面試題) juejin.cn/post/684490… 22 Netty面試題(總結最全面的面試題) 23 Tomcat面試題(總結最全面的面試題) juejin.cn/post/684490… 24 Linux面試題(總結最全面的面試題) juejin.cn/post/684490… 25 互聯網相關面試題(總結最全面的面試題) 26 互聯網安全面試題(總結最全面的面試題)
Spring是一個輕量級Java開發框架,最先有Rod Johnson建立,目的是爲了解決企業級應用開發的業務邏輯層和其餘各層的耦合問題。它是一個分層的JavaSE/JavaEE full-stack(一站式)輕量級開源框架,爲開發Java應用程序提供全面的基礎架構支持。Spring負責基礎架構,所以Java開發者能夠專一於應用程序的開發。git
Spring最根本的使命是解決企業級應用開發的複雜性,即簡化Java開發。程序員
Spring能夠作不少事情,它爲企業級開發提供給了豐富的功能,可是這些功能的底層都依賴於它的兩個核心特性,也就是依賴注入(dependency injection,DI)和面向切面編程(aspect-oriented programming,AOP)。github
爲了下降Java開發的複雜性,Spring採起了如下4種關鍵策略web
IOC(控制翻轉):面試
AOP(面對切面編程)正則表達式
Spring設計目標:Spring爲開發者提供一個一站式輕量級應用開發平臺;spring
Spring設計理念:在JavaEE開發中,支持POJO和JavaBean開發方式,使應用面向接口開發,充分支持OOP(面向對象)設計方法;Spring經過IOC容器實現對象耦合關係的管理,並實現依賴反轉,將對象之間的依賴關係交給IOC容器,實現解耦;數據庫
Spring框架的核心:IOC容器和AOP模塊。經過IOC容器管理POJO對象以及他們之間的耦合關係;經過AOP以動態非侵入的方式加強服務。編程
IOC讓相互協做的組件保持鬆散的耦合,而AOP編程容許你把遍及於應用各層的功能分離出來造成可重用的功能組件。
優勢
方便解耦,簡化開發
Spring就是一個大工廠,能夠將全部對象的建立和依賴關係的維護,交給Spring管理。
AOP編程的支持
Spring提供面向切面編程,能夠方便的實現對程序進行權限攔截、運行監控等功能。
聲明式事務的支持
只須要經過配置就能夠完成對事務的管理,而無需手動編程。
方便程序的測試
Spring對Junit4支持,能夠經過註解方便的測試Spring程序。
方便集成各類優秀框架
Spring不排斥各類優秀的開源框架,其內部提供了對各類優秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
下降JavaEE API的使用難度
Spring對JavaEE開發中很是難用的一些API(JDBC、JavaMail、遠程調用等),都提供了封裝,使這些API應用難度大大下降。
缺點
Spring價值:
核心容器(Core Container)
、 AOP(Aspect Oriented Programming)和設備支持(Instrmentation)
、數據訪問與集成(Data Access/Integeration)
、 Web
、 消息(Messaging)
、 Test
等 6 個模塊中。 如下是 Spring 5 的模塊結構圖: 這是基本的Spring模塊,提供spring 框架的基礎功能,BeanFactory 是 任何以spring爲基礎的應用的核心。Spring 框架創建在此模塊之上,它使Spring成爲一個容器。
Bean 工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和依賴從真正的應用代碼中分離。最經常使用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根據XML文件中的定義加載beans。該容器從XML 文件讀取配置元數據並用它去建立一個徹底配置的系統或應用。
Spring 應用通常有如下組件:
使用 Spring 有如下方式:
控制反轉即IOC (Inversion of Control),它把傳統上由程序代碼直接操控的對象的調用權交給容器,經過容器來實現對象組件的裝配和管理。所謂的「控制反轉」概念就是對組件對象控制權的轉移,從程序代碼自己轉移到了外部容器。
Spring IOC 負責建立對象,管理對象(經過依賴注入(DI),裝配對象,配置對象,而且管理這些對象的整個生命週期。
管理對象的建立和依賴關係的維護。對象的建立並非一件簡單的事,在對象關係比較複雜時,若是依賴關係須要程序猿來維護的話,那是至關頭疼的
解耦,由容器去維護具體的對象
託管了類的產生過程,好比咱們須要在類的產生過程當中作一些處理,最直接的例子就是代理,若是有容器程序能夠把這部分處理交給容器,應用程序則無需去關心類是如何完成代理的
Spring 中的 IOC 的實現原理就是工廠模式加反射機制。
示例:
interface Fruit { public abstract void eat(); } class Apple implements Fruit { public void eat(){ System.out.println("Apple"); } } class Orange implements Fruit { public void eat(){ System.out.println("Orange"); } } class Factory { public static Fruit getInstance(String ClassName) { Fruit f=null; try { f=(Fruit)Class.forName(ClassName).newInstance(); } catch (Exception e) { e.printStackTrace(); } return f; } } class Client { public static void main(String[] a) { Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple"); if(f!=null){ f.eat(); } } } 複製代碼
Spring 的 IOC 設計支持如下功能:
其中,最重要的就是依賴注入,從 XML 的配置上說,即 ref 標籤。對應 Spring RuntimeBeanReference 對象。
對於 IOC 來講,最重要的就是容器。容器管理着 Bean 的生命週期,控制着 Bean 的依賴注入。
BeanFactory和ApplicationContext是Spring的兩大核心接口,均可以當作Spring的容器。其中ApplicationContext是BeanFactory的子接口。
依賴關係
ApplicationContext接口做爲BeanFactory的派生,除了提供BeanFactory所具備的功能外,還提供了更完整的框架功能:
繼承MessageSource,所以支持國際化。
統一的資源文件訪問方式。
提供在監聽器中註冊bean的事件。
同時加載多個配置文件。
載入多個(有繼承關係)上下文 ,使得每個上下文都專一於一個特定的層次,好比應用的web層。
加載方式
BeanFactroy採用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),纔對該Bean進行加載實例化。這樣,咱們就不能發現一些存在的Spring的配置問題。若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法纔會拋出異常。
ApplicationContext,它是在容器啓動時,一次性建立了全部的Bean。這樣,在容器啓動時,咱們就能夠發現Spring中存在的配置錯誤,這樣有利於檢查所依賴屬性是否注入。 ApplicationContext啓動後預載入全部的單實例Bean,經過預載入單實例bean ,確保當你須要的時候,你就不用等待,由於它們已經建立好了。
相對於基本的BeanFactory,ApplicationContext 惟一的不足是佔用內存空間。當應用程序配置Bean較多時,程序啓動較慢。
建立方式
註冊方式
Spring 做者 Rod Johnson 設計了兩個接口用以表示容器。
BeanFactory 簡單粗暴,能夠理解爲就是個 HashMap,Key 是 BeanName,Value 是 Bean 實例。一般只提供註冊(put),獲取(get)這兩個功能。咱們能夠稱之爲 「低級容器」。
ApplicationContext 能夠稱之爲 「高級容器」。由於他比 BeanFactory 多了更多的功能。他繼承了多個接口。所以具有了更多的功能。例如資源的獲取,支持多種消息(例如 JSP tag 的支持),對 BeanFactory 多了工具級別的支持等待。因此你看他的名字,已經不是 BeanFactory 之類的工廠了,而是 「應用上下文」, 表明着整個大容器的全部功能。該接口定義了一個 refresh 方法,此方法是全部閱讀 Spring 源碼的人的最熟悉的方法,用於刷新整個容器,即從新加載/刷新全部的 bean。
固然,除了這兩個大接口,還有其餘的輔助接口,這裏就不介紹他們了。
BeanFactory和ApplicationContext的關係
爲了更直觀的展現 「低級容器」 和 「高級容器」 的關係,這裏經過經常使用的 ClassPathXmlApplicationContext 類來展現整個容器的層級 UML 關係。
有點複雜? 先不要慌,我來解釋一下。
最上面的是 BeanFactory,下面的 3 個綠色的,都是功能擴展接口,這裏就不展開講。
看下面的隸屬 ApplicationContext 粉紅色的 「高級容器」,依賴着 「低級容器」,這裏說的是依賴,不是繼承哦。他依賴着 「低級容器」 的 getBean 功能。而高級容器有更多的功能:支持不一樣的信息源頭,能夠訪問文件資源,支持應用事件(Observer 模式)。
一般用戶看到的就是 「高級容器」。 但 BeanFactory 也很是夠用啦!
左邊灰色區域的是 「低級容器」, 只負載加載 Bean,獲取 Bean。容器其餘的高級功能是沒有的。例如上圖畫的 refresh 刷新 Bean 工廠全部配置,生命週期事件回調等。
小結
加載配置文件,解析成 BeanDefinition 放在 Map 裏。
調用 getBean 的時候,從 BeanDefinition 所屬的 Map 裏,拿出 Class 對象進行實例化,同時,若是有依賴關係,將遞歸調用 getBean 方法 —— 完成依賴注入。
上面就是 Spring 低級容器(BeanFactory)的 IOC。
至於高級容器 ApplicationContext,他包含了低級容器的功能,當他執行 refresh 模板方法的時候,將刷新整個容器的 Bean。同時其做爲高級容器,包含了太多的功能。一句話,他不只僅是 IOC。他支持不一樣信息源頭,支持 BeanFactory 工具類,支持層級容器,支持訪問文件資源,支持事件發佈通知,支持接口回調等等。
FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這裏,你須要正確設置classpath由於這個容器將在classpath裏找bean配置。
WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的全部bean。
依賴注入是時下最流行的IOC實現方式,依賴注入分爲接口注入(Interface Injection),Setter方法注入(Setter Injection)和構造器注入(Constructor Injection)三種方式。其中接口注入因爲在靈活性和易用性比較差,如今從Spring4開始已被廢棄。
構造器依賴注入:構造器依賴注入經過容器觸發一個類的構造器來實現的,該類有一系列參數,每一個參數表明一個對其餘類的依賴。
Setter方法注入:Setter方法注入是容器經過調用無參構造器或無參static工廠 方法實例化bean以後,調用該bean的setter方法,即實現了基於setter的依賴注入。
構造函數注入 setter 注入 沒有部分注入 有部分注入 不會覆蓋 setter 屬性 會覆蓋 setter 屬性 任意修改都會建立一個新實例 任意修改不會建立一個新實例 適用於設置不少屬性 適用於設置少許屬性
Spring框架支持如下五種bean的做用域:
注意: 缺省的Spring bean 的做用域是Singleton。使用 prototype 做用域須要慎重的思考,由於頻繁建立和銷燬 bean 會帶來很大的性能開銷。
不是,Spring框架中的單例bean不是線程安全的。
spring 中的 bean 默認是單例模式,spring 框架並無對單例 bean 進行多線程的封裝處理。
實際上大部分時候 spring bean 無狀態的(好比 dao 類),全部某種程度上來講 bean 也是安全的,但若是 bean 有狀態的話(好比 view model 對象),那就要開發者本身去保證線程安全了,最簡單的就是改變 bean 的做用域,把「singleton」變動爲「prototype」,這樣請求 bean 至關於 new Bean()了,因此就能夠保證線程安全了。
在通常狀況下,只有無狀態的Bean才能夠在多線程環境下共享,在Spring中,絕大部分Bean均可以聲明爲singleton做用域,由於Spring對一些Bean中非線程安全狀態採用ThreadLocal進行處理,解決線程安全問題。
ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。同步機制採用了「時間換空間」的方式,僅提供一份變量,不一樣的線程在訪問前須要獲取鎖,沒得到鎖的線程則須要排隊。而ThreadLocal採用了「空間換時間」的方式。
ThreadLocal會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進ThreadLocal。
bean在Spring容器中從建立到銷燬經歷了若干階段,每一階段均可以針對Spring如何管理bean進行個性化定製。
正如你所見,在bean準備就緒以前,bean工廠執行了若干啓動步驟。
咱們對上圖進行詳細描述:
Spring對bean進行實例化;
Spring將值和bean的引用注入到bean對應的屬性中;
若是bean實現了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;
若是bean實現了BeanFactoryAware接口,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入;
若是bean實現了ApplicationContextAware接口,Spring將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來;
若是bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessBeforeInitialization()方法;
若是bean實現了InitializingBean接口,Spring將調用它們的after-PropertiesSet()方法。相似地,若是bean使用initmethod聲明瞭初始化方法,該方法也會被調用;
若是bean實現了BeanPostProcessor接口,Spring將調用它們的post-ProcessAfterInitialization()方法;
此時,bean已經準備就緒,能夠被應用程序使用了,它們將一直駐留在應用上下文中,直到該應用上下文被銷燬;
若是bean實現了DisposableBean接口,Spring將調用它的destroy()接口方法。一樣,若是bean使用destroy-method聲明瞭銷燬方法,該方法也會被調用。
如今你已經瞭解瞭如何建立和加載一個Spring容器。可是一個空的容器並無太大的價值,在你把東西放進去以前,它裏面什麼都沒有。爲了從Spring的DI(依賴注入)中受益,咱們必須將應用對象裝配進Spring容器中。
有兩個重要的bean 生命週期方法,第一個是setup , 它是在容器加載bean的時候被調用。第二個方法是 teardown 它是在容器卸載類的時候被調用。
bean 標籤有兩個重要的屬性(init-method和destroy-method)。用它們你能夠本身定製初始化和註銷方法。它們也有相應的註解(@PostConstruct和@PreDestroy)。
該標籤用來裝配可重複的list值。 | |
---|---|
該標籤用來裝配沒有重複的set值。 | |
該標籤可用來注入鍵和值能夠爲任何類型的鍵值對。 | |
該標籤支持注入鍵和值都是字符串類型的鍵值對。 |
在spring中,對象無需本身查找或建立與其關聯的其餘對象,由容器負責把須要相互協做的對象引用賦予各個對象,使用autowire來配置自動裝載模式。
在Spring框架xml配置中共有5種自動裝配:
no:默認的方式是不進行自動裝配的,經過手工設置ref屬性來進行裝配bean。
byName:經過bean的名稱進行自動裝配,若是一個bean的 property 與另外一bean 的name 相同,就進行自動裝配。
byType:經過參數的數據類型進行自動裝配。
constructor:利用構造函數進行裝配,而且構造函數的參數經過byType進行裝配。
autodetect:自動探測,若是有構造方法,經過 construct的方式自動裝配,不然使用 byType的方式自動裝配。
使用@Autowired註解來自動裝配指定的bean。在使用@Autowired註解以前須要在Spring配置文件進行配置,<context:annotation-config />。
在啓動spring IOC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor後置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IOC容器自動查找須要的bean,並裝配給該對象的屬性。在使用@Autowired時,首先在容器中查詢對應類型的bean:
若是查詢結果恰好爲一個,就將該bean裝配給@Autowired指定的數據;
若是查詢的結果不止一個,那麼@Autowired會根據名稱來查找;
若是上述查找的結果爲空,那麼會拋出異常。解決方法時,使用required=false。
自動裝配的侷限性是:
重寫:你仍需用 和 配置來定義依賴,意味着總要重寫自動裝配。
基本數據類型:你不能自動裝配簡單的屬性,如基本數據類型,String字符串,和類。
模糊特性:自動裝配不如顯式裝配精確,若是有可能,建議使用顯式裝配。
基於Java的配置,容許你在少許的Java註解的幫助下,進行你的大部分Spring配置而非經過XML文件。
以@Configuration 註解爲例,它用來標記類能夠當作一個bean的定義,被Spring IOC容器使用。
另外一個例子是@Bean註解,它表示此方法將要返回一個對象,做爲一個bean註冊進Spring應用上下文。
@Configuration public class StudentConfig { @Bean public StudentBean myStudent() { return new StudentBean(); } } 複製代碼
<context:annotation-config/>
元素。@Component:這將 java 類標記爲 bean。它是任何 Spring 管理組件的通用構造型。spring 的組件掃描機制如今能夠將其拾取並將其拉入應用程序環境中。
@Controller:這將一個類標記爲 Spring Web MVC 控制器。標有它的 Bean 會自動導入到 IOC 容器中。
@Service:此註解是組件註解的特化。它不會對 @Component 註解提供任何其餘行爲。您能夠在服務層類中使用 @Service 而不是 @Component,由於它以更好的方式指定了意圖。
@Repository:這個註解是具備相似用途和功能的 @Component 註解的特化。它爲 DAO 提供了額外的好處。它將 DAO 導入 IOC 容器,並使未經檢查的異常有資格轉換爲 Spring DataAccessException。
public class Employee { private String name; @Required public void setName(String name){ this.name=name; } public string getName(){ return name; } } 複製代碼
public class Employee { private String name; @Autowired public void setName(String name) { this.name=name; } public string getName(){ return name; } } 複製代碼
@Autowired和@Resource可用於:構造函數、成員變量、Setter方法
@Autowired和@Resource之間的區別在於
@Autowired默認是按照類型裝配注入的,默認狀況下它要求依賴對象必須存在(能夠設置它required屬性爲false)。
@Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean纔會按照類型來裝配注入。
JdbcTemplate
SimpleJdbcTemplate
NamedParameterJdbcTemplate
SimpleJdbcInsert
SimpleJdbcCall
編程式事務管理:這意味你經過編程的方式管理事務,給你帶來極大的靈活性,可是難維護。
聲明式事務管理:這意味着你能夠將業務代碼和事務管理分離,你只需用註解和XML配置來管理事務。
spring事務的傳播行爲說的是,當多個事務同時存在的時候,spring如何處理這些事務的行爲。
① PROPAGATION_REQUIRED:若是當前沒有事務,就建立一個新事務,若是當前存在事務,就加入該事務,該設置是最經常使用的設置。
② PROPAGATION_SUPPORTS:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就以非事務執行。
③ PROPAGATION_MANDATORY:支持當前事務,若是當前存在事務,就加入該事務,若是當前不存在事務,就拋出異常。
④ PROPAGATION_REQUIRES_NEW:建立新事務,不管當前存不存在事務,都建立新事務。
⑤ PROPAGATION_NOT_SUPPORTED:以非事務方式執行操做,若是當前存在事務,就把當前事務掛起。
⑥ PROPAGATION_NEVER:以非事務方式執行,若是當前存在事務,則拋出異常。
⑦ PROPAGATION_NESTED:若是當前存在事務,則在嵌套事務內執行。若是當前沒有事務,則按REQUIRED屬性執行。
spring 有五大隔離級別,默認值爲 ISOLATION_DEFAULT(使用數據庫的設置),其餘四個隔離級別和數據庫的隔離級別一致:
ISOLATION_DEFAULT:用底層數據庫的設置隔離級別,數據庫設置的是什麼我就用什麼;
ISOLATION_READ_UNCOMMITTED:未提交讀,最低隔離級別、事務未提交前,就可被其餘事務讀取(會出現幻讀、髒讀、不可重複讀);
ISOLATION_READ_COMMITTED:提交讀,一個事務提交後才能被其餘事務讀取到(會形成幻讀、不可重複讀),SQL server 的默認級別;
ISOLATION_REPEATABLE_READ:可重複讀,保證屢次讀取同一個數據時,其值都和事務開始時候的內容是一致,禁止讀取到別的事務未提交的數據(會形成幻讀),MySQL 的默認級別;
ISOLATION_SERIALIZABLE:序列化,代價最高最可靠的隔離級別,該隔離級別能防止髒讀、不可重複讀、幻讀。
髒讀 :表示一個事務可以讀取另外一個事務中還未提交的數據。好比,某個事務嘗試插入記錄 A,此時該事務還未提交,而後另外一個事務嘗試讀取到了記錄 A。
不可重複讀 :是指在一個事務內,屢次讀同一數據。
幻讀 :指同一個事務內屢次查詢返回的結果集不同。好比同一個事務 A 第一次查詢時候有 n 條記錄,可是第二次同等條件下查詢卻有 n+1 條記錄,這就好像產生了幻覺。發生幻讀的緣由也是另一個事務新增或者刪除或者修改了第一個事務結果集裏面的數據,同一個記錄的數據內容被修改了,全部數據行的記錄就變多或者變少了。
OOP(Object-Oriented Programming)面向對象編程,容許開發者定義縱向的關係,但並適用於定義橫向的關係,致使了大量代碼的重複,而不利於各個模塊的重用。
AOP(Aspect-Oriented Programming),通常稱爲面向切面編程,做爲面向對象的一種補充,用於將那些與業務無關,但卻對多個對象產生影響的公共行爲和邏輯,抽取並封裝爲一個可重用的模塊,這個模塊被命名爲「切面」(Aspect),減小系統中的重複代碼,下降了模塊間的耦合度,同時提升了系統的可維護性。可用於權限認證、日誌、事務處理等。
AOP實現的關鍵在於 代理模式,AOP代理主要分爲靜態代理和動態代理。靜態代理的表明爲AspectJ;動態代理則以Spring AOP爲表明。
(1)AspectJ是靜態代理的加強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,所以也稱爲編譯時加強,他會在編譯階段將AspectJ(切面)織入到Java字節碼中,運行的時候就是加強以後的AOP對象。
(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是每次運行時在內存中臨時爲方法生成一個AOP對象,這個AOP對象包含了目標對象的所有方法,而且在特定的切點作了加強處理,並回調原對象的方法。
Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理:
JDK動態代理只提供接口的代理,不支持類的代理。核心InvocationHandler接口和Proxy類,InvocationHandler 經過invoke()方法反射來調用目標類中的代碼,動態地將橫切邏輯和業務編織在一塊兒;接着,Proxy利用 InvocationHandler動態建立一個符合某一接口的的實例, 生成目標類的代理對象。
若是代理類沒有實現 InvocationHandler 接口,那麼Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,能夠在運行時動態的生成指定類的一個子類對象,並覆蓋其中特定方法並添加加強代碼,從而實現AOP。CGLIB是經過繼承的方式作的動態代理,所以若是某個類被標記爲final,那麼它是沒法使用CGLIB作動態代理的。
靜態代理與動態代理區別在於生成AOP代理對象的時機不一樣,相對來講AspectJ的靜態代理方式具備更好的性能,可是AspectJ須要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最終生成的代理實例; method 是被代理目標實例的某個具體方法; args 是被代理目標實例某個方法的具體入參, 在方法反射調用時使用。
(1)切面(Aspect):切面是通知和切點的結合。通知和切點共同定義了切面的所有內容。 在Spring AOP中,切面可使用通用類(基於模式的風格) 或者在普通類中以 @AspectJ 註解來實現。
(2)鏈接點(Join point):指方法,在Spring AOP中,一個鏈接點 老是 表明一個方法的執行。 應用可能有數以千計的時機應用通知。這些時機被稱爲鏈接點。鏈接點是在應用執行過程當中可以插入切面的一個點。這個點能夠是調用方法時、拋出異常時、甚至修改一個字段時。切面代碼能夠利用這些點插入到應用的正常流程之中,並添加新的行爲。
(3)通知(Advice):在AOP術語中,切面的工做被稱爲通知。
(4)切入點(Pointcut):切點的定義會匹配通知所要織入的一個或多個鏈接點。咱們一般使用明確的類和方法名稱,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點。
(5)引入(Introduction):引入容許咱們向現有類添加新方法或屬性。
(6)目標對象(Target Object): 被一個或者多個切面(aspect)所通知(advise)的對象。它一般是一個代理對象。也有人把它叫作 被通知(adviced) 對象。 既然Spring AOP是經過運行時代理實現的,這個對象永遠是一個 被代理(proxied) 對象。
(7)織入(Weaving):織入是把切面應用到目標對象並建立新的代理對象的過程。在目標對象的生命週期裏有多少個點能夠進行織入:
經過在代理類中包裹切面,Spring在運行期把切面織入到Spring管理的bean中。代理封裝了目標類,並攔截被通知方法的調用,再把調用轉發給真正的目標bean。當代理攔截到方法調用時,在調用目標bean方法以前,會執行切面邏輯。
直到應用須要被代理的bean時,Spring才建立代理對象。若是使用的是ApplicationContext的話,在ApplicationContext從BeanFactory中加載全部bean的時候,Spring纔會建立被代理的對象。由於Spring運行時才建立代理對象,因此咱們不須要特殊的編譯器來織入SpringAOP的切面。
關注點(concern)是應用中一個模塊的行爲,一個關注點可能會被定義成一個咱們想實現的一個功能。
橫切關注點(cross-cutting concern)是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,好比日誌,安全和數據傳輸,幾乎應用的每一個模塊都須要的功能。所以這些都屬於橫切關注點。
在AOP術語中,切面的工做被稱爲通知,其實是程序執行時要經過SpringAOP框架觸發的代碼段。
Spring切面能夠應用5種類型的通知:
aspect 由 pointcount 和 advice 組成,切面是通知和切點的結合。 它既包含了橫切邏輯的定義, 也包括了鏈接點的定義. Spring AOP 就是負責實施切面的框架, 它將切面所定義的橫切邏輯編織到切面所指定的鏈接點中. AOP 的工做重心在於如何將加強編織目標對象的鏈接點上, 這裏包含兩個工做:
能夠簡單地認爲, 使用 @Aspect 註解的類就是切面.