(系列5)JAVA框架

框架

Spring IoC?

IoC

IoC 控制反轉(zhuǎn),把對象創(chuàng)建、依賴反轉(zhuǎn)給容器實(shí)現(xiàn),需要?jiǎng)?chuàng)建一個(gè)容器和一種描述讓容器知道對象間的依賴關(guān)系,Spring 通過 IoC 容器管理對象及其依賴關(guān)系。IoC 的主要實(shí)現(xiàn)方式是 DI,對象不是從容器中查找依賴的類,而是容器實(shí)例化對象時(shí)主動(dòng)為它注入依賴的類。

基于 XML 的 IoC 初始化

當(dāng)創(chuàng)建 ClassPathXmlApplicationContext 時(shí),調(diào)用父類 AbstractApplicationContext 的 refresh 方法啟動(dòng)整個(gè) IoC 容器對 Bean 定義的載入過程,在創(chuàng)建 IoC 容器前如果已有容器存在,需要銷毀,保證使用的是新創(chuàng)建的容器。

容器創(chuàng)建后通過 loadBeanDefinitions 方法加載 Bean 配置資源,首先解析配置文件路徑,讀取配置文件內(nèi)容,然后通過 XML 解析器將配置信息轉(zhuǎn)換成文檔對象,之后按照 Bean 的定義規(guī)則解析文檔對象。

IoC 容器中注冊的 Bean 信息存放在一個(gè) HashMap 中,key 是字符串,值是 BeanDefinition。當(dāng)配置信息中的 Bean 被解析且被注冊到 IoC 容器后,初始化就算完成了。


DI

實(shí)現(xiàn)

  • 構(gòu)造方法注入

    IoC 容器會(huì)檢查對象的構(gòu)造方法,取得它的依賴對象列表,當(dāng)對象實(shí)例化完成時(shí)依賴的屬性也會(huì)成功注入,可以直接使用。缺點(diǎn)是當(dāng)依賴對象較多時(shí),可能需要多個(gè)構(gòu)造方法。

  • setter 方法注入

    只需要為依賴對象的屬性添加 setter 方法,在描述性上要比構(gòu)造方法注入強(qiáng),缺點(diǎn)是無法在對象構(gòu)造完成后就進(jìn)入就緒狀態(tài)。IoC 容器會(huì)先實(shí)例化 Bean 對象,然后通過反射調(diào)用 setter 方法注入屬性。

  • 注解注入

    @Autowired:自動(dòng)按類型注入,如果有多個(gè)匹配則按照指定 Bean 的 id 查找,需要搭配 @Qualifier。

    @Resource :按照 Bean 的 id 注入,如果找不到則會(huì)按類型注入。

    @Value :用于注入基本數(shù)據(jù)類型和 String。


Bean

生命周期

在 IoC 容器的初始化時(shí)會(huì)對 Bean 定義完成資源定位,加載讀取配置并解析,最后將解析的 Bean 信息放在一個(gè) HashMap 集合中。當(dāng) IoC 容器初始化后,會(huì)創(chuàng)建 Bean 實(shí)例并完成依賴注入,注入對象依賴的各種屬性值,在初始化時(shí)可以指定自定義的初始化方法。經(jīng)過一系列初始化操作后 Bean 達(dá)到可用狀態(tài),當(dāng)使用完成后會(huì)調(diào)用 destroy 方法進(jìn)行銷毀,此時(shí)也可以指定自定義的銷毀方法,最終 Bean 被銷毀且從容器中移除。

通過配置 bean 標(biāo)簽或注解中的 init-Method 和 destory-Method 屬性指定自定義初始化和銷毀方法。


作用域

通過 scope 屬性指定作用域。

范圍 作用域 備注
所有 Spring 應(yīng)用 singleton 默認(rèn)作用域,每個(gè)容器中只有一個(gè)唯一的 Bean 實(shí)例。
prototype 每次 Bean 請求都會(huì)創(chuàng)建一個(gè)新的實(shí)例。
Spring Web 應(yīng)用 request 為每個(gè)請求創(chuàng)建一個(gè)新的實(shí)例。
session 為每個(gè)會(huì)話創(chuàng)建一個(gè)新的實(shí)例。
global session 為全局 session 創(chuàng)建一個(gè)新的實(shí)例。

創(chuàng)建

  • XML

    默認(rèn)無參構(gòu)造方法,只需指明 bean 標(biāo)簽中的 id 和 class 屬性,如果沒有無參構(gòu)造方法會(huì)報(bào)錯(cuò)。

    靜態(tài)工廠方法,通過 bean 標(biāo)簽的 class 屬性指明工廠,factory-method 屬性指明方法。

    實(shí)例工廠方法,通過 bean 標(biāo)簽的 factory-bean 屬性指明工廠,factory-method 屬性指明方法。

  • 注解

    @Component 把當(dāng)前類對象存入 Spring 容器,相當(dāng)于在 xml 中配置一個(gè) bean 標(biāo)簽。value 屬性指定 bean 的 id,默認(rèn)使用當(dāng)前類首字母小寫的類名。

    @Controller@Service,@Repository 都是 @Component 的衍生注解,作用及屬性都一模一樣,只是提供了更明確的語義,@Controller 用于表現(xiàn)層,@Service用于業(yè)務(wù)層,@Repository用于持久層。

    如果想注入第三方類又沒有源碼,就沒法使用 @Component,需要用 @Bean。被 @Bean 注解的方法返回值是一個(gè)對象,這個(gè)對象由 Spring 的 IoC 容器管理,name 屬性用于給對象指定一個(gè)名稱。


BeanFactory、FactoryBean 和 ApplicationContext 的區(qū)別

BeanFactory 是一個(gè) Bean 工廠,使用簡單工廠模式,是 Spring IoC 容器頂級接口,作用是管理 Bean,包括實(shí)例化、定位、配置對象及維護(hù)對象間的依賴。BeanFactory 屬于延遲加載,適合多例模式。

FactoryBean 是一個(gè)工廠 Bean,使用工廠方法模式,作用是生產(chǎn)其他 Bean 實(shí)例,可以通過實(shí)現(xiàn)該接口來自定義實(shí)例 Bean 的邏輯。如果一個(gè) Bean 實(shí)現(xiàn)了這個(gè)接口,那么它就是創(chuàng)建對象的工廠 Bean,而不是 Bean 實(shí)例本身。

ApplicationConext 是 BeanFactory 的子接口,擴(kuò)展了 BeanFactory 的功能,提供了支持國際化文本消息,統(tǒng)一的資源文件讀取方式等功能。Bean 的依賴注入在容器初始化時(shí)就已經(jīng)完成,屬于立即加載,適合單例模式。


注解配置文件

@Configuration 指定當(dāng)前類是一個(gè) Spring 配置類,創(chuàng)建容器時(shí)會(huì)從該類上加載注解,value 屬性指定配置類的字節(jié)碼。

@ComponentScan 開啟組件掃描,basePackages 屬性指定要掃描的包。

@PropertySource 用于加載 properties 文件中的配置。

@Import 導(dǎo)入其他配置類,有 @Import 的是父配置類,引入的是子配置類,value 屬性指定其他配置類的字節(jié)碼。


Spring AOP ?

AOP

AOP 面向切面編程,將代碼中重復(fù)的部分抽取出來,使用動(dòng)態(tài)代理技術(shù),在不修改源碼的基礎(chǔ)上對方法進(jìn)行增強(qiáng)。

如果目標(biāo)對象實(shí)現(xiàn)了接口,默認(rèn)采用 JDK 動(dòng)態(tài)代理,也可以強(qiáng)制使用 CGLib;如果目標(biāo)對象沒有實(shí)現(xiàn)接口,采用 CGLib 的方式。

常用場景包括權(quán)限認(rèn)證、自動(dòng)緩存、錯(cuò)誤處理、日志、調(diào)試和事務(wù)等。


相關(guān)注解

@Aspect:聲明被注解的類是一個(gè)切面 Bean。

@Before:前置通知,指在某個(gè)連接點(diǎn)之前執(zhí)行的通知。

@After:后置通知,指某個(gè)連接點(diǎn)退出時(shí)執(zhí)行的通知(不論正常返回還是異常退出)。

@AfterReturning:返回后通知,指某連接點(diǎn)正常完成之后執(zhí)行的通知,返回值使用 returning 屬性接收。

@AfterThrowing:異常通知,指方法異常退出時(shí)執(zhí)行的通知,和 @AfterReturning 只會(huì)有一個(gè)執(zhí)行,異常使用 throwing 屬性接收。


相關(guān)術(shù)語

Aspect:切面,一個(gè)關(guān)注點(diǎn)的模塊化,這個(gè)關(guān)注點(diǎn)可能會(huì)橫切多個(gè)對象。

Joinpoint:連接點(diǎn),程序執(zhí)行過程中的某一行為,即業(yè)務(wù)層中的所有方法。

Advice:通知,指切面對于某個(gè)連接點(diǎn)所產(chǎn)生的動(dòng)作,包括前置通知、后置通知、返回后通知、異常通知和環(huán)繞通知。

Pointcut:切入點(diǎn),指被攔截的連接點(diǎn),切入點(diǎn)一定是連接點(diǎn),但連接點(diǎn)不一定是切入點(diǎn)。

Proxy:代理,Spring AOP 中有 JDK 動(dòng)態(tài)代理和 CGLib 代理,目標(biāo)對象實(shí)現(xiàn)了接口時(shí)采用 JDK 動(dòng)態(tài)代理,反之采用 CGLib 代理。

Target:代理的目標(biāo)對象,指一個(gè)或多個(gè)切面所通知的對象。

Weaving :織入,指把增強(qiáng)應(yīng)用到目標(biāo)對象來創(chuàng)建代理對象的過程。


Spring MVC ?

處理流程

Web 容器啟動(dòng)時(shí)初始化 IoC 容器,加載 Bean 的定義信息并初始化所有單例 Bean,遍歷容器中的 Bean,獲取每個(gè) Controller 中的所有方法訪問的 URL,將 URL 和對應(yīng)的 Controller 保存到一個(gè) Map 集合中。

所有的請求會(huì)轉(zhuǎn)發(fā)給 DispatcherServlet 處理,DispatcherServlet 會(huì)請求 HandlerMapping 找出容器中被 @Controler 修飾的 Bean 以及被 @RequestMapping 修飾的方法和類,生成 Handler 和 HandlerInterceptor 并以一個(gè) HandlerExcutionChain 鏈的形式返回。

DispatcherServlet 使用 Handler 找到對應(yīng)的 HandlerApapter,通過 HandlerApapter 調(diào)用 Handler 的方法,將請求參數(shù)綁定到方法的形參上,執(zhí)行方法處理請求并得到邏輯視圖 ModelAndView。

使用 ViewResolver 解析 ModelAndView 得到物理視圖 View,進(jìn)行視圖渲染,將數(shù)據(jù)填充到視圖中并返回給客戶端。


組件

DispatcherServlet:前端控制器,整個(gè)流程控制的核心,負(fù)責(zé)接收請求并轉(zhuǎn)發(fā)給對應(yīng)的處理組件。

Handler:處理器,完成具體業(yè)務(wù)邏輯。

HandlerMapping:處理器映射器,完成 URL 到 Controller 映射。

HandlerInterceptor:處理器攔截器,如果需要完成攔截處理可以實(shí)現(xiàn)該接口。

HandlerExecutionChain:處理器執(zhí)行鏈,包括 Handler 和 HandlerInterceptor。

HandlerAdapter:處理器適配器,DispatcherServlet 通過 HandlerAdapter 來執(zhí)行不同的 Handler。

ModelAndView:邏輯視圖,裝載模型數(shù)據(jù)信息。

ViewResolver:視圖解析器,將邏輯視圖解析為物理視圖。


相關(guān)注解

@RequtestMapping:將 URL 請求和方法映射起來,在類和方法定義上都可以添加。value 屬性指定 URL 請求的地址。method 屬性限制請求類型,如果沒有使用指定方法請求 URL,會(huì)報(bào) 405 錯(cuò)誤。params 屬性限制必須提供的參數(shù)。

@RequestParam:如果 Controller 方法的形參和 URL 參數(shù)名不一致可以使用該注解綁定。value 屬性表示 HTTP 請求中的參數(shù)名,required 屬性設(shè)置參數(shù)是否必要,默認(rèn)false。defaultValue 屬性指定沒有給參數(shù)賦值時(shí)的默認(rèn)值。

@PathVariable:Spring MVC 支持 RESTful 風(fēng)格 URL,通過 @PathVariable 完成參數(shù)綁定。


Spring Data JPA

ORM

Object-Relational Mapping ,表示對象關(guān)系映射,映射的不只是對象的值還有對象之間的關(guān)系,通過 ORM 就可以把對象映射到關(guān)系型數(shù)據(jù)庫中。操作實(shí)體類就相當(dāng)于操作數(shù)據(jù)庫表,可以不再重點(diǎn)關(guān)注 SQL 語句。


JPA 的使用

只需要持久層接口繼承 JpaRepository 即可,泛型參數(shù)列表中第一個(gè)參數(shù)是實(shí)體類類型,第二個(gè)參數(shù)是主鍵類型。

運(yùn)行時(shí)通過 JdkDynamicAopProxyinvoke 方法創(chuàng)建了一個(gè)動(dòng)態(tài)代理對象 SimpleJpaRepository,SimpleJpaRepository 中封裝了 JPA 的操作,通過 hibernate 完成數(shù)據(jù)庫操作。


實(shí)體類相關(guān)注解

@Entity:表明當(dāng)前類是一個(gè)實(shí)體類。

@Table :關(guān)聯(lián)實(shí)體類和數(shù)據(jù)庫表。

@Column :關(guān)聯(lián)實(shí)體類屬性和數(shù)據(jù)庫表中字段。

@Id :聲明當(dāng)前屬性為數(shù)據(jù)庫表主鍵對應(yīng)的屬性。

@GeneratedValue: 配置主鍵生成策略。

@OneToMany :配置一對多關(guān)系,mappedBy 屬性值為主表實(shí)體類在從表實(shí)體類中對應(yīng)的屬性名。

@ManyToOne :配置多對一關(guān)系,targetEntity 屬性值為主表對應(yīng)實(shí)體類的字節(jié)碼。

@JoinColumn:配置外鍵關(guān)系,name 屬性值為外鍵名稱,referencedColumnName 屬性值為主表主鍵名稱。


對象導(dǎo)航查詢

通過 get 方法查詢一個(gè)對象的同時(shí),通過此對象可以查詢它的關(guān)聯(lián)對象。

對象導(dǎo)航查詢一到多默認(rèn)使用延遲加載, 關(guān)聯(lián)對象是多個(gè)對象,使用立即加載可能浪費(fèi)資源;對象導(dǎo)航查詢多到一默認(rèn)使用立即加載。

實(shí)體類注解的 fetch 屬性表示加載方式,LAZY 是延遲加載,EAGER 是立即加載。


Mybatis?

XML 標(biāo)簽

selectinsert、update、delete 標(biāo)簽分別對應(yīng)查詢、添加、更新、刪除操作。

parameterType 屬性表示參數(shù)的數(shù)據(jù)類型,包括基本數(shù)據(jù)類型和對應(yīng)的包裝類型、String 和 Java Bean 類型,當(dāng)有多個(gè)參數(shù)時(shí)可以使用 #{argn} 的形式表示第 n 個(gè)參數(shù)。除了基本數(shù)據(jù)類型都要以全限定類名的形式指定參數(shù)類型。

resultType 表示返回的結(jié)果類型,包括基本數(shù)據(jù)類型和對應(yīng)的包裝類型、String 和 Java Bean 類型。還可以使用把返回結(jié)果封裝為復(fù)雜類型的 resultMap 。


一級緩存

一級緩存是 SqlSession 級別,默認(rèn)開啟。

SqlSession 對象中有一個(gè) HashMap 緩存數(shù)據(jù),不同 SqlSession 間緩存數(shù)據(jù)互不影響。同一個(gè) SqlSession 中執(zhí)行兩次相同的 SQL 語句時(shí),第一次執(zhí)行完畢會(huì)將結(jié)果保存在緩存中,第二次查詢直接從緩存中獲取。

如果 SqlSession 執(zhí)行了 DML 操作(insert、update、delete),Mybatis 必須將緩存清空保證數(shù)據(jù)有效性。


二級緩存

二級緩存是Mapper 級別,默認(rèn)關(guān)閉。

相比于一級緩存,緩存范圍更大,多個(gè) SqlSession 可以共用二級緩存,作用域是 Mapper 的同一個(gè) namespace,不同 SqlSession 兩次執(zhí)行相同的 namespace 下的 SQL 語句,參數(shù)也相等,則第一次執(zhí)行成功后會(huì)將數(shù)據(jù)保存在二級緩存中。

需要在全局配置文件中配置 <setting name="cacheEnabled" value="true"/> ,并在對應(yīng)的映射文件中配置 <cache/> 標(biāo)簽。


#{}${} 的區(qū)別

使用 ${} 相當(dāng)于使用字符串拼接,存在 SQL 注入的風(fēng)險(xiǎn)。

使用 #{} 相當(dāng)于使用占位符,可以防止 SQL 注入,不支持使用占位符的地方就只能使用 ${} ,典型情況就是動(dòng)態(tài)參數(shù)。


SpringBoot?

優(yōu)點(diǎn)

簡化開發(fā):它的作用就是快速搭建 Spring 框架。

簡化配置:比如要?jiǎng)?chuàng)建一個(gè) web 項(xiàng)目,在使用 Spring 的時(shí)候,需要在 pom 文件中添加多個(gè)依賴,而在 SpringBoot 中只需要添加一個(gè) starter-web 依賴即可。

簡化部署:使用 Spring 時(shí)需要部署 tomcat,然后把項(xiàng)目打成 war 包。而 SpringBoot 內(nèi)嵌了 tomcat,只需要將項(xiàng)目打成 jar 包即可。


注解

@SpringBootApplication:自動(dòng)給程序進(jìn)行必要配置,這個(gè)配置等同于:@Configuration ,@EnableAutoConfiguration@ComponentScan 三個(gè)配置。

@EnableAutoConfiguration:允許 SpringBoot 自動(dòng)配置注解,開啟后 SpringBoot 就能根據(jù)當(dāng)前類路徑下的包或者類來配置 Bean。

@SpringBootConfiguration:相當(dāng)于 @Configuration,只是語義不同。


SpringCloud?

微服務(wù)的優(yōu)點(diǎn)

各個(gè)服務(wù)的開發(fā)、測試、部署都相互獨(dú)立,用戶服務(wù)可以拆分為獨(dú)立服務(wù),如果用戶量很大,可以很容易對其實(shí)現(xiàn)負(fù)載。

當(dāng)新需求出現(xiàn)時(shí),使用微服務(wù)不再需要考慮各方面的問題,例如兼容性、影響度等。

使用微服務(wù)拆分項(xiàng)目后,各個(gè)服務(wù)之間消除了很多限制,只需要保證對外提供的接口正??捎茫幌拗普Z言和框架等選擇。


服務(wù)治理 Eureka

服務(wù)治理由三部分組成:服務(wù)提供者、服務(wù)消費(fèi)者、注冊中心。

服務(wù)注冊:在分布式系統(tǒng)架構(gòu)中,每個(gè)微服務(wù)在啟動(dòng)時(shí),將自己的信息存儲(chǔ)在注冊中心。

服務(wù)發(fā)現(xiàn):服務(wù)消費(fèi)者從注冊中心獲取服務(wù)提供者的網(wǎng)絡(luò)信息,通過該信息調(diào)用服務(wù)。

Spring Cloud 的服務(wù)治理使用 Eureka 實(shí)現(xiàn),Eureka 是 Netflix 開源的基于 REST 的服務(wù)治理解決方案,Spring Cloud 集成了 Eureka,提供服務(wù)注冊和服務(wù)發(fā)現(xiàn)的功能,可以和基于 Spring Boot 搭建的微服務(wù)應(yīng)用輕松完成整合。


服務(wù)網(wǎng)關(guān) Zuul

Spring Cloud 集成了 Zuul 組件,實(shí)現(xiàn)服務(wù)網(wǎng)關(guān)。

Zuul 是 Netflix 提供的一個(gè)開源的 API 網(wǎng)關(guān)服務(wù)器,是客戶端和網(wǎng)站后端所有請求的中間層,對外開放一個(gè) API,將所有請求導(dǎo)入統(tǒng)一的入口,屏蔽了服務(wù)端的具體實(shí)現(xiàn)邏輯,可以實(shí)現(xiàn)方向代理功能,在網(wǎng)關(guān)內(nèi)部實(shí)現(xiàn)動(dòng)態(tài)路由、身份認(rèn)證、IP過濾、數(shù)據(jù)監(jiān)控等。


負(fù)載均衡 Ribbon

Ribbon 是 Netflix 發(fā)布的均衡負(fù)載器,Spring Cloud 集成了 Ribbon,提供用于對 HTTP 請求進(jìn)行控制的負(fù)載均衡客戶端。

在注冊中心對 Ribbon 進(jìn)行注冊之后,Ribbon 就可以基于某種負(fù)載均衡算法(輪循、隨機(jī)、加權(quán)輪詢、加權(quán)隨機(jī)等)自動(dòng)幫助服務(wù)消費(fèi)者調(diào)用接口,開發(fā)者也可以根據(jù)具體需求自定義 Ribbon 負(fù)載均衡算法。實(shí)際開發(fā)中 Spring Clooud Ribbon 需要結(jié)合 Spring Cloud Eureka 使用,Eureka 提供所有可以調(diào)用的服務(wù)提供者列表,Ribbon 基于特定的負(fù)載均衡算法從這些服務(wù)提供者中選擇要調(diào)用的實(shí)例。


聲明式接口調(diào)用 Feign

Feign 是 Netflix 提供的,一個(gè)聲明式、模板化的 Web Service 客戶端,簡化了開發(fā)者編寫 Web 客戶端的操作,開發(fā)者可以通過簡單的接口和注解來調(diào)用 HTTP API。

相比于 Ribbon + RestTemplate 的方式,F(xiàn)eign 可以大大簡化代碼開發(fā),支持多種注解,包括 Feign 注解、Spring MVC 注解等。

RestTemplate 是 Spring 框架提供的基于 REST 的服務(wù)組件,底層是對 HTTP 請求及響應(yīng)進(jìn)行了封裝,提供了很多訪問 REST 服務(wù)的方法,簡化代碼開發(fā)。


服務(wù)配置 Config

Spring Cloud Config 通過服務(wù)端可以為多個(gè)客戶端提供配置服務(wù),既可以將配置文件存儲(chǔ)在本地,也可以將配置文件存儲(chǔ)在遠(yuǎn)程的 Git 倉庫,創(chuàng)建 Config Server,通過它管理所有的配置文件。


服務(wù)跟蹤 Zipkin

Spring Cloud Zipkin 是一個(gè)可以采集并跟蹤分布式系統(tǒng)中請求數(shù)據(jù)的組件,讓開發(fā)者更直觀地監(jiān)控到請求在各個(gè)微服務(wù)耗費(fèi)的時(shí)間,Zipkin 包括兩部分 Zipkin Server 和 Zipkin Client。


服務(wù)熔斷 Hystrix

熔斷器的作用:在不改變各個(gè)微服務(wù)調(diào)用關(guān)系的前提下,針對錯(cuò)誤情況進(jìn)行預(yù)先處理。

設(shè)計(jì)原則:服務(wù)隔離、服務(wù)降級、熔斷機(jī)制、提供實(shí)時(shí)監(jiān)控和報(bào)警功能、提供實(shí)時(shí)配置修改功能。

Hystrix 數(shù)據(jù)監(jiān)控需要結(jié)合 Spring Boot Actuator 使用,Actuator 提供了對服務(wù)的數(shù)據(jù)監(jiān)控、數(shù)據(jù)統(tǒng)計(jì),可以通過 hystirx-stream 節(jié)點(diǎn)獲取監(jiān)控的請求數(shù)據(jù),同時(shí)提供了可視化監(jiān)控界面。


參考資料

[1] # SpringMVC常用注解整理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容