『壹』 spring boot啟動不掃描創建bean怎麼回事
說明你的spring boot啟動時的application類不在io.github.gefangshuai.app及其子包下。
『貳』 怎麼學習spring boot 源碼
可以根據官網的示例來學習。
『叄』 Feign源碼解析二
本文會基於Feign源碼,看看Feign到底是怎麼實現遠程調用
上文中,我們的 user-service 服務需要調用遠程的 order-service 服務完成一定的業務邏輯,而基本實現是order-service提供一個spi的jar包給user-service依賴,並且在user-service的啟動類上添加了一個註解
這個註解就是@EnableFeignClients,接下來我們就從這個註解入手,一步一步解開Feign的神秘面紗
該註解類上的注釋大概的意思就是:
掃描那些被聲明為 Feign Clients (只要有 org.springframework.cloud.openfeign.FeignClient 註解修飾的介面都是Feign Clients介面)的介面
下面我們繼續追蹤源碼,看看到底什麼地方用到了這個註解
利用IDEA的查找調用鏈快捷鍵,可以發現在.class類型的文件中只有一個文件用到了這個註解
OK,下面主要就是看這個類做了什麼
通過UML圖我們發現該類分別實現了 ImportBeanDefinitionRegistrar , ResourceLoaderAware 以及 EnvironmentAware 介面
這三個介面均是spring-framework框架的spring-context模塊下的介面,都是和spring上下文相關,具體作用下文會分析
總結下來就是利用這兩個重要屬性,一個獲取應用配置屬性,一個可以載入classpath下的文件,那麼FeignClientsRegistrar持有這兩個東西之後要做什麼呢?
上面將bean配置類包裝成 FeignClientSpecification ,注入到容器。該對象非常重要,包含FeignClient需要的 重試策略 , 超時策略 , 日誌 等配置,如果某個FeignClient服務沒有設置獨立的配置類,則讀取默認的配置,可以將這里注冊的bean理解為整個應用中所有feign的默認配置
由於 FeignClientsRegistrar 實現了 ImportBeanDefinitionRegistrar 介面,這里簡單提下這個介面的作用
我們知道在spring框架中,我們如果想注冊一個bean的話主要由兩種方式:自動注冊/手動注冊
知道了 ImportBeanDefinitionRegistrar 介面的作用,下面就來看下 FeignClientsRegistrar 類是何時被載入實例化的
通過IDEA工具搜索引用鏈,發現該類是在註解@EnableFeignClients上被import進來的,文章開始的圖片中有
這里提下@Import註解的作用
該註解僅有一個屬性value,使用該註解表明導入一個或者多個@Configuration類,其作用和.xml文件中的<import>等效,其允許導入@Configuration類,ImportSelector介面/ImportBeanDefinitionRegistrar介面的實現,也同樣可以導入一個普通的組件類
注意,如果是XML或非@Configuration的bean定義資源需要被導入的話,需要使用@ImportResource註解代替
這里我們導入的FeignClientsRegistrar類正是一個ImportBeanDefinitionRegistrar介面的實現
FeignClientsRegistrar重寫了該介面的 registerBeanDefinitions 方法,該方法有兩個參數註解元數據 metadata 和bean定義注冊表 registry
該方法會由spring負責調用,繼而注冊所有標注為@FeignClient註解的bean定義
下面看registerBeanDefinitions方法中的第二個方法,在該方法中完成了所有@FeignClient註解介面的掃描工作,以及注冊到spring中,注意這里注冊bean的類型為 FeignClientFactoryBean ,下面細說
總結一下該方法,就是掃描@EnableFeignClients註解上指定的basePackage或clients值,獲取所有@FeignClient註解標識的介面,然後將這些介面一一調用以下 兩個重要方法 完成 注冊configuration配置bean 和注冊 FeignClient bean
斷點位置相當重要
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
這里是利用了spring的代理工廠來生成代理類,即這里將所有的 feignClient的描述信息 BeanDefinition 設定為 FeignClientFactoryBean 類型,該類繼承自FactoryBean,因此這是一個代理類,FactoryBean是一個工廠bean,用作創建代理bean,所以得出結論,feign將所有的 feignClient bean定義的類型包裝成 FeignClientFactoryBean
最終其實就是存入了BeanFactory的beanDefinitionMap中
那麼代理類什麼時候會觸發生成呢? 在spring 刷新容器時 ,會根據beanDefinition去實例化bean,如果beanDefinition的beanClass類型為代理bean,則會調用其 T getObject() throws Exception; 方法生成代理bean,而我們實際利用注入進來的FeignClient介面就是這些一個個代理類
這里有一個需要注意的點,也是開發中會遇到的一個 啟動報錯點
如果我們同時定義了兩個不同名稱的介面 (同一個包下/或依賴方指定全部掃描我們提供的 @FeignClient ),且這兩個 @FeignClient 介面註解的 value/name/serviceId 值一樣的話,依賴方拿到我們的提供的spi依賴,啟動類上 @EnableFeignClients 註解掃描能同時掃描到這兩個介面,就會 啟動報錯
原因就是Feign會為每個@FeignClient註解標識的介面都注冊一個以serviceId/name/value為key,FeignClientSpecification類型的bean定義為value去spring注冊bean定義,又默認不允許覆蓋bean定義,所以報錯
官方提示給出的解決方法要麼改個@FeignClient註解的serviceId,name,value屬性值,要麼就開啟spring允許bean定義覆寫
至此我們知道利用在springboot的啟動類上添加的@EnableFeignClients註解,該註解中import進來了一個手動注冊bean的 FeignClientsRegistrar注冊器 ,該注冊器會由spring載入其 registerBeanDefinitions方法 ,由此來掃描所有@EnableFeignClients註解定義的basePackages包路徑下的所有標注為@FeignClient註解的介面,並將其注冊到spring的bean定義Map中,並實例化bean
下一篇博文中,我會分析為什麼我們在調用(@Resource)這些由@FeignClient註解的bean的方法時會發起 遠程調用
『肆』 學習java的同學都是怎麼讀源碼的
剛參加工作那會,沒想過去讀源碼,更沒想過去改框架的源碼;總想著別人的框架應該是完美的、萬能的,應該不需要改;另外即使我改了源碼,怎麼樣讓我的改動生效了?項目中引用的不還是沒改的jar包嗎。回想起來覺得那時候的想法確實挺??
工作了一年多之後准備跳槽了,開始了一輪的面試,其中有幾個面試官就問到了相關的源碼問題:ArrayList、HashMap的底層實現,spring、mybatis的相關源碼。問源碼的面試一般就是回去等消息,然後就沒然後了。
那時候開始意識到,源碼這東西在之前的工作的中感受不到,但是在面試中好像面的還挺頻繁的,從此有意識的開始了jdk部分源碼的閱讀(主要是集合)。一開始看源碼,看的特別糙,知道個大概,知道ArrayList的底層實現是數組,HashMap的底層是散列表(數組+鏈表);更深入一點的擴容、hash碰撞等等就不知道了。
讀spring源碼起於工作中遇到了一個問題(spring jdbcTemplate事務,各種詭異,包你醍醐灌頂!),排查一段時間最終是解決了,但過程讓我非常難受,各種上網查資料、各種嘗試,感覺就像大海撈針一樣,遙遙無期。我下定決心,我要看一看spring的源碼,於是我買了一本《spring源碼深度解析》,結合著這本書、打開著eclipse,開始了spring的源碼閱讀之旅。至此,讀源碼成了習慣,源碼已經進入了我的心裡。
後來,springboot的火熱,讓我也想蹭上一蹭,於是有了springboot的啟動源碼系列,雖然還在進行中,但是我相信我能將其完成;工作中用到了shiro,我又結合著《跟我學shiro》將shiro的源碼看了個大概,有了shiro源碼系列博文,還差一篇認證與授權(應該很快就能面世),shiro源碼系列就封筆了。最近在搭建自己的後台管理系統,用到了quartz,集成的過程也遇到了一些問題,因此有了quartz的兩篇文章。
慢慢的,從一味的網上找資料變成了很多時候會從源碼中找答案。不求能讀太多的源碼,但願自己接觸的技術都能讀上一讀,路漫漫其修遠兮,吾將上下而求索!
大家為什麼要讀源碼?
很多人一定和我一樣的感受:源碼在工作中有用嗎?用處大嗎?很長一段時間內我也有這樣的疑問,認為哪些有事沒事扯源碼的人就是在裝,只是為了提高他們的逼格而已。
那為什麼我還要讀源碼呢?一剛開始為了面試,後來為了解決工作中的問題,再後來就是個人喜好了。說的好聽點是有匠人精神;說的委婉點是好奇(底層是怎麼實現的);說的不自信點是對黑盒的東西我用的沒底,怕用錯;說的簡單直白點是提升自我價值,為了更高的薪資待遇(這里對真正的技術迷說聲抱歉)。
源碼中我們可以學到很多東西,學習別人高效的代碼書寫、學習別人對設計模式的熟練使用、學習別人對整個架構的布局,等等。如果你還能找出其中的不足,那麼恭喜你,你要飛升了!會使用固然重要,但知道為什麼這么使用同樣重要。從模仿中學習,從模仿中創新。
讀源碼不像圍城(外面的人想進來,裡面的人想出去),它是外面的人不想進來,裡面的人不想出去;當我們跨進城內,你會發現(還是城外好,皮!)城內風光無限,源碼的海洋任我們遨遊!
首先我們要對我們的目標有所了解,知道她有什麼特點,有些什麼功能。對對方都還不了解,就想著進入別人的內心世界,那不是臭不要臉嘛,我們要做一個有著流氓心的紳士;對她有個大致的了解了,就可以發起攻勢,一舉拿下。
那麼怎麼樣了解了,方式有很多,我這里提供幾種,僅供參考
最好的方式就是官方參考指南,親生父母往往對孩子是最了解的,對孩子的描述也是最詳細的;比如Spring Boot Reference Guide就是對springboot最詳細的描述,怎麼樣使用springboot、springboot特性等等,通過此指南,springboot在你面前一覽無遺;
但是,springboot畢竟是外國人的孩子,如果英語不好,估計讀起來有點頭疼了,不過我們有google翻譯呀,咬咬牙也是能看的。源碼世界的丈母娘、老岳丈是非常慷慨的!
其次是書籍,國外優秀的有很多,國內也不乏好書,比較推薦此方式,自成體系,讓我們掌握的知識點不至於太散。這就是好比是源碼的閨蜜,對源碼非常了解,重點是挺大方,會盡全力幫助我們了解源碼。
再次就是博客,雖然可能覺得知識點比較散,但是針對某個知識點卻特別的細,對徹底掌握非常有幫助,園子內就有很多技術大牛,寫的博客自然也是非常棒,非常具有學習價值。當然還有社區、論壇、github、碼雲等等。這就是源碼的朋友圈,我們從中也能獲取到非常多關於源碼的信息。
設計模式的了解
優秀的框架、技術從不乏設計模式;jdk源碼中就應用了很多設計模式,比如IO流中的適配器模式與裝飾模式、GUI的觀察者模式、集合中的迭代器模式等等;spring源碼中也是用到了大量的設計模式。設計模式有什麼優點、各適用於什麼場景,不是本文的內容,需要我們大家自行去了解。
我們只需要對一些常用的設計模式有個大致了解,再去讀源碼是比較好的;不需要將23種設計模式都通讀,也不需要將常用設計模式完全理解透;對於全部通讀,我們時間有限,另外有些模式確實不太好理解、用的少,性價比不高,沒必要全部都讀。
推薦書籍:《Head First Design Patterns》(中文版:《Head First 設計模式》)、《Java與模式》;
另外我比較推薦的一種學習設計模式的方式是讀別人博客:java_my_life,劉偉技術博客,chenssy的設計模式;
設計模式之於源碼,就好比逛街購物之於女人,想順利勾搭源碼,我們需要好好掌握設計模式這個套路。
配合ide進行斷點追蹤
我們通過源碼的圈子對源碼的了解終究只是停在表面,終究還是沒有走進她的內心,接下來我就和大家分享下,我是如何走進她的內心的!
相信看過我的源碼博客的小夥伴都知道,我非常喜歡通過idea斷點來進行源碼追蹤,斷點追蹤源碼是我非常推薦的一種方式。斷點不僅可以用來調試我們的代碼,也可以用來調試我們用到的框架源碼。
面對未知的、茫茫多的源碼,我們往往沒有足夠的時間、經歷和耐心去通讀所有源碼,我們只需要去讀我們關注的部分即可(有人可能會說我都不關心,這?)。那為什麼要用斷掉調試的方式來跟源碼,而不是直接從源代碼入手去跟我們關注的部分呢?
嘗試過的小夥伴應該知道,如果我們對源碼不熟悉,直接通過源碼的方式去跟,一方面很容易迷路(多態,會有很多子類實現),不知道接下來跟哪一個,另一方面也很容易跟丟,當我們跟入的很深的時候,很有可能就忘記上一步跟到哪了。所以讀源碼的重要性淺顯易懂了。
『伍』 如何構建spring boot
Spring Boot充分利用了JavaConfig的配置模式以及「約定優於配置」的理念,能夠極大的簡化基於Spring
MVC的Web應用和REST服務開發。
Spring
4倡導微服務的架構,針對這一理念,近來在微博上也有一些有價值的討論,如這里和這里。微服務架構倡導將功能拆分到離散的服務中,獨立地進行部署,Spring
Boot能夠很方便地將應用打包成獨立可運行的JAR包,因此在開發模式上很契合這一理念。目前,Spring
Boot依然是0.5.0的里程碑版本,因此相關的文檔尚不完善,本文將會以一個簡單的樣例來介紹基於這個項目的開發過程。
要Spring
Boot進行功能開發,需要使用Gradle或者Maven作為構建工具。在本例中,我們會使用Eclipse和Maven插件進行開發。要使用Spring
Boot,首先創建一個Maven工程,並修改Maven主要的配置文件pom.xml,如下所示:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>0.5.0.M7</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
</dependency>
</dependencies>
<properties>
<start-class>com.levin.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestone</id>
<url>http://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestone</id>
<url>http://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
在上面的配置中,需要將工程的parent設置為spring-boot-starter-parent,並添加對spring-boot-starter-web的依賴,這樣我們就無需設置各個依賴項及其版本信息了。並且在構建中要聲明使用spring-boot-maven-plugin這個插件,它會對Maven打包形成的JAR進行二次修改,最終產生符合我們要求的內容結構。
在我們的應用中將要發布一個REST服務,顯示一個基本的用戶信息,首先定義一個簡單的模型類:
package com.levin;
public class Person {
private String name;
private String email;
public Person(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
接下來,我們需要聲明一個Spring MVC的Controller,響應對實體的請求:
@Controller
public class ShowPersonController {
@RequestMapping("/showPerson")
public @ResponseBody Person showPerson() {
return new Person("levinzhang","[email protected]");
}
}
這個類與我們在使用Spring MVC定義Controller時並無任何差別。接下來,我們需要聲明一個主類啟動這個應用程序:
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
這個類的main方法中使用了SpringApplication幫助類,並以Application這個類作為配置來啟動Spring的應用上下文。在這個類中使用了ComponentScan以及EnableAutoConfiguration註解,其中ComponentScan註解會告知Spring掃描指定的包來初始化Spring
Bean,這能夠確保我們聲明的Bean能夠被發現。EnableAutoConfiguration將會啟動自動配置模式,在我們的配置中會將對Tomcat的依賴級聯進來,因此在應用啟動時將會自動啟動一個嵌入式的Tomcat,因為在樣例中使用了Spring
MVC,所以也會自動注冊所需的DispatcherServlet,這都不需要類似web.xml這樣的配置。
在Eclipse中要運行這個應用的話,可以直接以Java
Application的形式來運行這個main函數,此時會啟動應用,我們在瀏覽器中可以看到如下的運行效果,這就是我們想要的REST服務:
在開發調試完成之後,可以將應用打成JAR包的形式,在Eclipse中可以直接使用Maven插件的package命令,最終會形成一個可運行的JAR包。我們使用java
–jar命令就可以運行這個JAR包了。所呈現出的效果與在調試期是一樣的。現在看一下這個JAR包解壓後的目錄結構:
這個JAR包與傳統JAR包的不同之處在於裡面有一個名為lib的目錄,在這個目錄中包含了這個簡單應用所依賴的其他JAR包,其中也包含內置的嵌入式Tomcat,正是使用它,才能發布服務和訪問Web資源。除了我們編寫的源碼所編譯形成的CLASS以外,在org目錄下還有許多Spring所提供的CLASS,正是依賴這些CLASS,才能夠載入位於lib目錄下JAR中的類。這樣的載入機制與在OSGi
bundle中聲明Bundle-Classpath很類似,不過在OSGi中會由容器來負責載入指定路徑下的類。這大致闡述了這樣一個JAR包能夠發布服務的原因。
如果我們想要使用HTML、JSP等Web資源的話,在Controller中直接返回對應的視圖就可以了。
如果我們想要將這個JAR包轉換成可以在Servlet容器中部署的WAR的話,就不能依賴於Application的main函數了,而是要以類似於web.xml文件配置的方式來啟動Spring應用上下文,此時我們需要聲明這樣一個類:
public class HelloWebXml extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
這個類的作用與在web.xml中配置負責初始化Spring應用上下文的監聽器作用類似,只不過在這里不需要編寫額外的XML文件了。
如果要將最終的打包形式改為WAR的話,還需要對pom.xml文件進行修改,除了需要將packaging的值修改為war以外,還需要對依賴進行適當的配置(這一部分在Spring
Boot的樣例和文檔中均未提及,提醒大家注意):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
在這里需要移除對嵌入式Tomcat的依賴,這樣打出的WAR包中,在lib目錄下才不會包含Tomcat相關的JAR包,否則將會出現啟動錯誤。另外,在移除對Tomcat的依賴後,為了保證編譯正確,還需要添加對servlet-api的依賴,因此添加如下的配置:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>7.0.42</version>
<scope>provided</scope>
</dependency>
在這里將scope屬性設置為provided,這樣在最終形成的WAR中不會包含這個JAR包,因為Tomcat或Jetty等伺服器在運行時將會提供相關的API類。此時,執行mvn
package命令就會得到一個WAR文件,我們可以直接將其放到Tomcat下運行(需要7.0.42版本以上)。
以上介紹了基於Spring Boot開發應用的過程,目前它的文檔尚不完善,但是在GitHub上有不少的樣例,包括與Spring
Data集成訪問資料庫(關系型以及非關系型)、安全、WebSocket等,讀者感興趣可以下載運行,需要注意的是有些樣例中使用的是0.5.0.M6版本,這個版本有問題,運行時會出錯,建議手動修改為0.5.0.M7或快照版本。
基於以上的介紹,希望讀者能夠對Spring
Boot這個新項目有所了解。它簡化了JAR包管理和相關基礎設施環境的配置,能夠幫助我們快速開發Web應用或構建REST服務,希望它能夠盡快完善成熟,更多地用於實踐,提升開發效率。
『陸』 在哪裡可下spring boot admin ui源碼
創建PageController,編碼如下:
package org.springboot.sample.controller;
import java.util.Date;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class PageController {
// 從 application.properties 中讀取配置,如取不到默認值為Hello Shanhy
@Value("${application.hell:Hello Shanhy}")
private String hello = "Hello Shanhy";
/**
* 默認頁<br/>
* @RequestMapping("/") 和 @RequestMapping 是有區別的
* 如果不寫參數,則為全局默認頁,加入輸入404頁面,也會自動訪問到這個頁面。
* 如果加了參數「/」,則只認為是根頁面。
*
* @return
* @author SHANHY
* @create 2016年1月5日
*/
@RequestMapping(value = {"/","/index"})
public String index(Map<String, Object> model){
// 直接返回字元串,框架默認會去 spring.view.prefix 目錄下的 (index拼接spring.view.suffix)頁面
// 本例為 /WEB-INF/jsp/index.jsp
model.put("time", new Date());
model.put("message", this.hello);
return "index";
}
/**
* 響應到JSP頁面page1
*
* @return
* @author SHANHY
* @create 2016年1月5日
*/
@RequestMapping("/page1")
public ModelAndView page1(){
// 頁面位置 /WEB-INF/jsp/page/page.jsp
ModelAndView mav = new ModelAndView("page/page1");
mav.addObject("content", hello);
return mav;
}
/**
* 響應到JSP頁面page1(可以直接使用Model封裝內容,直接返回頁面字元串)
*
* @return
* @author SHANHY
* @create 2016年1月5日
*/
@RequestMapping("/page2")
public String page2(Model model){
// 頁面位置 /WEB-INF/jsp/page/page.jsp
model.addAttribute("content", hello + "(第二種)");
return "page/page1";
}
}
pom.xml添加依賴:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>123456789
上面說了spring-boot 不推薦JSP,想使用JSP需要配置application.properties。
添加src/main/resources/application.properties內容:
# 頁面默認前綴目錄
spring.mvc.view.prefix=/WEB-INF/jsp/
# 響應頁面默認後綴
spring.mvc.view.suffix=.jsp
# 自定義屬性,可以在Controller中讀取
application.hello=Hello Shanhy123456
在 src/main 下面創建 webapp/WEB-INF/jsp 目錄用來存放我們的jsp頁面。
index.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Spring Boot Sample</title>
</head>
<body>
Time: ${time}
<br>
Message: ${message}
</body>
</html>12345678910111213
page1.jsp
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Spring Boot Sample</title>
</head>
<body>
<h1>${content }</h1>
</body>
</html>1234567891011
要想讓spring-boot支持JSP,需要將項目打成war包。
我們做最後一點修改,修改pom.xml文件,將 jar 中的 jar 修改為 war
然後啟動spring-boot服務。
『柒』 springBoot @RequestBody 寫在方法上與寫在參數上的區別
1. @Controller
控制層組件,定義一個springMVC的控制器類,往往需要和@RequestMapping配合使用。
2. @RestController
相當於@ResponseBody+@Controller合在一起的作用。
3. @Service
服務層組件,用於標注業務層組件,表示定義一個bean,自動根據bean的類名實例化一個首寫字母為小寫的bean,也可以指定bean的名稱:@Service(「beanName」)。
4. @Repository
持久層組件,用於標注數據訪問組件,即DAO組件。
5. @Component
把普通pojo實例化到spring容器中,相當於配置文件中的 <bean id="" class=""/>。
6. @RequestMapping
用於配置控制層的訪問URL,可以用在控制器類上和控制器方法上,如果用在控制器類上,則訪問類中的方法是要加上類上的路徑,例如:
@Controller
@RequestMapping("/personal/linkInfo")
public class LinkInfoController {
@RequestMapping(value = "/addLinkInfo")
public String addLinkInfo(LinkInfoReq linkInfoReq) {
linkInfoService.addLinkInfo(linkInfoReq);
return "redirect:/personal/linkInfo/toLinkInfo";
}
}
上述代碼的訪問路徑就是XXX/personal/linkInfo/addLinkInfo。
@RequestMapping源代碼如下圖:
a) value:設置訪問的URL,數組,可以將多個請求映射到一個方法上去。支持通配符配置
代碼示例:
@RequestMapping(value = {"/page","/page*"})
public void getInfo() {
}
上述代碼訪問路徑可以是:XXX/page,XXX/pageadc等滿足value條件的路徑。
b) method:設置訪問的方法,數組,可是設置多個訪問方法映射到同一個方法上,默認為GET方法
代碼示例:
@RequestMapping(value = "/page", method = RequestMethod.POST)
public void getInfo() {
}
上述代碼 /page路徑就只能用POST方法才能請求。
method的可選值有GET,HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE。
c) params:指定request中必須包含某些參數值是,才讓該方法處理。數組。
@RequestMapping(value = "/page", params = {"type=1"})
public void getInfo() {
}
上述代碼/page路徑只有請求參數中包含type且值等於1時才能訪問該方法。
d) headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。數組。
示例代碼:
@RequestMapping(value = "/page", headers = {" content-type=text/plain " })
public void getInfo() {
}
上述代碼/page路徑只有headers中content-type=text/plain才能訪問該方法。
e) consumes:指定處理請求的提交內容類型(Content-Type),例如application/json, text/html。
f) proces:指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回。
7. @ResponseBody
通常使用在controller方法上,作用是將方法的返回值通過合適的HttpMessageConverter轉換成特定格式寫入到response的body區域,然後返回給客戶端,如果沒有使用@RequestBody註解,方法返回值將會封裝到ModelAndView並解析返回視圖。
8. @RequestParam
接受的參數來自requestHeader,即請求頭,用來接收GET和POST請求參數並將參數賦值到被@RequestParam註解的變數上,同樣可以使用requet.getParameter(「name」)獲取,默認的參數接受方式,如果controller方法的參數未使用@RequestParam,則默認也是使用@RequestParam接受參數。用來處理Content-Type: 為 application/x-www-form-urlencoded編碼的內容。
@RequestParam有三個配置參數:
a) required:是否必須,默認true,必須。
b) defaultValue:默認值,請求的參數為空時使用默認值。
c) value:請求的參數名。
9. @RequestBody
接受的參數來自requestBody,即請求體,一般用於處理非 Content-Type: application/x-www-form-urlencoded編碼格式的數據,比如:application/json、application/xml等類型的數據。
10. @Autowired
它可以對類成員變數,方法及構造函數進行標注,完成自動裝配工作,可以消除set,get方法。
11. @Resource
其作用和@Autowired相似。
不同點:
@Resource是Java自己的註解,@Resource有兩個屬性重要屬性,分是name和type;Spring將@Resource註解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
@Autowired是spring的註解,是spring2.5版本引入的,@Autowired只根據type進行注入,不會去匹配name。如果涉及到type無法辨別注入對象時,那需要依賴@Qualifier註解一起來修飾。
@Resource裝配順序
a) 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
b) 如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
c) 如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
d) 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退為一個原始類型進行匹配,如果匹配則自動裝配;
推薦使用@Resource,不用謝set方法,並且這個註解屬於java自己的,減少了與spring的耦合度。
12. @Value
該註解有兩種使用方式:
a) @Value(「${}」)
這種使用方式注入的是配置文件里的參數
這樣配置文件中的com.title就能配置到LinkInfoController的title屬性中
b) @Value(「#{}」)
該方式表示SpEl表達式通常用來獲取bean的屬性,或者調用bean的某個方法。
這樣就可以把User對象的name配置到LinkInfoController的name屬性中。
13. @Transactional
用於配置spring事務管理。屬性信息如下:
事物的傳播行為如下:
14. @SpringBootApplication
該註解其實是一個組合註解,源碼如下圖:
比較重要的註解有三個:
a) @SpringBootConfiguration
從源代碼可以看到@SpringBootConfiguration繼承自@Configuration,這兩個註解的功能也是一樣的。
b) @EnableAutoConfiguration
此注釋自動載入應用程序所需的所有Bean。
c) @ComponentScan
該註解會掃描指定路徑下的的類,並將其加入到IoC容器中。在springboot中,@ComponentScan默認掃描@SpringBootApplication所在類的同級目錄以及它的子目錄。
15. @Configuration
從Spring3.0,@Configuration用於定義配置類,可替換xml配置文件,被註解的類內部包含有一個或多個被@Bean註解的方法,這些方法將會被或類進行掃描,並用於構建bean定義,初始化Spring容器。
16. @Bean
該註解主要用在@Configuration註解的類里,也可以用在@Component註解的類里。添加的bean的id為方法名。相當於配置文件里的<bean></bean>。
@Configuration
public class RedisConfig extends CachingConfigurerSupport{
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
return redisCacheManager;
}
}
如上代碼就相當於在xml文件里配置:
<beans>
<bean id=" cacheManager " class=" com.mypage.config. RedisCacheManager "/>
</beans>
17. @MapperScan
指定要變成實現類的介面所在的包,然後包下面的所有介面在編譯之後都會生成相應的實現類添加位置:是在Springboot啟動類上面添加:
18. @EnableCaching
該註解是spring framework中的註解驅動的緩存管理功能。自spring版本3.1起加入了該註解。如果你使用了這個註解,那麼你就不需要在XML文件中配置cache manager了。
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
/**
* 採用RedisCacheManager作為緩存管理器
* @param connectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
return redisCacheManager;
}
}
19. @EnableRedisHttpSession
用來設置springboot使用redis存儲session,該註解會創建一個名字叫springSessionRepositoryFilter的Spring Bean,其實就是一個Filter,這個Filter負責用Spring Session來替換原先的默認HttpSession實現。
示例代碼如下:
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60*30)
public class HttpSessionConfig {
}
其中屬性maxInactiveIntervalInSeconds是設置session的有效時間,單位毫秒,默認1800ms。
但其實這樣還是不夠的,還要在配置文件中設置redis存儲session:
spring.session.store-type=redis
這樣就可以了。