Spring Boot從入門到實戰(zhàn)(核心開發(fā)技術(shù))_第1頁
Spring Boot從入門到實戰(zhàn)(核心開發(fā)技術(shù))_第2頁
Spring Boot從入門到實戰(zhàn)(核心開發(fā)技術(shù))_第3頁
Spring Boot從入門到實戰(zhàn)(核心開發(fā)技術(shù))_第4頁
Spring Boot從入門到實戰(zhàn)(核心開發(fā)技術(shù))_第5頁
已閱讀5頁,還剩38頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

SpringBoot從入門到實戰(zhàn)核心開發(fā)技術(shù)注:因內(nèi)容過長上傳受限制,本文檔只顯示第一篇內(nèi)容,完整版文檔請下載此文檔后留言謝謝。目錄TOC\h\h第1章Spring框架基礎(chǔ)\h1.1Spring簡介\h1.1.1Spring的發(fā)展歷史\h1.1.2Spring的特性\h1.1.3Spring的體系結(jié)構(gòu)\h1.2控制反轉(zhuǎn)\h1.2.1IoC和DI簡介\h1.2.2元數(shù)據(jù)配置\h1.2.3Bean管理\h1.3面向切面編程\h1.3.1代理模式\h1.3.2AOP中的術(shù)語\h1.3.3@AspectJ注解\h1.3.4基于XML配置的AOP\h1.3.5基于@Aspect注解的AOP\h1.4總結(jié)\h第2章SpringMVC基礎(chǔ)\h2.1SpringMVC簡介\h2.1.1SpringMVC的工作流程\h2.1.2DispatcherServlet類\h2.1.3HandlerInterceptor攔截器\h2.2SpringMVC注解\h2.2.1請求注解\h2.2.2參數(shù)注解\h2.2.3異常注解\h2.2.4跨域注解\h2.2.5請求跳轉(zhuǎn)\h2.3總結(jié)\h第3章SpringBoot基礎(chǔ)\h3.1SpringBoot簡介\h3.1.1SpringBoot的特性\h3.1.2快速創(chuàng)建SpringBoot應(yīng)用\h3.1.3SpringBootStarter簡介\h3.2SpringBoot的運行原理\h3.2.1SpringApplication啟動類\h3.2.2@SpringBootApplication注解\h3.3SpringBoot的配置文件\h3.3.1默認配置文件\h3.3.2多環(huán)境配置\h3.3.3配置注解\h3.4測試與部署\h3.4.1測試\h3.4.2打包\h3.5總結(jié)\h第4章SpringBoot之數(shù)據(jù)訪問\h4.1訪問SQL數(shù)據(jù)庫\h4.1.1JdbcTemplate模板類\h4.1.2SpringDataJPA組件\h4.1.3SpringBoot集成MyBatis\h4.2訪問NoSQL數(shù)據(jù)庫\h4.2.1訪問Redis\h4.2.2訪問MongoDB\h4.3Caching緩存\h4.3.1訪問EhCache\h4.3.2訪問Couchbase\h4.4遠程調(diào)用\h4.4.1調(diào)用RestTemplate\h4.4.2調(diào)用WebClient\h4.5總結(jié)\h第5章配置中心與服務(wù)發(fā)現(xiàn)\h5.1配置中心組件\h5.1.1XXL-CONF組件簡介\h5.1.2Apollo組件簡介\h5.1.3SpringCloudConfig組件簡介\h5.2服務(wù)注冊與發(fā)現(xiàn)\h5.2.1Eureka組件簡介\h5.2.2Consul組件簡介\h5.3Nacos組件\h5.3.1Nacos組件簡介\h5.3.2快速搭建Nacos\h5.3.3SpringBoot集成Nacos\h5.3.4SpringCloud集成Nacos\h5.4總結(jié)\h第6章服務(wù)限流與降級\h6.1限流\h6.1.1限流的原理\h6.1.2限流示例\h6.2Hystrix組件\h6.2.1Hystrix組件簡介\h6.2.2Hystrix原理\h6.2.3Hystrix示例\h6.3Sentinel組件\h6.3.1Sentinel組件簡介\h6.3.2Sentinel的原理\h6.3.3快速搭建SentinelDashboard\h6.3.4SpringBoot集成Sentinel\h6.4Nacos集成Sentinel配置\h6.5總結(jié)\h第7章全鏈路追蹤系統(tǒng)\h7.1全鏈路追蹤系統(tǒng)簡介\h7.1.1基本特性\h7.1.2基本概念\h7.2開源的全鏈路追蹤系統(tǒng)\h7.2.1Dapper簡介\h7.2.2Zipkin簡介\h7.2.3Pinpoint簡介\h7.2.4Skywalking簡介\h7.2.5開源的全鏈路追蹤系統(tǒng)比較\h7.3全鏈路追蹤系統(tǒng)實踐\h7.3.1Zipkin實踐\h7.3.2Skywalking實踐\h7.4總結(jié)\h第8章微服務(wù)監(jiān)控管理\h8.1SpringBootActuator組件\h8.1.1Endpoints組件簡介\h8.1.2自定義端點\h8.2Micrometer工具\h8.2.1Micrometer工具簡介\h8.2.2SpringBoot集成\h8.3Prometheus工具\h8.3.1Prometheus工具簡介\h8.3.2快速搭建Prometheus\h8.4Grafana工具\h8.4.1Grafana的安裝\h8.4.2Grafana集成Prometheus\h8.5總結(jié)\h第9章SpringCloud網(wǎng)關(guān)\h9.1API網(wǎng)關(guān)\h9.1.1網(wǎng)關(guān)簡介\h9.1.2網(wǎng)關(guān)示例\h9.2核心配置\h9.2.1RoutePredicate配置\h9.2.2GatewayFilter配置\h9.2.3全局配置\h9.3總結(jié)\h第10章SpringBoot測試與部署\h10.1SpringBoot測試\h10.1.1SpringBoot測試簡介\h10.1.2核心注解\h10.2SpringBoot部署\h10.2.1JAR包部署\h10.2.2Docker部署\h10.3總結(jié)\h第11章SpringBoot微服務(wù)開發(fā)實例\h11.1項目描述\h11.1.1項目需求\h11.1.2需求分析\h11.2數(shù)據(jù)結(jié)構(gòu)\h11.2.1MySQL數(shù)據(jù)結(jié)構(gòu)\h11.2.2Redis數(shù)據(jù)結(jié)構(gòu)\h11.3項目開發(fā)\h11.3.1后臺接口管理項目\h11.3.2促銷活動微服務(wù)項目\h11.3.3網(wǎng)關(guān)項目\h11.3.4項目部署\h11.4總結(jié)\h第12章ReactiveWeb開發(fā)實戰(zhàn)\h12.1Reactive編程\h12.1.1響應(yīng)式宣言\h12.1.2Reactive編程簡介\h12.1.3ReactiveStreams標準\h12.1.4JavaFlowAPI簡介\h12.2SpringWebFlux框架\h12.2.1SpringWebFlux簡介\h12.2.2Mono類\h12.2.3Flux類\h12.2.4SpringWebFlux示例\h12.3SpringWebFlux實戰(zhàn)\h12.4總結(jié)第1章Spring框架基礎(chǔ)回顧筆者這幾年的JavaWeb開發(fā)經(jīng)歷,最初使用Servlet與JSP技術(shù)進行開發(fā),后來使用SSH架構(gòu)進行開發(fā),再后來使用SpringMVC架構(gòu)進行開發(fā),如今使用流行的SpringBoot架構(gòu)進行開發(fā)。在JavaWeb開發(fā)領(lǐng)域,Spring的發(fā)展速度大大超出預期,已經(jīng)成為每個Java編程人員必須掌握的框架。Spring框架以其靈活、簡易、快速等特性迅速搶占了Java企業(yè)級開發(fā)的市場,成為世界上最流行的企業(yè)級開發(fā)架構(gòu)。本章作為全書的開篇,將介紹Spring框架的發(fā)展歷史,以及Spring框架最核心的內(nèi)容——控制反轉(zhuǎn)(InversionofControl,IoC)與面向切面編程(AspectOrientedProgramming,AOP)原理,并給出代碼示例。1.1Spring簡介Spring發(fā)展到今天,已經(jīng)不僅僅指SpringFramework,而且還代表Spring的整個家族。Spring可以為Java企業(yè)級開發(fā)提供強有力的支持,其龐大而活躍的社區(qū)及持續(xù)開源的代碼貢獻,為各大公司的應(yīng)用服務(wù)提供了基礎(chǔ)支撐。1.1.1Spring的發(fā)展歷史世界上有兩種天才,一種是專注于本專業(yè)并做出突出貢獻的人,另一種是不但在本專業(yè)中有所建樹,而且在專業(yè)之外還有非常高的造詣。例如,愛因斯坦屬于前者,而達·芬奇則屬于后者。在Java領(lǐng)域也有這么一位天才,他就是悉尼大學的音樂學博士,而且他還是SpringFramework的創(chuàng)始人,他的名字叫RodJohnson。2002年RodJohnson編寫了Expertone-on-oneJ2EEDevelopmentwithoutEJB一書,書中批評了J2EE架構(gòu)的臃腫和低效,甚至提出,絕大多數(shù)的J2EE工程根本不需要EJB。這在當時引起了軒然大波。為了支持自己的理論,他編寫了超過30000行的基礎(chǔ)結(jié)構(gòu)代碼,代碼中的根包命名為erface21,當時人們稱這套開源框架為interface21,這就是Spring框架的前身。從官網(wǎng)的描述中可以看到,Spring并不是J2EE的競爭對手,而是J2EE規(guī)范的補充及基于規(guī)范的實現(xiàn)。Spring的版本發(fā)布歷史如下:2004年3月,Spring1.0發(fā)布,支持以XML文件的方式配置Bean。2006年10月,Spring2.0發(fā)布,支持JDK5,采用注解方式注入Bean。2007年11月,更名為SpringSource,同時發(fā)布了Spring2.5,支持JDK6。2009年12月,Spring3.0發(fā)布,開始推薦Java的配置方式。2013年12月,Spring4.0發(fā)布,支持JDK8,全面支持Java的配置方式。2014年4月,SpringBoot1.0.0發(fā)布。2017年9月,Spring5.0發(fā)布,支持JDK9,新增SpringWebFlux特性。在本書的編寫過程中,Spring5.3.x通用版已經(jīng)發(fā)布,SpringBoot也發(fā)布了2.5.0通用版。1.1.2Spring的特性Spring之所以流行并受到廣大Java編程人員的追捧,究其原因是Spring具有以下5個關(guān)鍵特性。1.靈活Spring框架具有靈活、可擴展及集成第三方包的特點,可以方便開發(fā)者構(gòu)建各種應(yīng)用。它以控制反轉(zhuǎn)(IoC)和依賴注入(DI)為核心提供基礎(chǔ)功能。無論是創(chuàng)建一個安全、響應(yīng)式及基于云平臺的微服務(wù),還是創(chuàng)建一個復雜的數(shù)據(jù)流應(yīng)用,Spring都有相應(yīng)的框架。2.多產(chǎn)品化Spring家族有多個產(chǎn)品:SpringMVC、SpringBoot、SpringCloud等。SpringMVC提供了JavaWeb的開發(fā)架構(gòu)。SpringBoot改變了編程方式,結(jié)合應(yīng)用的上下文和自動化配置,可以將其嵌入微服務(wù)開發(fā)中,還可以結(jié)合SpringCloud組件,進行云服務(wù)開發(fā)。3.快速Spring框架可以快速啟動,快速關(guān)閉,快速執(zhí)行。Spring5可以執(zhí)行異步非阻塞應(yīng)用,讓程序更高效。SpringBoot可以讓開發(fā)者更容易搭建一個JavaWeb工程。啟動一個Spring工程的時間可以達到秒級。4.安全Spring代碼貢獻者與專業(yè)的安全人員會對Spring框架進行測試并修補報告的漏洞,第三方依賴包也會被監(jiān)控并定期更新,以幫助開發(fā)者安全地保存數(shù)據(jù)。此外,SpringSecurity框架使開發(fā)者更容易集成標準的安全方案,并為開發(fā)者提供默認的安全解決方案。5.可支持的社區(qū)Spring擁有龐大的、全球化的、積極的開源社區(qū),無論開發(fā)者有什么問題,都可以在社區(qū)中獲得支持。此外,Spring還提供了各種形式的文檔和視頻等資料供開發(fā)者參考。1.1.3Spring的體系結(jié)構(gòu)Spring是為了解決企業(yè)級應(yīng)用程序開發(fā)而創(chuàng)建的。隨著Spring的發(fā)展,Spring家族出現(xiàn)了多個產(chǎn)品線,包括SpringFramework、SpringBoot、SpringCloud、SpringData、SpringIntegration、SpringBatch、SpringSecurity和SpringCloudDataFlow等。本節(jié)主要介紹SpringFramework。如圖1.1所示,SpringFramework是一個分層框架,由多個模塊組成,Spring的這些模塊主要包括核心容器模塊、數(shù)據(jù)訪問和集成模塊、Web模塊、AOP(面向切面編程)模塊、植入(Instrument)模塊、消息傳輸(Messaging)模塊和測試模塊等,這些模塊都構(gòu)建在核心容器模塊之上。圖1.1SpringFramework分層架構(gòu)圖1.核心容器核心容器(CoreContainer)模塊提供了Spring框架的基本功能,分為Core(即spring-core)、Beans(即spring-beans)、Context(即spring-context)和Expression(即spring-expression)4個子模塊。Core和Beans是整個Spring框架的基礎(chǔ)模塊,也是Spring的控制反轉(zhuǎn)與依賴注入的基本實現(xiàn)模塊,Spring的其他模塊依賴Core和Beans這兩個模塊。spring-core:其他模塊的核心,包含Spring框架的核心工具類,Spring的其他模塊都要使用該包里的類。spring-beans:核心模塊,定義對Bean的支持,負責訪問配置文件,以及創(chuàng)建和管理Bean,支持依賴注入和控制反轉(zhuǎn)的相關(guān)操作。該模塊有幾個核心接口:BeanFactory接口、BeanDefinition接口和BeanPostProcessor接口。BeanFactory接口是工廠模式的具體實現(xiàn),開發(fā)者無須自己編程去實現(xiàn)單例模式,它允許開發(fā)者把依賴關(guān)系的配置和描述從程序邏輯中解耦;BeanDefinition接口是對Bean的描述;BeanPostProcessor接口可以動態(tài)修改Bean的屬性。spring-context:上下文模塊,是Spring運行時容器,提供對Spring的上下文支持,并提供一個框架式的對象訪問方式,類似于一個JNDI注冊表。Application-Context接口是該模塊的關(guān)鍵,通過它可以方便、快捷地取出依賴注入的Bean。ApplicationContext接口的實現(xiàn)類很多,如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext和AnnotationConfigApplicationContext等。為了整合第三方庫到Spring應(yīng)用程序的上下文中,Spring還提供了spring-context-support模塊。該模塊提供了對高速緩存(EhCache和JCache)和調(diào)度(CommonJ和Quartz)的支持。spring-expression:Spring的表達式語言,用以幫助Spring在運行時查詢和操作對象。同時,該表達式還支持設(shè)置和獲取對象的屬性值及方法的調(diào)用,以及訪問數(shù)組、集合和索引器的內(nèi)容并支持查詢和操作運行時對象,是對JSP2.1規(guī)范中規(guī)定的統(tǒng)一表達式語言(UnifiedEL,UEL)的擴展。2.SpringAOP模塊AOP模塊是Spring框架的另一個核心模塊,主要由AOP(即spring-aop)、Aspects(即spring-aspects)和Instrument(即spring-instrument)3個子模塊組成,提供面向切面的編程架構(gòu)。spring-aop:AOP的主要實現(xiàn)模塊。以JVM的動態(tài)代理技術(shù)為基礎(chǔ),設(shè)計出一系列面向切面編程的實現(xiàn),如前置通知、后置通知、環(huán)繞通知、返回通知和異常通知等。同時,以Pointcut接口來匹配切入點,可以使用現(xiàn)有的切入點來指定橫切面,也可以擴展相關(guān)方法,再根據(jù)需求進行切入。spring-aspects:集成自AspectJ框架,主要是為了給SpringAOP提供多種AOP實現(xiàn)方法。spring-instrument:基于JavaSE中的java.lang.instrument進行設(shè)計,可以看作AOP的一個支援模塊。該模塊的主要作用是在JVM啟用時生成一個agent代理類,開發(fā)者通過這個agent代理類在運行時修改類的字節(jié),從而改變一個類的功能,實現(xiàn)AOP的功能。例如,spring-instrument-tomcat模塊包含支持Tomcat的植入代理。3.數(shù)據(jù)訪問和集成模塊數(shù)據(jù)訪問和集成模塊是由JDBC(即spring-jdbc)、ORM(即spring-orm)、OXM(即spring-oxm)、JMS(即spring-jms)和Transactions(即spring-transactions)5個子模塊組成的。spring-jdbc:主要提供JDBC的模板方法、關(guān)系型數(shù)據(jù)庫的對象化方式、SimpleJdbc方式及事務(wù)管理來簡化JDBC編程,它實現(xiàn)的類是JdbcTemplate、SimpleJdbcTemplate及NamedParameterJdbcTemplate。通過JdbcTemplate,消除了不必要的和煩瑣的JDBC編碼。spring-orm:ORM框架支持模塊,主要集成Hibernate、JavaPersistenceAPI(JPA)和JavaDataObjects(JDO),用于資源管理、數(shù)據(jù)訪問對象(DAO)的實現(xiàn)和事務(wù)處理。spring-oxm:主要提供一個抽象層以支撐OXM(ObjecttoXMLMapping,提供一個支持對象或XML映射實現(xiàn)的抽象層,將Java對象映射成XML數(shù)據(jù),或者將XML數(shù)據(jù)映射成Java對象),如JAXB、Castor、XMLBeans、JiBX和XStream等。spring-jms:發(fā)送和接收信息的模塊,自Spring4.1以后,它還提供對spring-messaging模塊的支持。spring-transactions:事務(wù)控制實現(xiàn)模塊。Spring框架對事務(wù)做了很好的封裝,通過對該框架的AOP進行配置,可以將事務(wù)靈活地配置在任何一層,用以實現(xiàn)特殊接口和所有POJO(普通Java對象)的類編程和聲明式事務(wù)管理。4.SpringWeb模塊Web模塊建立在應(yīng)用程序的上下文模塊之上,為基于Web的應(yīng)用程序提供上下文。該模塊主要由Web(即spring-web)、WebMVC(即spring-webmvc)、WebSocket(即spring-websocket)和WebFlux(即spring-webflux)4個子模塊組成。spring-web:提供最基礎(chǔ)的Web支持(如文件上傳功能),以及初始化一個面向Web的應(yīng)用程序上下文的IoC容器,同時也包含一些與Web相關(guān)的支持。spring-webmvc:一個Web-Servlet模塊,實現(xiàn)SpringMVC(Model-View-Controller)的Web應(yīng)用。Spring的MVC框架讓領(lǐng)域模型代碼和Web表單之間能清晰地分離,并能與SpringFramework的其他功能集成。其中DispatchServlet是核心類,它完成對請求的處理與返回。spring-websocket:基于WebSocket協(xié)議的Web實現(xiàn)。spring-webflux:基于Reactor實現(xiàn)異步非阻塞的Web框架。5.Messaging模塊Messaging(即spring-messaging)模塊是從Spring4開始新加入的,它的主要功能是為Spring框架集成一些基礎(chǔ)的報文傳送功能。6.Test模塊Test(即spring-test)模塊主要為應(yīng)用測試提供支持,它集成了JUnit框架,可以對Spring組件進行單元測試和集成測試。1.2控制反轉(zhuǎn)在Spring框架中,Bean的實例化和組裝都是由IoC容器通過配置元數(shù)據(jù)完成的。本節(jié)主要介紹SpringIoC容器的理念,以及spring-beans模塊和spring-context模塊中的幾個關(guān)鍵接口類。1.2.1IoC和DI簡介IoC(InversionofControl)是“控制反轉(zhuǎn)”的意思。如何理解“控制反轉(zhuǎn)”這個詞呢?首先我們需要知道反轉(zhuǎn)的是什么,是由誰來控制。在Spring框架沒有出現(xiàn)之前,在Java面向?qū)ο蟮拈_發(fā)中,開發(fā)者通過new關(guān)鍵字完成對Object的創(chuàng)建。Spring框架誕生后,是通過Spring容器來管理對象的,因此Object的創(chuàng)建是通過Spring來完成的。最終得出結(jié)論:控制反轉(zhuǎn)指的是由開發(fā)者來控制創(chuàng)建對象變成了由Spring容器來控制創(chuàng)建對象,創(chuàng)建對象和銷毀對象的過程都由Spring來控制。以Spring框架為開發(fā)基礎(chǔ)的應(yīng)用盡量不要自己創(chuàng)建對象,應(yīng)全部交由Spring容器管理。DI(DependencyInjection)稱為依賴注入。在Java程序中,類與類之間的耦合非常頻繁,如ClassA需要依賴ClassB的對象b。而基于Spring框架的開發(fā),在ClassA中不需要顯式地使用new關(guān)鍵字新建一個對象b,只需在對象b的聲明之上加一行注解@Autowired,這樣在ClassA用到b時,Spring容器會主動完成對象b的創(chuàng)建和注入。這就是ClassA依賴Spring容器的注入。通過上面的解釋,我們可以發(fā)現(xiàn)IoC和DI其實是同一概念從不同角度的解釋。在Spring框架中,org.springframework.context.ApplicationContext接口代表SpringIoC容器,它負責實例化、配置和組裝Beans。容器通過讀取元數(shù)據(jù)的配置來獲取對象的實例化,以及配置和組裝的描述信息。元數(shù)據(jù)可以用XML、Java注解或Java配置代碼表示應(yīng)用的對象及這些對象之間的內(nèi)部依賴關(guān)系。Spring框架提供了幾個開箱即用的ApplicationContext接口的實現(xiàn)類,如Class-PathXmlApplicationContext、FileSystemXmlApplicationContext和AnnotationConfig-ApplicationContext等。在獨立應(yīng)用程序中,通常創(chuàng)建一個ClassPathXmlApplication-Context或FileSystemXmlApplicationContext實例對象來獲取XML的配置信息。開發(fā)者也可以指示容器使用Java注解或Java配置作為元數(shù)據(jù)格式,通過Annotation-ConfigApplicationContext來獲取Java配置的Bean。1.2.2元數(shù)據(jù)配置1.基于XML的配置Spring框架最早是通過XML配置文件的方式來配置元數(shù)據(jù)的,示例代碼如下:<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="/schema/beans"

xmlns:xsi="/2001/XMLSchema-instance"

xsi:schemaLocation="/schema/beans

/schema/beans/spring-beans.xsd">

<!--定義UserService類-->

<beanid="userService"class="com.spring.boot.UserService">

<!--id屬性-->

<propertyname="id"value="1"/>

<!--name屬性-->

<propertyname="name"value="zhangsan"/>

</bean>

</beans>

在src/main/resources目錄下新建spring.xml文件,內(nèi)容如上面的代碼所示,<bean>和</bean>標簽用來描述Bean的元數(shù)據(jù)信息。在上面的代碼中聲明了一個UserService類,該類有兩個屬性,即id和name,通過<property>和</property>標簽直接進行賦值。UserService實體類的聲明代碼如下://聲明UserService類

publicclassUserService{

privateIntegerid;//用戶ID

privateStringname;//用戶名稱

//getter和setter方法

publicIntegergetId(){

returnid;

}

publicvoidsetId(Integerid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

=name;

}

//打印屬性值

publicvoidgetUser(){

System.out.println("id:"+this.id);

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

}

}

以上代碼聲明了一個UserService類,并實現(xiàn)了屬性id和屬性name的setter和getter方法,通過getUser()方法打印屬性值。編寫測試代碼,展示通過Spring上下文獲取UserService對象,具體代碼如下://測試類

publicclassSpringXmlTest{

publicstaticvoidmain(String[]args){

//通過spring.xml獲取Spring應(yīng)用上下文

ApplicationContextcontext=newClassPathXmlApplication

Context("spring.xml");

UserServiceuserService=context.getBean("userService",

UserService.class);

userService.getUser();//打印結(jié)果

}

}

打印結(jié)果:id:1

name:zhangsan

在上面的示例代碼中,ClassPathXmlApplicationContext可以通過spring.xml文件獲取UserService類的配置元數(shù)據(jù),通過Spring容器的組裝和實例化UserService類,最終正確調(diào)用getUser()方法打印出定義的屬性值。2.基于Java注解的配置從Spring2.5開始,支持以Java注解的方式來配置Bean,如@Scope、@Service、@Component、@Controller、@Repository、@Autowired和@Resource等注解。@Scope注解可以設(shè)置Bean的作用域。Spring容器實例化的對象默認是單例的,如果想要修改作用域,可以通過@Scope注解進行修改。表1.1中列出了@Scope注解使用的一些作用域。表1.1@Scope注釋的作用域request、session、application和websocket作用域只在Web應(yīng)用環(huán)境中使用。在普通的SpringIoC容器里只有singleton和prototype兩種作用域,其他的設(shè)置會拋出異常。下面改造基于XML配置元數(shù)據(jù)的例子,將其改成基于Java注解的方式來注入Bean,具體代碼如下://注解的方式聲明UserService

@Service

publicclassUserService{

privateIntegerid;//用戶ID

privateStringname;//用戶名稱

//getter和setter方法

publicIntegergetId(){

returnid;

}

publicvoidsetId(Integerid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

=name;

}

//屬性值打印

publicvoidgetUser(){

System.out.println("id:"+this.id);

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

}

}

上面的代碼在UserService類中加了一個@Service注解,spring.xml配置文件不再使用。下面增加一個注解類,添加@ComponentScan注解,代碼如下://@ComponentScan注解用來掃描UserService類

@ComponentScan("com.spring.boot")

publicclassSpringAnnotationTest{

}

@ComponentScan注解的值是com.spring.boot,說明Spring容器可以自動掃描這個包路徑下可管理的類,并對該類進行實例化。添加測試類代碼如下:@ComponentScan("com.spring.boot")

publicclassSpringAnnotationTest{

publicstaticvoidmain(String[]args){

//通過注解類獲取應(yīng)用上下文

ApplicationContextcontext=newAnnotationConfigApplication

Context(SpringAnnotationTest.class);

//獲取UserService對象

UserServiceuserService=context.getBean(UserService.class);

userService.setId(1);

userService.setName("zhangsan");

userService.getUser();//調(diào)用方法,打印屬性值

}

}

打印結(jié)果:id:1

name:zhangsan

通過AnnotationConfigApplicationContext類可以獲取被@Service注解的User-Service實例化對象,并正確打印屬性值。通過Java注解的方式同樣完成了實例的初始化,說明XML配置方式可以完全被替換。3.基于Java配置的示例從Spring3.0開始,Spring框架開始支持基于Java的方式來配置元數(shù)據(jù),如@Configuration、@Bean、@Import和@Profile等注解。@Configuration注解一般用來配置類,配置類中可以使用@Bean注解來聲明某個類的初始化操作;@Import注解可以導入由@Configuration注解的配置類;@Profile注解可以根據(jù)不同環(huán)境生成不同的實例。下面改造基于Java注解的案例,給出一個基于Java配置的示例。UserService類去掉@Service注解后,將變成普通的Bean。UserService類的聲明代碼如下://聲明UserService類

publicclassUserService{

privateIntegerid;//用戶ID

privateStringname;//用戶名稱

publicIntegergetId(){

returnid;

}

publicvoidsetId(Integerid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

=name;

}

//屬性值打印

publicvoidgetUser(){

System.out.println("id:"+this.id);

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

}

}

新增配置類,代碼如下://基于@Configuration注解生成UserService對象

@Configuration

publicclassSpringConfigTest{

@Bean

publicUserServiceuserService(){

returnnewUserService();

}

}

SpringConfigTest類由@Configuration注解,表明這個類是個配置類。由@Bean注解的userService()方法返回了UserService類的實例。添加測試類代碼如下:@Configuration

publicclassSpringConfigTest{

@Bean

publicUserServiceuserService(){

returnnewUserService();

}

publicstaticvoidmain(String[]args){

//通過配置類獲取Spring應(yīng)用上下文

ApplicationContextcontext=newAnnotationConfigApplication

Context(SpringConfigTest.class);

UserServiceuserService=context.getBean(UserService.class);

userService.setId(1);

userService.setName("zhangsan");

userService.getUser();//打印屬性值

}

}

打印結(jié)果:id:1

name:zhangsan

從上面的例子看,基于Java配置實例化對象的方式不再需要對spring.xml的依賴?;贘ava注解或Java配置來管理Bean的方式已經(jīng)是當今編程的流行方式。后文介紹SpringBoot時,還會介紹一些新的注解或配置方式。1.2.3Bean管理如圖1.2所示為Bean被Spring容器組裝的簡單過程。首先通過XML配置、注解配置或Java配置等3種方式配置元數(shù)據(jù),然后裝配BeanDefinition屬性,如果有增強設(shè)置,如實現(xiàn)了BeanFactoryPostProcessor或BeanPostProcessor接口,則進行攔截增強處理,最后通過配置的初始化方法完成Bean的實例化。圖1.2Bean的組裝過程spring-beans模塊是Spring容器組裝Bean的核心模塊,它提供了組裝Bean的幾個關(guān)鍵接口,如圖1.2中的BeanDefinition、BeanFactoryPostProcessor、BeanPost-Processor和BeanFactory等。BeanDefinition:該接口繼承自AttributeAccessor和BeanDefinition兩個接口。該接口可以獲取Bean的元數(shù)據(jù)配置信息,也可以改變Bean的屬性。BeanFactoryPostProcessor:該接口為函數(shù)接口,只有一個方法postProcessBean-Factory()。該接口可以通過ConfigurableListableBeanFactory參數(shù)獲取Bean-Definition,然后對Bean的屬性進行修改,如把Bean的Scope從singleton改為prototype等。BeanPostProcessor:該接口有兩個方法,即postProcessBeforeInitialization()和postProcessAfterInitialization(),分別用于在Bean實例化之前和實例化之后進行額外的操作。BeanPostProcessor接口與BeanFactoryPostProcessor接口的區(qū)別在于,BeanFactoryPostProcessor接口是在Bean實例化之前進行修改。本節(jié)將通過兩個簡單的例子,展現(xiàn)BeanFactoryPostProcessor和BeanPostProcessor接口的擴展能力。首先來看一個BeanFactoryPostProcessor接口擴展的例子。BeanFactory-PostProcessor接口方法的輸入?yún)?shù)是ConfigurableListableBeanFactory,使用該參數(shù)可以獲取相關(guān)Bean的定義信息。示例代碼如下:@Component

publicclassBeanFactoryPostProcessorImplimplementsBeanFactory

PostProcessor{

@Override

publicvoidpostProcessBeanFactory(ConfigurableListableBean

FactorybeanFactory)throwsBeansException{

//獲取UserService的BeanDefinition

BeanDefinitionbeanDefinition=beanFactory.getBeanDefinition

("userService");

//修改Scope屬性

beanDefinition.setScope("prototype");

System.out.println(beanDefinition.getScope());

}

}

打印結(jié)果:prototype

通過打印結(jié)果可以看到,在UserService實例化之前修改了該類的作用域,將其從singleton改為了prototype。對于BeanPostProcessor接口的擴展,可以在Spring容器實例化Bean之后或者執(zhí)行Bean的初始化方法之前添加一些自己的處理邏輯。示例代碼如下:@Component

publicclassBeanPostProcessorImplimplementsBeanPostProcessor{

//在實例化之前操作

@Override

publicObjectpostProcessBeforeInitialization(Objectbean,String

beanName)throwsBeansException{

//判斷Bean的類型

if(beaninstanceofUserService){

System.out.println("postProcessBeforeInitializationbean:

"+beanName);

}

returnbean;

}

//在實例化之后操作

@Override

publicObjectpostProcessAfterInitialization(Objectbean,String

beanName)throwsBeansException{

//判斷Bean的類型

if(beaninstanceofUserService){

System.out.println("postProcessAfterInitializationbean:"

+beanName);

}

returnbean;

}

}

打印結(jié)果:postProcessBeforeInitializationbean:userService

postProcessAfterInitializationbean:userService

從打印結(jié)果中可以看到,在UserService實例化之前和之后都打印了日志,因此通過BeanPostProcessor可以做一些增強邏輯。1.3面向切面編程AOP(AspectOrientedProgramming)與OOP(ObjectOrientedProgramming,面向?qū)ο缶幊蹋┫噍o相成。AOP提供了與OOP不同的抽象軟件結(jié)構(gòu)的視角。在OOP中,我們以類(Class)作為基本單元,而在AOP中則以切面(Aspect)作為基本單元。AOP是一種增強的編程方式,可以解耦一些非業(yè)務(wù)邏輯,如聲明式事務(wù)管理、日志管理或異常處理等。從底層原理來講,AOP實際上是基于Java的代理模式實現(xiàn)的。本節(jié)首先介紹代理模式的定義,然后介紹AOP編程概念,最后使用@Aspect注解實現(xiàn)面向切面編程。1.3.1代理模式代理模式是經(jīng)典的設(shè)計模式之一,目的是為了擴展和增強類或接口。代理模式通??梢苑譃殪o態(tài)代理模式和動態(tài)代理模式。1.靜態(tài)代理模式靜態(tài)代理模式的實現(xiàn)比較簡單,主要的實現(xiàn)原理是:代理類與被代理類同時實現(xiàn)一個主題接口,代理類持有被代理類的引用。(1)新建一個公共接口UserInterface,代碼如下://聲明UserInterface接口

publicinterfaceUserInterface{

//聲明方法

publicabstractvoidgetUser();

}

(2)定義真實執(zhí)行類RealUser并實現(xiàn)公共接口UserInterface,代碼如下://聲明RealUser類,實現(xiàn)UserInterface接口

publicclassRealUserimplementsUserInterface{

@Override

publicvoidgetUser(){

//新建UserService對象

System.out.println("真實用戶角色執(zhí)行!");

UserServiceuserService=newUserService();

userService.setId(1);

userService.setName("zhangsan");

userService.getUser();

}

}

(3)定義代理類UserProxy實現(xiàn)公共接口UserInterface,并持有被代理類的實例。在執(zhí)行時,調(diào)用被代理類(RealUser)實例的getUser()方法。代碼如下://聲明UserProxy代理類,并實現(xiàn)UserInterface接口

publicclassUserProxyimplementsUserInterface{

privateUserInterfaceuserInterface;

//構(gòu)造方法傳入UserInterface類型參數(shù)

publicUserProxy(UserInterfaceuserInterface){

this.userInterface=userInterface;

}

//實現(xiàn)getUser()方法,在執(zhí)行方法前后進行額外操作

@Override

publicvoidgetUser(){

doBefore();

userInterface.getUser();

doAfter();

}

//真實方法執(zhí)行前操作

privatevoiddoBefore(){

System.out.println("代理類開始執(zhí)行");

}

//真實方法執(zhí)行后操作

privatevoiddoAfter(){

System.out.println("代理類結(jié)束執(zhí)行");

}

}

(4)編寫測試代碼,具體如下:publicclassSpringProxyTest{

publicstaticvoidmain(String[]args){

UserInterfacerealUser=newRealUser();

//傳入真實對象RealUser

UserProxyuserProxy=newUserProxy(realUser);

userProxy.getUser();

}

}

運行結(jié)果如下:代理類開始執(zhí)行

真實用戶角色執(zhí)行!

id:1

name:zhangsan

代理類結(jié)束執(zhí)行

從打印結(jié)果可以看到,代理類實際上是調(diào)用了被代理類的方法。2.動態(tài)代理顧名思義,動態(tài)代理是指在程序運行時動態(tài)地創(chuàng)建代理類。動態(tài)代理的使用方式主要分為兩種:一種是基于接口的代理,另一種則是基于類的代理?;诮涌诘拇矸绞绞侵竿ㄟ^JDK自帶的反射類來生成動態(tài)代理類;基于類的代理方式則是指通過字節(jié)碼處理來實現(xiàn)類代理,如CGLIB和Javassist等。首先我們來看一個基于JDK反射生成代理類的例子。(1)定義一個公共接口UserServiceInterface,代碼如下:publicinterfaceUserServiceInterface{

publicvoidgetUser();

}

(2)定義真實用戶角色類UserServiceImpl并實現(xiàn)公共接口UserServiceInterface,代碼如下:publicclassUserServiceImplimplementsUserServiceInterface{

@Override

publicvoidgetUser(){

System.out.println("zhangsan");//實現(xiàn)getUser()方法

}

}

(3)定義代理類UserServiceProxy,實現(xiàn)InvocationHandler接口,并重寫invoke()方法,代碼如下://定義實現(xiàn)InvocationHandler接口的代理類UserServiceProxy

publicclassUserServiceProxyimplementsInvocationHandler{

privateObjecttarget;

//構(gòu)造方法

publicUserServiceProxy(Objecttarget){

this.target=target;

}

//通過Proxy動態(tài)生成代理類對象

public<T>TgetProxy(){

return(T)Proxy.newProxyInstance(target.getClass().get

ClassLoader(),target.getClass().getInterfaces(),this);

}

//動態(tài)執(zhí)行方法

@Override

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)

throwsThrowable{

System.out.println("JDKbefore");

method.invoke(target,args);

System.out.println("JDKafter");

returnnull;

}

}

(4)編寫測試代碼:publicclassSpringProxyTest{

publicstaticvoidmain(String[]args){

//通過代理類生成UserServiceInterface接口類型對象

UserServiceInterfaceuserServiceInterface=newUserService

Proxy(newUserServiceImpl()).getProxy();

userServiceInterface.getUser();//調(diào)用getUser()方法

}

}

打印結(jié)果如下:JDKproxybefore

zhangsan

JDKproxyafter

通過上面的代理類的執(zhí)行結(jié)果可以看到,真實用戶角色類被屏蔽了,只需要暴露接口即可執(zhí)行成功。屏蔽內(nèi)部實現(xiàn)的邏輯就是代理模式的特點。上面主要講的是基于JDK反射的例子。下面來看一下CGLIB實現(xiàn)動態(tài)代理的原理。它是通過繼承父類的所有公共方法,然后重寫這些方法,并在重寫方法時對這些方法進行增強處理來實現(xiàn)的。根據(jù)里氏代換原則(LSP),父類出現(xiàn)的地方子類都可以出現(xiàn),因此CGLIB實現(xiàn)的代理類也是可以被正常使用的。CGLIB的基本架構(gòu)如圖1.3所示,代理類繼承自目標類,每次調(diào)用代理類的方法時都會被攔截器攔截,然后在攔截器中調(diào)用真實目標類的方法。圖1.3CGLIB動態(tài)代理實現(xiàn)原理CGLIB實現(xiàn)動態(tài)代理的方式比較簡單,具體如下:(1)直接實現(xiàn)MethodInterceptor攔截器接口,并重寫intercept()方法。代碼如下://繼承MethodInterceptor類并實現(xiàn)intercept()方法

publicclassUserMethodInterceptorimplementsMethodInterceptor{

@Override

publicObjectintercept(Objectobj,Methodmethod,Object[]args,

MethodProxyproxy)throwsThrowable{

System.out.println("Cglibbefore");

proxy.invokeSuper(obj,args);

System.out.println("Cglibafter");

returnnull;

}

}

(2)新建Enhancer類,并設(shè)置父類和攔截器類。代碼如下:publicclassSpringProxyTest{

publicstaticvoidmain(String[]args){

Enhancerenhancer=newEnhancer();

enhancer.setSuperclass(UserServiceImpl.class);//設(shè)置父類

//設(shè)置攔截器

enhancer.setCallback(newUserMethodInterceptor());

UserServiceImpluserServiceImpl=(UserServiceImpl)enhancer.

create();//創(chuàng)建對象

userServiceImpl.getUser();//調(diào)用getUser方法

}

}

打印結(jié)果如下:Cglibbefore

zhangsan

Cglibafter

JDK實現(xiàn)動態(tài)代理是基于接口,其中,目標類與代理類都繼承自同一個接口;而CGLIB實現(xiàn)動態(tài)代理是繼承目標類并重寫目標類的方法。在項目開發(fā)過程中,可根據(jù)實際情況進行選擇。1.3.2AOP中的術(shù)語SpringAOP就是負責實現(xiàn)切面編程的框架,它能將切面所定義的橫切邏輯織入切面所指定的連接點中。AOP是一種面向切面的編程,有很多獨有的概念,如切面、連接點和通知等,它們組合起來才能完成一個完整的切面邏輯。因此,AOP的工作重心在于如何將增強織入目標對象的連接點上。1.切面切面(Aspect)通常由Pointcut(切點)和Advice(通知)組合而成。通常是定義一個類,并在類中定義Pointcut和Advice。定義的Pointcut用來匹配Joinpoint(連接點),也就是對那些需要被攔截的方法進行定義。定義的Advice用來對被攔截的方法進行增強處理。在SpringAOP中,切面定義可以基于XML配置定義,也可以用@Aspect注解定義。我們可以簡單地認為,使用@Aspect注解的類就是一個切面類。2.連接點連接點是程序執(zhí)行過程中的一個明確的點,如方法的執(zhí)行或者異常處理。在SpringAOP中,一個連接點一般代表一個方法的執(zhí)行。3.通知通知是切面在特定的連接點上執(zhí)行的特殊邏輯。通知可以分為方法執(zhí)行前(Before)通知、方法執(zhí)行后(After)通知和環(huán)繞(Around)通知等。包括SpringAOP在內(nèi)的許多AOP框架通常會使用攔截器來增強邏輯處理能力,圍繞著連接點維護一個攔截器鏈。SpringAOP的Advice類型如表1.2所示。表1.2Advice類型4.切點切點是一種連接點的聲明。通知是由切點表達式連接并匹配上切點后再執(zhí)行的處理邏輯。切點用來匹配特定連接點的表達式,增強處理將會與切點表達式產(chǎn)生關(guān)聯(lián),并運行在匹配到的連接點上。通過切點表達式匹配連接點是AOP的核心思想。Spring默認使用AspectJ的切點表達式。5.引入SpringAOP可以引入一些新的接口來增強類的處理能力。例如,可以使用引入(Introduction)讓一個Bean實現(xiàn)IsModified接口,從而實現(xiàn)一個簡單的緩存功能。6.目標類目標類(TargetClass)是指被切面增強的類。被一個或多個切面增強的對象也叫作增強對象。SpringAOP采用運行時代理(RuntimeProxies),目標對象就是代理對象。7.AOP代理Spring框架中的AOP代理(AOPProxy)指的是JDK動態(tài)代理或者CGLIB動態(tài)代理。為了實現(xiàn)切面功能,目標對象會被AOP框架創(chuàng)建出來。在Spring框架中,AOP代理的創(chuàng)建方式包括兩種:如果有接口,則使用基于接口的JDK動態(tài)代理,否則使用基于類的CGLIB動態(tài)代理。也可以在XML中通過設(shè)置proxy-target-class屬性來完全使用CGLIB動態(tài)代理。8.織入在編譯期、加載期和運行期都可以將增強織入(Weaving)目標對象中,但SpringAOP一般是在運行期將其織入目標對象中。織入可以將一個或多個切面與類或?qū)ο筮B接在一起,然后創(chuàng)建一個被增強的對象。1.3.3@AspectJ注解在spring-aspects模塊中引入了AspectJ工程。@AspectJ可以通過注解聲明切面。為了能夠使用@AspectJ注解,必須要開啟Spring的配置支持。@AspectJ注解支持以XML的方式進行切面聲明配置,如<aop:aspectj-autoproxy/>標簽配置,也可以通過Java配置的方式進行切面聲明配置。@EnableAspectJAutoProxy注解用于開啟AOP代理自動配置。AspectJ的重要注解如表1.3所示。表1.3AspectJ的重要注解@Pointcut切點注解是匹配一個執(zhí)行表達式。表達式類型如表1.4所示。表1.4@Pointcut表達式類型@Pointcut切點表達式可以組合使用&&、||或!三種運算符。示例代碼如下:@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation()

&&args(account,..)")

@Around通知注解的方法可以傳入ProceedingJoinPoint參數(shù),ProceedingJoinPoint類實例可以獲取切點方法的相關(guān)參數(shù)及實例等。1.3.4基于XML配置的AOP下面的例子是基于XML方式配置的切面。(1)定義一個類,在類中定義一些切點,代碼如下://聲明切面類

publicclassAspectTest{

//方法執(zhí)行前操作

publicvoidbefore(){

System.out.println("before");

}

//方法執(zhí)行后操作

publicvoidafter(){

System.out.println("after");

}

//方法環(huán)繞操作

publicvoidaround(){

System.out.println("around");

}

}

(2)定義目標對象,代碼如下://定義目標類

publicclassUserService{

privateIntegerid;

privateStringname;

publicIntegergetId(){

returnid;

}

publicvoidsetId(Integerid){

this.id=id;

}

publicStringgetName(){

returnname;

}

publicvoidsetName(Stringname){

=name;

}

//執(zhí)行方法

publicvoidgetUser(){

System.out.println("id:"+this.id);

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

}

}

(3)基于XML方式配置切面,代碼如下:<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="/schema/beans"

xmlns:xsi="/2001/XMLSchema-instance"

xmlns:aop="/schema/aop"

xsi:schemaLocation="/schema/beans

/schema/beans/spring-beans.xsd

/schema/aop

/schema/aop/spring-aop.xsd">

<aop:aspectj-autoproxy/>

<beanid="aspectTest"class="com.spring.boot.AspectTest"/>

<beanid="userService"class="com.spring.boot.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論