Spring中存對(duì)象和取對(duì)象的方式詳解
本文我來(lái)介紹一種更簡(jiǎn)單的存儲(chǔ)對(duì)象方式和取對(duì)象方式,跟上我的節(jié)奏,我們開(kāi)始吧??!
透露一下:Spring中更簡(jiǎn)單的存對(duì)象與取對(duì)象的方式是注解。
給大家插個(gè)題外話(huà)(了解即可),注解實(shí)現(xiàn)有兩種方式:1.在編譯的時(shí)候,把注解替換成相關(guān)代碼,并添加到我們?cè)瓉?lái)的代碼中。2.攔截方法,當(dāng)程序執(zhí)行到某個(gè)方法時(shí),會(huì)執(zhí)行攔截,在執(zhí)行之前或之后或之中進(jìn)行一些操作(與我們寫(xiě)的注解有關(guān))。
1.存儲(chǔ)對(duì)象(Bean)
在上一篇我們存儲(chǔ)對(duì)象是在配置文件中添加<bean>標(biāo)簽,但這樣其實(shí)很麻煩,我們每次都得去那添加一個(gè)。所以為了簡(jiǎn)化,我們可以在配置文件中配置掃描路徑,然后通過(guò)注解來(lái)存儲(chǔ)對(duì)象。
1.1配置掃描路徑(重要!?。。?/h3>
在使用的時(shí)候,把下面這段代碼放到你的配置文件中,把<content>標(biāo)簽中的包名替換成你項(xiàng)目需要掃描的包名。(這個(gè)搭配注解來(lái)實(shí)現(xiàn)存儲(chǔ)對(duì)象)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:content="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <content:component-scan base-package="包名"></content:component-scan> </beans>
為什么會(huì)配置這個(gè)掃描路徑呢?舉個(gè)例子吧,假設(shè)你找個(gè)人,你是從整個(gè)中國(guó)一個(gè)一個(gè)找好找還是從一個(gè)村里找好找。所以嘛,Spring也是這樣呀,你給它配置了掃描包,Spring就會(huì)從這個(gè)包里一個(gè)一個(gè)找,看哪些添加了注解(需要Spring幫忙創(chuàng)建對(duì)象的),他就會(huì)把哪些類(lèi)存儲(chǔ)起來(lái)。
1.如果我們配置的掃描包中存在子類(lèi),里面的注解也是會(huì)被掃描的。
2.如果我創(chuàng)建的類(lèi)在掃描包外面,此時(shí)我用相關(guān)注解也沒(méi)有用的,因?yàn)楦静粫?huì)掃這個(gè)類(lèi)!
3.那如果我的類(lèi)就是在掃描包外面,但是欸,我還是想交給Spring創(chuàng)建對(duì)象,腫么辦呢?好說(shuō)嘛!用我上一篇存儲(chǔ)Bean的方法,掃描包可以與Bean同時(shí)生效的。
4.我們?cè)O(shè)置了掃描包,沒(méi)有添加注解,這樣也是沒(méi)辦法將對(duì)象存儲(chǔ)到Spring中的。(兩個(gè)要搭配使用?。。。?/p>
1.2添加注解存儲(chǔ)對(duì)象
將對(duì)象存儲(chǔ)到Spring中,有兩種可以實(shí)現(xiàn),一種是類(lèi)注解,一種是方法注解。
1.2.1類(lèi)注解
類(lèi)注解有五種:@Controller @Service @Component @Repository @Configuration。
我先來(lái)說(shuō)一下,為啥有這么多類(lèi)注解。簡(jiǎn)單來(lái)說(shuō),為了讓程序員看到類(lèi)注解后更直觀的知道這個(gè)類(lèi)是干什么的。JavaEE上有標(biāo)準(zhǔn)分層(至少三層):控制層,業(yè)務(wù)層,數(shù)據(jù)層。當(dāng)然也有更多層的劃分,大家可以看阿里巴巴Java開(kāi)發(fā)手冊(cè)。
控制層主要用于與用戶(hù)交互,業(yè)務(wù)層主要用于處理一些業(yè)務(wù),數(shù)據(jù)層主要與數(shù)據(jù)庫(kù)進(jìn)行交互。不同層干不同事,所以也就出來(lái)了不同的注解。
1.2.1.1@Controller
這個(gè)注解主要用于控制層中。代碼如下:
@Controller//通過(guò)這個(gè)注解將對(duì)象存儲(chǔ)到Spring中 public class StudentController { public void study() { System.out.println("控制層aaaa"); } }
1.2.1.2@Service
這個(gè)注解一般都是用于業(yè)務(wù)層的。
@Service//通過(guò)這個(gè)注解存儲(chǔ)對(duì)象 public class StudentService { public void eat() { System.out.println("業(yè)務(wù)層啊啊啊"); } }
1.2.1.3@Repository
這個(gè)注解用在Dao層,也即是數(shù)據(jù)層。
@Repository public class StudentMapper { public void study() { System.out.println("我是數(shù)據(jù)層"); } }
1.2.1.4@Component
這個(gè)用于哪呢?當(dāng)我們進(jìn)行一些操作不屬于三層中的任何一層的時(shí)候,我們就可以用這個(gè)注解。
@Component public class Test { public void test() { System.out.println("保密功能"); } }
1.2.1.5@Configuration
這個(gè)一般都是用于配置類(lèi)上。
@Configuration public class Test1 { public void set() { System.out.println("配置類(lèi)"); } }
1.2.1.6五大類(lèi)注解的關(guān)系
這五大類(lèi)注解其實(shí)本質(zhì)都一樣,都是為了將對(duì)象存儲(chǔ)到Spring中。并且@Controller / @Service / @Repository / @Configuration這幾個(gè)的源碼中都存在@Component,可以認(rèn)為這四個(gè)注解均為@Component的子類(lèi),或者均為@Component的擴(kuò)展。
1.2.1.7通過(guò)類(lèi)注解將對(duì)象存儲(chǔ)到Spring中的命名規(guī)則
- 當(dāng)我們創(chuàng)建的類(lèi)名為比較標(biāo)準(zhǔn)的大駝峰形式,Spring提供的對(duì)象名為首字母小寫(xiě),其余不動(dòng)的形式。
- 如果類(lèi)名首字母和第二個(gè)字母都為大寫(xiě),提供的對(duì)象名為原類(lèi)名。
- 除了第二條外,默認(rèn)情況下都是Spring提供的對(duì)象名為首字母小寫(xiě),其余不動(dòng)的形式。
1.2.2方法注解
1.2.2.1使用與注意事項(xiàng)
方法注解為@Bean。顧名思義,該注解用到方法上。
創(chuàng)建一個(gè)User類(lèi),并且創(chuàng)建一個(gè)Users類(lèi),我們來(lái)使用一下。
//User類(lèi) public class User { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } //Users類(lèi) @Component public class Users { @Bean public User user1() { User user = new User(); user.setAge(18); user.setName("張三"); user.setId(1); return user; } }
注意事項(xiàng):
1.@Bean注解必須搭配五大類(lèi)注解使用,否則會(huì)報(bào)錯(cuò)的?。榱薙pring執(zhí)行的性能)
2.通過(guò)方法注解將對(duì)象存儲(chǔ)到Spring中命名規(guī)則為(默認(rèn)情況下)對(duì)象名等于方法名。
3.方法的返回類(lèi)型必須存在,且必須為一個(gè)類(lèi)。
4.我們可能不同類(lèi)卻存在相同方法名的方法,此時(shí)如果我們?nèi)圆捎梅椒鳛閷?duì)象id來(lái)獲取對(duì)象,此時(shí)會(huì)出現(xiàn)覆蓋。最后只有一個(gè)結(jié)果,而且還不一定是我們想要拿到的那個(gè)對(duì)象。我們有兩種方法進(jìn)行解決:一種是通過(guò)注解@Order注解來(lái)給其排序,值越小的優(yōu)先級(jí)越高,越先執(zhí)行。(但是也會(huì)覆蓋)最后呈現(xiàn)的結(jié)果為值最大的。另外一種是給Bean重命名。
5.當(dāng)我們對(duì)同一類(lèi)型使用多個(gè)@Bean時(shí),通過(guò)注入的方式注入對(duì)象會(huì)報(bào)錯(cuò)的,因?yàn)橛卸鄠€(gè)Bean了,Spring不知道用哪個(gè)了。有兩種解決方法:(1)注入的時(shí)候,使用Resource注解,并且指定對(duì)象名,通過(guò)name屬性;(2)使用@Qualifier注解的value屬性來(lái)設(shè)置注入的名稱(chēng)(必須結(jié)合Autowired使用)。
1.2.2.2Bean重命名
由于上面我們提到了當(dāng)用默認(rèn)的提供名字的時(shí)候可能會(huì)出現(xiàn)誤差,所以我們可以對(duì)方法上面的@Bean進(jìn)行重命名。說(shuō)白了也就是對(duì)存儲(chǔ)到Spring種的對(duì)象指定好名字。
//可以只指定一個(gè)名字 @Bean(name = "user")//這里可以用name=...也可以用value=..... public User user1() { User user = new User(); user.setAge(18); user.setName("張三"); user.setId(1); System.out.println(1); return user; } //也可以指定多個(gè)名字(用哪個(gè)都可以) @Bean(name = {"user","use","custom"})//這里可以用name=...也可以用value=..... public User user1() { User user = new User(); user.setAge(18); user.setName("張三"); user.setId(1); System.out.println(1); return user; }
但是,當(dāng)我們重命名以后,就不可以再用方法名(Spring默認(rèn)提供的名字)來(lái)取出對(duì)象了,除非你將重命名后的名字設(shè)置為了方法名。
2.取出對(duì)象
我在上一篇文章中,敘述了取出對(duì)象的方法,正常來(lái)說(shuō),我們?nèi)赃@樣去取出最終對(duì)象。但是在一些類(lèi)中用到另外的類(lèi)的時(shí)候,我們可以有簡(jiǎn)單方法呀,也就是對(duì)象注入。
對(duì)象注入有三種方式:屬性注入;setters方法注入;構(gòu)造方法注入。
@Autowired是先通過(guò)類(lèi)型進(jìn)行查找,如果發(fā)現(xiàn)有多個(gè),然后通過(guò)名稱(chēng)(根據(jù)我們定義的屬性后面,我們定義的變量名查找)查找。(裝配順序)
@Qualifier必須和@Autowired一起使用,@Qualifier通過(guò)名字來(lái)進(jìn)行注入。
@Resource先根據(jù)名稱(chēng)(如果有多個(gè)相同的名稱(chēng))查再根據(jù)類(lèi)型查。
@Value注入普通類(lèi)型屬性。
2.1屬性注入
@Controller public class StudentController { @Autowired public StudentService studentService;//在控制類(lèi)中引入了另外一個(gè)類(lèi),為了更方便使用,我們這里采用對(duì)象注入方式注入對(duì)象。 public void study() { System.out.println("控制層aaaa"); } }
屬性注入就是通過(guò)@AutoWired注解來(lái)完成的。將這個(gè)注解放在當(dāng)前類(lèi)中引入的另外類(lèi)最為成員變量的上面即可。
優(yōu)點(diǎn):很簡(jiǎn)單。
缺點(diǎn):
1.對(duì)于有final修飾的變量無(wú)法無(wú)法進(jìn)行注入。
2.兼容性差,只使用于IoC容器。
3.風(fēng)險(xiǎn)更大,更容易違背單一設(shè)計(jì)原則。(比如在服務(wù)層,我們就想處理一套業(yè)務(wù),但通過(guò)這個(gè)我們可以進(jìn)行多套業(yè)務(wù))
2.2setters方法注入
也就是通過(guò)setters方法進(jìn)行注入
@Controller public class StudentController { private StudentService studentService; //添加setter方法,并添加注解(注入對(duì)象) @Autowired public void setStudentService(StudentService studentService) { this.studentService = studentService; } public void study() { System.out.println("控制層aaaa"); } }
優(yōu)點(diǎn):符合單一設(shè)計(jì)規(guī)則,每個(gè)Setter方法只有一個(gè)參數(shù)。
缺點(diǎn):
1.不能注入不可變對(duì)象(final修飾的)
2.使用setter注入的對(duì)象可能被修改。
2.3構(gòu)造方法注入
也就是通過(guò)構(gòu)造方法來(lái)注入對(duì)象。
@Controller public class StudentController { private StudentService studentService; //通過(guò)構(gòu)造方法來(lái)注入了 @Autowired public StudentController(StudentService studentService) { this.studentService = studentService; } public void setStudentService(StudentService studentService) { this.studentService = studentService; } public void study() { System.out.println("控制層aaaa"); } }
1.如果當(dāng)前類(lèi)只有這樣的一個(gè)構(gòu)造方法,@Autowired這個(gè)注解是可以省略的。
優(yōu)點(diǎn):
1.可以注入不可變對(duì)象(final修飾的)為什么呢?因?yàn)楸籪inal修飾的變量必須被復(fù)制,要不直接復(fù)制,要不就是在構(gòu)造方法中復(fù)制。
2.注入對(duì)象不會(huì)被改變的,構(gòu)造方法只會(huì)執(zhí)行一次。
3.構(gòu)造方法注入可以保證完全被初始化。
4.通用性更好。
2.4另外種注入關(guān)鍵字@Resource
和@Autowired相同之處:
- 都是進(jìn)行注入。
不同之處:
- @Autowired來(lái)自Spring而@Resource來(lái)自JDK
- 與@Autowired相比,@Resource支持更多參數(shù),我們可以設(shè)置name等于什么,根據(jù)名稱(chēng)注入Bean。
- @Autowired可以用于三種注入方式中,而@Resource只可以用在Setter和屬性注入中。
以上就是Spring中存對(duì)象和取對(duì)象的方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring存對(duì)象和取對(duì)象的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring boot 自定義規(guī)則訪問(wèn)獲取內(nèi)部或者外部靜態(tài)資源圖片的方法
這篇文章主要介紹了spring boot 自定義規(guī)則訪問(wèn)獲取內(nèi)部或者外部靜態(tài)資源圖片的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01使用Java編寫(xiě)控制JDBC連接、執(zhí)行及關(guān)閉的工具類(lèi)
這篇文章主要介紹了如何使用Java來(lái)編寫(xiě)控制JDBC連接、執(zhí)行及關(guān)閉的程序,包括一個(gè)針對(duì)各種數(shù)據(jù)庫(kù)通用的釋放資源的工具類(lèi)的寫(xiě)法,需要的朋友可以參考下2016-03-03更簡(jiǎn)單更高效的Mybatis?Plus最新代碼生成器AutoGenerator
這篇文章主要為大家介紹了更簡(jiǎn)單更高效的Mybatis?Plus最新代碼生成器AutoGenerator使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02Spring boot基于JPA訪問(wèn)MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
本文主要介紹了Spring boot基于JPA訪問(wèn)MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn),Spring boot結(jié)合Jpa 能夠簡(jiǎn)化創(chuàng)建 JPA 數(shù)據(jù)訪問(wèn)層和跨存儲(chǔ)的持久層功能,用戶(hù)的持久層Dao接口只需要繼承定義好的接口,感興趣的可以了解一下2021-06-06SpringBoot+SpringSecurity實(shí)現(xiàn)認(rèn)證的流程詳解
這篇文章主要介紹了SpringBoot+SpringSecurity實(shí)現(xiàn)認(rèn)證的流程,文中通過(guò)代碼示例和圖文結(jié)合的方式講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-05-05詳解Java正則表達(dá)式中Pattern類(lèi)和Matcher類(lèi)
java.util.regex是一個(gè)用正則表達(dá)式所訂制的模式來(lái)對(duì)字符串進(jìn)行匹配工作的類(lèi)庫(kù)包。包括兩個(gè)類(lèi)Pattern和Matcher Pattern,Pattern是一個(gè)正則表達(dá)式經(jīng)編譯后的表現(xiàn)模式。Matcher對(duì)象是一個(gè)狀態(tài)機(jī)器,它依據(jù)Pattern對(duì)象做為匹配模式對(duì)字符串展開(kāi)匹配檢查。2016-12-12springboot 使用logback啟動(dòng)報(bào)警報(bào)錯(cuò)的解決
這篇文章主要介紹了springboot 使用logback啟動(dòng)報(bào)警報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07maven關(guān)于pom文件中的relativePath標(biāo)簽使用
在Maven項(xiàng)目中,子工程通過(guò)<relativePath>標(biāo)簽指定父工程的pom.xml位置,以確保正確繼承父工程的配置,這個(gè)標(biāo)簽可以配置為默認(rèn)值、空值或自定義值,默認(rèn)情況下,Maven會(huì)向上一級(jí)目錄尋找父pom;若配置為空值2024-09-09