javascript
Spring框架从入门到精通
文章目錄
- 初識Spring框架
- 時代變遷
- Spring的野心
- 官網(wǎng)
- 框架組成
- 核心概念
- 三大核心組件的關(guān)系
- 主要jar組成
- Spring框架兩大核心:IoC和DI
- 概念
- IoC
- DI
- IoC的XML方式
- 創(chuàng)建springboot工程
- 創(chuàng)建Hello.java
- 創(chuàng)建applicationContext.xml
- 創(chuàng)建TestIoC.java
- 小結(jié)
- IoC的注解方式
- 創(chuàng)建springboot工程
- pom.xml
- Hello.java
- applicationContext.xml
- TestIoC.java
- DI依賴注入
- 創(chuàng)建Maven工程
- pom.xml
- Dept.java
- User.java
- applicationContext.xml
- TestDI.java
- 小結(jié)
- 面試:IoC和DI
- 自動裝配
- AOP面向切面編程
- 概念
- AspectJ
- AOP的三要素
- 通知
- 多切面執(zhí)行順序
- 使用步驟
- 創(chuàng)建切面
- 測試
初識Spring框架
時代變遷
原始時代我們用一個jsp搞定一切,但如此開發(fā)大型項目時我們遇到了問題,前端美化的代碼和后端的代碼交織,代碼中又有html、js、css樣式,又有業(yè)務(wù)邏輯和數(shù)據(jù)庫訪問代碼,雜亂不清晰,美工和開發(fā)打架。
于是mvc分層架構(gòu)封建時代出現(xiàn),把我們寫代碼的地方硬性分成3個地方,Model層封裝數(shù)據(jù),View視圖層頁面展現(xiàn),Controller控制層訪問轉(zhuǎn)發(fā)。代碼之間的耦合度降低。概念有了,需要實際干活的。于是隨著mvc分層概念的深入人心,業(yè)界涌現(xiàn)出很多實現(xiàn)框架,最著名的莫過于struts1和struts2。隨著前端框架的成熟,后端框架也應(yīng)運而生如:dbutils、jdbcTemplate、hibernate、ibatis、mybatis。
一個前端WEB層框架有了,一個后端數(shù)據(jù)庫層訪問框架有了,那中間呢?誰來勝任?spring破石而出。
Spring的野心
了解了歷史,有個問題值得我們?nèi)ド钏?#xff1f;spring到底想干什么?
它想把全球最好的技術(shù)組合到一起,為企業(yè)提供高質(zhì)量的企業(yè)級的應(yīng)用程序框架,減輕開發(fā)者開發(fā)的難度,減少重復(fù)的代碼。
目標(biāo)很宏大,那如何下手呢?如果是你,你會怎么實現(xiàn)?第一步要干什么呢?
我們拿經(jīng)典的框架來舉例子。
struts2作為WEB框架深受企業(yè)愛戴,它會自己管理action,來創(chuàng)建其實例,這樣在程序中就可以訪問action的資源。hibernate作為持久層優(yōu)秀的框架,它也自己管理持久對象??梢钥吹?#xff0c;各個諸侯都自己管理對象,而要想讓它們對象復(fù)用,那真是繁瑣。前面就有失敗者WebService,為了管理不同的開發(fā)語言的對象而層層包裝轉(zhuǎn)換,辛苦制定的規(guī)則,還借著J2EE規(guī)范之名,也推廣不開。
如何破局呢?想發(fā)號施令,想讓人聽從,最好的解決辦法就是扼住他們的咽喉。在java的世界里最重要的無疑就是對象的生命周期管理。于是spring以此為切入點,實現(xiàn)自己的統(tǒng)治。官宣所有對象由我來管理,struts2你不再管理對象,由我來管理,你要用從我這拿。hibernate你也不再管理對象,由我來管理,你要用從我這拿。你說管就能管的嗎?這兩個征戰(zhàn)數(shù)年戰(zhàn)功赫赫的大將軍會聽一個初出茅廬乳臭未干野小子的話?他們當(dāng)然不會聽,spring的話可以不聽,但他們都要聽開發(fā)者的。開發(fā)一個完整的系統(tǒng)有四個核心,WEB層支持、業(yè)務(wù)邏輯層、持久層支持、事務(wù)支持。而這就是它們的軟肋,這就是它們的命門所在,它們只能完成一部分工作,不是一個整體解決方案。而spring并沒有抹殺它們,而是依然給它們高官厚祿,承認(rèn)它們的市場地位,還贈與一個事務(wù)管理。一邊打壓一邊拉攏,它們兩位看看大勢已去,只能俯首稱臣。于是兵不血刃,一場變革悄然興起,一個經(jīng)典的三層框架誕生SSH (Strut2+Spring+Hibernate)。
故事很傳奇,聽的人很開心??蓅pring真就這么簡單嗎?如果這樣想,你就大錯特錯了。例如:spring怎么來實現(xiàn)對象的管轄?怎么讓不同技術(shù)之間能簡單的互相配合?這才是spring的決勝之處。
為實現(xiàn)這些spring可是絞盡腦汁、煞費苦心呢。它創(chuàng)新的形成了一套新的理論體系,可謂前無古人后無來者。其中最核心的是:IoC控制反轉(zhuǎn)、DI依賴注入、Bean工廠、SpringAOP面向切面編程、事務(wù)控制。
并且spring并沒有停止不前,這只是統(tǒng)治地球的第一步,隨著spring占領(lǐng)市場后,開始對有功之臣進(jìn)行清洗,struts2不再優(yōu)秀,致命bug層出不窮,剛好落井下石,spring推出了springmvc,最終終結(jié)了struts2。hibernate想用jdbcTemplate和jdo替代,卻被mybatis超越,目前還未統(tǒng)一。世界又達(dá)到新的平衡,經(jīng)典的新三大框架誕生,SSM(SpringMVC+Spring+MyBatis)。Spring并沒有放棄,而是另辟蹊徑,推出新的產(chǎn)品SpringBoot+SpringCloud 微服務(wù),目前新的趨勢已經(jīng)塵埃落定,一統(tǒng)江湖!
官網(wǎng)
http://spring.io框架組成
Spring是一個開源框架,是為了解決企業(yè)應(yīng)用程序開發(fā)復(fù)雜性而創(chuàng)建的。Spring框架的不光是技術(shù)牛,而是它的核心思想更牛,它不重復(fù)發(fā)明輪子,而是"拿來主義",把業(yè)界做的最好的技術(shù)黏合起來形成一個強(qiáng)大的企業(yè)級的應(yīng)用框架。
Spring 框架是一個分層架構(gòu),由7個定義良好的模塊組成。Spring 模塊構(gòu)建在核心容器之上,核心容器定義了創(chuàng)建、配置和管理 bean 的方式,如下圖所示:
組成 Spring 框架的每個模塊(或組件)都可以單獨存在,或者與其他一個或多個模塊聯(lián)合實現(xiàn)。每個模塊的功能如下:
|
| 核心容器Spring Core | 核心容器提供Spring框架的基本功能。核心容器的主要組件是BeanFactory,它是工廠模式的實現(xiàn)。BeanFactory 使用控制反轉(zhuǎn)(IOC)模式,將應(yīng)用程序的配置和依賴性規(guī)范與實際的應(yīng)用程序代碼分開。 |
| Spring上下文Spring Context | Spring上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業(yè)服務(wù),例如 JNDI、EJB、電子郵件、國際化、校驗和調(diào)度功能。 |
| Spring AOP | 通過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中??梢院苋菀椎厥?Spring框架管理的任何對象支持AOP。Spring AOP模塊為基于 Spring 的應(yīng)用程序中的對象提供了事務(wù)管理服務(wù)。通過使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務(wù)管理集成到應(yīng)用程序中。 |
| Spring DAO | JDBC DAO 抽象層提供了有意義的異常層次結(jié)構(gòu),可用該結(jié)構(gòu)來管理異常處理和不同數(shù)據(jù)庫供應(yīng)商拋出的錯誤消息。異常層次結(jié)構(gòu)簡化了錯誤處理,并且極大地降低了需要編寫的異常代碼數(shù)量(例如打開和關(guān)閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結(jié)構(gòu)。 |
| Spring ORM | Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關(guān)系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有這些都遵從 Spring 的通用事務(wù)和 DAO 異常層次結(jié)構(gòu)。 |
| Spring Web | Web上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于 Web 的應(yīng)用程序提供了上下文。所以Spring 框架支持與 Jakarta Struts的集成。Web模塊還簡化了處理多部分請求以及將請求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?/td> |
| Spring MVC框架 | MVC 框架是一個全功能的構(gòu)建 Web 應(yīng)用程序的 MVC 實現(xiàn)。通過策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術(shù),其中包括 JSP、Velocity、Tiles、iText 和 POI。 |
Spring 框架的功能可以用在任何J2EE服務(wù)器中,大多數(shù)功能也適用于不受管理的環(huán)境。Spring 的核心要點是:支持不綁定到特定J2EE服務(wù)的可重用業(yè)務(wù)和數(shù)據(jù)訪問對象。毫無疑問,這樣的對象可以在不同J2EE環(huán)境(Web或EJB)、獨立應(yīng)用程序、測試環(huán)境之間重用。
Spring以一種非侵入式的方式來管理你的代碼,Spring提倡"最少侵入",這也就意味著你可以適當(dāng)?shù)臅r候安裝或卸載Spring ,但這點越來越模糊。
核心概念
| BeanFactory | Spring內(nèi)部使用,創(chuàng)建bean的工廠 |
| ApplicationContext | 外部應(yīng)用程序調(diào)用,也成為spring容器 |
| IoC控制反轉(zhuǎn)Inversion of Control | 開發(fā)者在無需自己new對象,無需關(guān)心對象的創(chuàng)建過程User user = new User(); 手動創(chuàng)建對象User user = context.getBean(user); 容器創(chuàng)建對象 |
| DI依賴注入Dependency Injection | 松耦合方式實現(xiàn)對象直接的依賴 |
| AOP面向切面編程 | 補(bǔ)充java面向?qū)ο蟮牟蛔?/td> |
三大核心組件的關(guān)系
Bean、Context、Core三大核心組件的關(guān)系:
Bean 包裝的是 Object,而 Object 必然有數(shù)據(jù),如何給這些數(shù)據(jù)提供生存環(huán)境就是 Context要解決的問題,對 Context 來說它就是要發(fā)現(xiàn)每個 Bean 之間的關(guān)系,為它們建立這種關(guān)系并且要維護(hù)好這種關(guān)系。所以 Context 就是一個Bean關(guān)系的集合,這個關(guān)系集合又叫 Ioc 容器,一旦建立起這個 Ioc 容器后 Spring 就可以為你工作了。那 Core 組件又有什么用武之地呢?其實Core 就是發(fā)現(xiàn)、建立和維護(hù)每個 Bean 之間的關(guān)系所需要的一些類的工具,從這個角度看來,Core 這個組件叫 Util 更能讓你理解。
把Bean 比作一場演出中的演員的話,那 Context 就是這場演出的舞臺背景,而 Core應(yīng)該就是演出的道具了。只有他們在一起才能具備能演出一場好戲的最基本的條件。當(dāng)然有最基本的條件還不能使這場演出脫穎而出,還要他表演的節(jié)目足夠的精彩,這些節(jié)目就是 Spring 能提供的特色功能了。
主要jar組成
| org.springframework.core | 核心工具包,其他包依賴此包 |
| org.springframework.beans | 核心,包括:配置文件,創(chuàng)建和管理bean等 |
| org.springframework.aop | 面向切面編程,提供AOP的實現(xiàn) |
| org.springframework.context | 提供IoC功能上的擴(kuò)展服務(wù),此外還提供許多企業(yè)級服務(wù)的支持,郵件、任務(wù)調(diào)度、JNDI定位、EJB集成、遠(yuǎn)程訪問、緩存以及多種視圖層框架的支持 |
| org.springframework.web.mvc | 包含SpringMVC應(yīng)用開發(fā)時所需的核心類 |
| org.springframework.transaction | 為JDBC、Hibernate、JDO、JPA提供一致的聲明式和編程式事務(wù)管理 |
| org.springframework.web | 包含Web應(yīng)用開發(fā)時所需支持類 |
| org.springframework.aspects | 提供對AspectJ框架的支持 |
| org.springframework.test | 對junit等測試框架的簡單封裝 |
| org.springframework.asm | 3.0后提供自己獨立的,反編譯 |
| org.springframework.context.support | Context的擴(kuò)展支持,用于mvc方面 |
| org.springframework.expression | Spring表達(dá)式語言 |
| org.springframework.instument | 對服務(wù)器的代理接口 |
| org.springframework.jdbc | 對jdbc的簡單封裝 |
| org.springframework.jms | 為簡化jms api的使用而做的簡單封裝 |
| org.springframework.orm | 整合第三方orm,如hibernate/mybatis |
| org.springframework.web.servlet | 增強(qiáng)servlet |
Spring框架兩大核心:IoC和DI
概念
- IoC(Inversion of Control)簡單來說就是將對象Object的創(chuàng)建的權(quán)力及對象的生命周期的管理過程交由Spring框架來處理,從此在開發(fā)過程中不在需要關(guān)注對象的創(chuàng)建和生命周期的管理,而是在需要的時候由Spring框架提供,這個由Spring框架管理對象創(chuàng)建和生命周期的機(jī)制稱之為控制反轉(zhuǎn)。
- 在創(chuàng)建對象的過程中Spring可以依據(jù)對象的關(guān)系,自動把其它對象注入(無需創(chuàng)建對象,直接拿著使用)進(jìn)來,這個過程稱之為DI(Dependency Injection)依賴注入。
總結(jié)下Spring核心就干了兩件事:
IoC
IOC(Inversion of Control),控制反轉(zhuǎn)。
就是指將對象的創(chuàng)建,對象的存儲(map),對象的管理(依賴查找,依賴注入)交給了spring容器。
DI
DI(Dependency Injection)依賴注入 。
相對于IoC而言,依賴注入(DI)更加準(zhǔn)確地描述了IoC的設(shè)計理念。所謂依賴注入,即組件之間的依賴關(guān)系由容器在應(yīng)用系統(tǒng)運行期來決定,也就是由容器動態(tài)地將某種依賴關(guān)系的目標(biāo)對象實例注入到應(yīng)用系統(tǒng)中的各個關(guān)聯(lián)的組件之中。
IoC的XML方式
創(chuàng)建springboot工程
創(chuàng)建Hello.java
package spring;public class Hello {public void hi() {System.out.println("Hello Spring.");} }創(chuàng)建applicationContext.xml
創(chuàng)建TestIoC.java
package spring;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestIoC {@Testpublic void bean() {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");Hello h1 = new Hello();System.out.println(h1);h1.hi();//根據(jù)id獲取bean//Spring就是一個大工廠(容器)專門生成bean,bean就是對象Hello hello = (Hello)ac.getBean("Hello");System.out.println(hello);hello.hi();} }小結(jié)
這就是spring框架的IoC,控制反轉(zhuǎn)。之前我們自己new出新類。new User();變成由一個初始化的xml配置文件來創(chuàng)建,也就是由spring容器來創(chuàng)建。遍歷xml配置文件,讀取到<bean>,獲取到class屬性的類的全路徑,利用反射創(chuàng)建這個類。
在java范疇中萬物皆O(shè)bject,在Spring中萬物皆Bean。Bean是Spring的核心、基礎(chǔ)、根源。
IoC的注解方式
創(chuàng)建springboot工程
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.tedu</groupId><artifactId>spring</artifactId><version>0.0.1-SNAPSHOT</version><!-- 集中定義依賴版本號 --><properties><junit.version>4.10</junit.version><spring.version>4.1.3.RELEASE</spring.version></properties><dependencies><!-- 單元測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency></dependencies> </project>Hello.java
package spring;import org.springframework.stereotype.Component;@Component//讓spring容器認(rèn)識 public class Hello {public void hi() {System.out.println("Hello Spring.");} }applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"><!-- 包掃描, 用注解的方式,配置bean 會掃描 指定包下,帶@Component注解的類并注入spring容器中,key是類名小寫,value是類的對象--><context:component-scan base-package="cn.tedu" /> </beans>TestIoC.java
package spring;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestIoC {@Testpublic void bean() {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");//根據(jù)id獲取bean,beanname就是類名,首字母變小寫Hello hello = (Hello) ac.getBean("hello");System.out.println(hello);hello.hi();} }DI依賴注入
創(chuàng)建Maven工程
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.tedu</groupId><artifactId>spring</artifactId><version>0.0.1-SNAPSHOT</version><!-- 集中定義依賴版本號 --><properties><junit.version>4.10</junit.version><spring.version>4.1.3.RELEASE</spring.version></properties><dependencies><!-- 單元測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency></dependencies> </project>Dept.java
package spring.pojo; import org.springframework.stereotype.Component; @Component public class Dept {String name = "java開發(fā)部";@Overridepublic String toString() {return "Dept{" +"name='" + name + '\'' +'}';} }User.java
package spring.pojo;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class User {String name = "jack";@Autowired //相當(dāng)于框架完成了:new User().setDept(new Dept());Dept dept;@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", dept=" + dept +'}';} }applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"><!-- 掃描包 --><context:component-scan base-package="cn.tedu.pojo" /> </beans>TestDI.java
package test;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;import spring.pojo.Dept; import spring.pojo.User;public class TestDI {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");Dept d = (Dept)ac.getBean("dept");User u = (User)ac.getBean("user");System.out.println(d);System.out.println(u);System.out.println(u.dept.name);} }小結(jié)
面試:IoC和DI
在平時的java應(yīng)用開發(fā)中,我們要實現(xiàn)某一個功能或者說是完成某個業(yè)務(wù)邏輯時可能需要多個對象來協(xié)作完成,在沒有使用Spring的時候,每個對象在需要使用他的合作對象時,自己均要使用像new object() 這樣的語法來將合作對象創(chuàng)建出來,這個合作對象是由自己主動創(chuàng)建出來的,創(chuàng)建合作對象的主動權(quán)在自己手上,自己需要哪個合作對象,就主動去創(chuàng)建,創(chuàng)建合作對象的主動權(quán)和創(chuàng)建時機(jī)是由自己把控的,而這樣就會使得對象間的耦合度高了,A對象需要使用合作對象B來共同完成一件事,A要使用B,那么A就對B產(chǎn)生了依賴,也就是A和B之間存在一種耦合關(guān)系,并且是緊密耦合在一起,而使用了Spring之后就不一樣了,創(chuàng)建合作對象B的工作是由Spring來做的,Spring創(chuàng)建好B對象,然后存儲到一個容器里面,當(dāng)A對象需要使用B對象時,Spring就從存放對象的那個容器里面取出A要使用的那個B對象,然后交給A對象使用,至于Spring是如何創(chuàng)建那個對象,以及什么時候創(chuàng)建好對象的,A對象不需要關(guān)心這些細(xì)節(jié)問題(你是什么時候生的,怎么生出來的我可不關(guān)心,能幫我干活就行),A得到Spring給我們的對象之后,兩個人一起協(xié)作完成要完成的工作即可。
所以控制反轉(zhuǎn)IoC(Inversion of Control)是說創(chuàng)建對象的控制權(quán)進(jìn)行轉(zhuǎn)移,以前創(chuàng)建對象的主動權(quán)和創(chuàng)建時機(jī)是由自己把控的,而現(xiàn)在這種權(quán)力轉(zhuǎn)移到第三方,比如轉(zhuǎn)移交給了IoC容器,它就是一個專門用來創(chuàng)建對象的工廠,你要什么對象,它就給你什么對象,有了 IoC容器,依賴關(guān)系就變了,原先的依賴關(guān)系就沒了,它們都依賴IoC容器了,通過IoC容器來建立它們之間的關(guān)系。
DI(依賴注入)其實就是IOC的另外一種說法,DI是由Martin Fowler 在2004年初的一篇論文中首次提出的。他總結(jié):控制的什么被反轉(zhuǎn)了?就是:獲得依賴對象的方式反轉(zhuǎn)了。
IoC是設(shè)計思想,IoC有三個核心:BeanFactory、反射、DI。BeanFactory利用反射實現(xiàn)對象的創(chuàng)建,DI實現(xiàn)對象關(guān)系管理。
自動裝配
利用注解方式,我們只需要寫@Autowired注解,底層就會去容器中找對應(yīng)的對象,如果有獲取到,反射調(diào)用其對應(yīng)的set方法,設(shè)置。而這個調(diào)用過程都是自動,我們沒有手工去寫set方法。所以這個過程也稱為自動裝配。
AOP面向切面編程
概念
Spring核心特征中除了IoC控制反轉(zhuǎn)、DI依賴注入,還有一個核心就是強(qiáng)大的面向切面編程AOP(Aspect Oriented Programming)的實現(xiàn)。 AOP 是實現(xiàn)程序功能統(tǒng)一維護(hù)的一種技術(shù)。它把 眾多模塊 涉及到的同一類問題進(jìn)行了統(tǒng)一處理。利用 AOP 可以對業(yè)務(wù)邏輯的各個部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合性降低,提高程序的可重用性,同時大大提高了開發(fā)效率。AspectJ
AspectJ 作為 Java 中流行的 AOP(aspect-oriented programming) 編程擴(kuò)展框架,有一些自己的語法和特點,Spring框架底層也是采用的 AspectJ來實現(xiàn)的面向切面編程。他成熟穩(wěn)定,輸入輸出都是 .class 文件,直接處理字節(jié)碼文件,這個過程并不簡單,特別是 針對于字節(jié)碼的格式和各種指令規(guī)則,如果處理出錯,就會導(dǎo)致程序編譯或者運行過程中出現(xiàn)問題。他使用起來非常簡單,并且它的功能非常強(qiáng)大,我們完全不需要理解任何 Java 字節(jié)碼相關(guān)的知識,就可以在很多情況下對字節(jié)碼進(jìn)行操控。AOP的三要素
切面(Aspect) 類是對物體特征的抽象,切面就是對同一類問題(橫切關(guān)注點)的抽象
通知(Advice) 來指定具體做什么事情。如方法執(zhí)行前做什么,方法執(zhí)行后做什么,拋出異常做什么,從而實現(xiàn)對象行為(方法)的增強(qiáng)
切點(PointCut) 配置切點表達(dá)式(expression)來指定在哪些類的哪些方法上織入(ware)橫切一些邏輯
連接點(JoinPoint) JPoint 是一個程序的關(guān)鍵執(zhí)行點,也是我們關(guān)注的重點。它就是指被切點攔截到的點然后執(zhí)行一些通知
通知
Spring框架實現(xiàn)了AOP面向切面,其引入了第三方AspectJ框架來具體實現(xiàn)。
AspectJ提供了五種切入方式,術(shù)語稱為通知advice。
具體五種為:
異常通知特殊,這里暫不討論。
可以看到,分別在業(yè)務(wù)方法(Business Method)的執(zhí)行前后進(jìn)行攔截,執(zhí)行指定的代碼。
多切面執(zhí)行順序
下面是 兩個切面 各通知的執(zhí)行順序:
使用步驟
1, 加入jar包
<dependencies><!--添加aop依賴包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies>2, 創(chuàng)建切面,提供通知和切點
3, 測試
創(chuàng)建切面
package cn.tedu;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;import java.util.Arrays;@Component @Aspect//切面:由切點和通知組成 public class AspectD {//切點表達(dá)式: *表示1個 ..表示多個 *依次代表方法返回值,類名,方法名,(..)是參數(shù)列表@Pointcut("execution(* cn.tedu.service.*.*(..))")public void pointcut(){}@Before("pointcut()")//前置通知,在每一個方法開始之前被調(diào)用public void beforeMethod(JoinPoint joinPoint){System.out.println("我是前置通知");}@After("pointcut()")//后置通知,在每一個方法結(jié)束后被調(diào)用public void afterMethod(JoinPoint joinPoint){System.out.println("我是后置通知");}@Around("pointcut()")//環(huán)繞通知,方法執(zhí)行前后都被調(diào)用,必須有返回值public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {long time = System.currentTimeMillis();Object o = joinPoint.proceed();//放行,執(zhí)行目標(biāo)方法time= System.currentTimeMillis()-time;String methodName = joinPoint.getSignature().getName();//方法名System.out.print("我是環(huán)繞通知");System.out.println(methodName+"===耗時:"+time+"===");return o;}}測試
創(chuàng)建啟動類,打開瀏覽器訪問以下程序即可觀察到控制臺的輸出效果
package cn.tedu;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;@RestController @RequestMapping("c") public class ControllerImpl {@RequestMapping("a")public void add(){for (int i = 0; i < 100; i++) {System.out.print("~");}} }總結(jié)
以上是生活随笔為你收集整理的Spring框架从入门到精通的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kafka tool 查看指定group
- 下一篇: web前端 基于html实现花店购物网站