Springboot注解,autowired注解_Spring系列之Spring常用注解總結

 2023-11-10 阅读 37 评论 0

摘要:作者:平凡希來源:https://www.cnblogs.com/xiaoxi/p/5935009.html傳統的Spring做法是使用.xml文件來對bean進行注入或者是配置aop、事物,這么做有兩個缺點:如果所有的內容都配置在.xml文件中,那么.xml文件將會十分龐大;如果按需求分
作者:平凡希來源:https://www.cnblogs.com/xiaoxi/p/5935009.html

傳統的Spring做法是使用.xml文件來對bean進行注入或者是配置aop、事物,這么做有兩個缺點:

  • 如果所有的內容都配置在.xml文件中,那么.xml文件將會十分龐大;如果按需求分開.xml文件,那么.xml文件又會非常多。總之這將導致配置文件的可讀性與可維護性變得很低。
  • 在開發中在.java文件和.xml文件之間不斷切換,是一件麻煩的事,同時這種思維上的不連貫也會降低開發的效率。

為了解決這兩個問題,Spring引入了注解,通過@XXX的方式,讓注解與Java Bean緊密結合,既大大減少了配置文件的體積,又增加了Java Bean的可讀性與內聚性。

不使用注解:

Springboot注解,先看一個不使用注解的Spring示例,在這個示例的基礎上,改成注解版本的,這樣也能看出使用與不使用注解之間的區別。

先定義一個老虎:

package com.spring.model;public class Tiger { private String tigerName="TigerKing"; public String toString(){ return "TigerName:"+tigerName; }}

再定義一個猴子:

package com.spring.model;public class Monkey { private String monkeyName = "MonkeyKing"; public String toString(){ return "MonkeyName:" + monkeyName; }}

定義一個動物園:

package com.spring.model;public class Zoo { private Tiger tiger; private Monkey monkey; public Tiger getTiger() { return tiger; } public void setTiger(Tiger tiger) { this.tiger = tiger; } public Monkey getMonkey() { return monkey; } public void setMonkey(Monkey monkey) { this.monkey = monkey; } public String toString(){ return tiger + "" + monkey; }}

java注解的作用。spring的配置文件這么寫:

8c857c3ca3d7cc9de3a4489c447cdaff.png

測試方法:

public class TestAnnotation { /** * 不使用注解 */ @Test public void test(){ //讀取配置文件 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml"); Zoo zoo=(Zoo) ctx.getBean("zoo"); System.out.println(zoo.toString()); }}

都很熟悉,權當復習一遍了。

1、@Autowired

Spring 注解。@Autowired顧名思義,就是自動裝配,其作用是為了消除代碼Java代碼里面的getter/setter與bean屬性中的property。當然,getter看個人需求,如果私有屬性需要對外提供的話,應當予以保留。

@Autowired默認按類型匹配的方式,在容器查找匹配的Bean,當有且僅有一個匹配的Bean時,Spring將其注入@Autowired標注的變量中。

因此,引入@Autowired注解,先看一下spring配置文件怎么寫:

98a88147080e93c036e4a7d6e112cec0.png

注意第13行,使用必須告訴spring一下我要使用注解了,告訴的方式有很多,是一種最簡單的,spring會自動掃描xxx路徑下的注解。

springmvc常用5種注解,看到第15行,原來zoo里面應當注入兩個屬性tiger、monkey,現在不需要注入了。再看下,Zoo.java也很方便,把getter/setter都可以去掉:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;public class Zoo { @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString(){ return tiger + "" + monkey; }}

這里@Autowired注解的意思就是,當Spring發現@Autowired注解時,將自動在代碼上下文中找到和其匹配(默認是類型匹配)的Bean,并自動注入到相應的地方去。

有一個細節性的問題是,假如bean里面有兩個property,Zoo.java里面又去掉了屬性的getter/setter并使用@Autowired注解標注這兩個屬性那會怎么樣?答案是Spring會按照xml優先的原則去Zoo.java中尋找這兩個屬性的getter/setter,導致的結果就是初始化bean報錯。

OK,假設此時我把.xml文件的16行、17行兩行給去掉,再運行,會拋出異常:

79f493a5bcb6e761febb280291f70a15.png

Java 注解、因為,@Autowired注解要去尋找的是一個Bean,Tiger和Monkey的Bean定義都給去掉了,自然就不是一個Bean了,Spring容器找不到也很好理解。那么,如果屬性找不到我不想讓Spring容器拋出異常,而就是顯示null,可以嗎?可以的,其實異常信息里面也給出了提示了,就是將@Autowired注解的required屬性設置為false即可:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;public class Zoo { @Autowired(required=false) private Tiger tiger; @Autowired(required=false) private Monkey monkey; public String toString(){ return tiger + "" + monkey; }}

此時,找不到tiger、monkey兩個屬性,Spring容器不再拋出異常而是認為這兩個屬性為null。

2、Qualifier(指定注入Bean的名稱)

如果容器中有一個以上匹配的Bean,則可以通過@Qualifier注解限定Bean的名稱,看下面的例子:

Springboot常用注解。定義一個Car接口:

package com.spring.service;public interface ICar { public String getCarName();}

兩個實現類BMWCar和BenzCar:

package com.spring.service.impl;import com.spring.service.ICar;public class BMWCar implements ICar{ public String getCarName(){ return "BMW car"; }}
package com.spring.service.impl;import com.spring.service.ICar;public class BenzCar implements ICar{ public String getCarName(){ return "Benz car"; }}

再寫一個CarFactory,引用car(這里先不用@Qualifier注解):

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;import com.spring.service.ICar;public class CarFactory { @Autowired private ICar car; public String toString(){ return car.getCarName(); }}

配置文件:

3df69392de4b40e32023606094d680e0.png

常用注解,測試方法:

/** * Autowired注解配合Qualifier注解 */@Testpublic void test1(){ //讀取配置文件 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext2.xml"); CarFactory carFactory=(CarFactory) ctx.getBean("carFactory"); System.out.println(carFactory.toString());}

運行一下,不用說,一定是報錯的,Car接口有兩個實現類,Spring并不知道應當引用哪個實現類。

7c22ca841f202f19f873c2380331fa67.png

出現這種情況通常有兩種解決辦法:

  • 在配置文件中刪除其中一個實現類,Spring會自動去base-package下尋找Car接口的實現類,發現Car接口只有一個實現類,便會直接引用這個實現類。
  • 實現類就是有多個該怎么辦?此時可以使用@Qualifier注解來指定Bean的名稱:
package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import com.spring.service.ICar;public class CarFactory { @Autowired @Qualifier("bmwCar") private ICar car; public String toString(){ return car.getCarName(); }}

此處會注入名為"bmwCar"的Bean。

3、Resource

@Resource注解與@Autowired注解作用非常相似,這個就簡單說了,看例子:

package com.spring.model;import javax.annotation.Resource;public class Zoo1 { @Resource(name="tiger") private Tiger tiger; @Resource(type=Monkey.class) private Monkey monkey; public String toString(){ return tiger + "" + monkey; }}

這是詳細一些的用法,說一下@Resource的裝配順序:

  1. @Resource后面沒有任何內容,默認通過name屬性去匹配bean,找不到再按type去匹配
  2. 指定了name或者type則根據指定的類型去匹配bean
  3. 指定了name和type則根據指定的name和type去匹配bean,任何一個不匹配都將報錯

然后,區分一下@Autowired和@Resource兩個注解的區別:

  1. @Autowired默認按照byType方式進行bean匹配,@Resource默認按照byName方式進行bean匹配
  2. @Autowired是Spring的注解,@Resource是J2EE的注解,這個看一下導入注解的時候這兩個注解的包名就一清二楚了

Spring屬于第三方的,J2EE是Java自己的東西,因此,建議使用@Resource注解,以減少代碼和Spring之間的耦合。

4、Service

上面這個例子,還可以繼續簡化,因為spring的配置文件里面還有15行~17行三個bean,下一步的簡化是把這三個bean也給去掉,使得spring配置文件里面只有一個自動掃描的標簽,增強Java代碼的內聚性并進一步減少配置文件。

要繼續簡化,可以使用@Service。先看一下配置文件,當然是全部刪除了:

<?xml version="1.0" encoding="UTF-8"?>

是不是感覺很爽?起碼我覺得是的。OK,下面以Zoo.java為例,其余的Monkey.java和Tiger.java都一樣:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class Zoo { @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString(){ return tiger + "" + monkey; }}

這樣,Zoo.java在Spring容器中存在的形式就是"zoo",即可以通過ApplicationContext的getBean("zoo")方法來得到Zoo.java。@Service注解,其實做了兩件事情:

  • 聲明Zoo.java是一個bean,這點很重要,因為Zoo.java是一個bean,其他的類才可以使用@Autowired將Zoo作為一個成員變量自動注入。
  • Zoo.java在bean中的id是"zoo",即類名且首字母小寫。

如果,我不想用這種形式怎么辦,就想讓Zoo.java在Spring容器中的名字叫做"Zoo",可以的:

package com.spring.model;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Service;@Service("Zoo")@Scope("prototype")public class Zoo { @Autowired private Tiger tiger; @Autowired private Monkey monkey; public String toString(){ return tiger + "" + monkey; }}

這樣,就可以通過ApplicationContext的getBean("Zoo")方法來得到Zoo.java了。

這里我還多加了一個@Scope注解,應該很好理解。因為Spring默認產生的bean是單例的,假如我不想使用單例怎么辦,xml文件里面可以在bean里面配置scope屬性。注解也是一樣,配置@Scope即可,默認是"singleton"即單例,"prototype"表示原型即每次都會new一個新的出來。

使用注解來構造IoC容器

用注解來向Spring容器注冊Bean。需要在applicationContext.xml中注冊。

如:在base-package指明一個包

表明cn.gacl.java包及其子包中,如果某個類的頭上帶有特定的注解【@Component/@Repository/@Service/@Controller】,就會將這個對象作為Bean注冊進Spring容器。也可以在中指定多個包,如:

多個包逗號隔開。

1、@Component

@Component是所有受Spring 管理組件的通用形式,@Component注解可以放在類的頭上,@Component不推薦使用。

2、@Controller

@Controller對應表現層的Bean,也就是Action,例如:

@Controller@Scope("prototype")public class UserAction extends BaseAction{ ……}

使用@Controller注解標識UserAction之后,就表示要把UserAction交給Spring容器管理,在Spring容器中會存在一個名字為"userAction"的action,這個名字是根據UserAction類名來取的。注意:如果@Controller不指定其value【@Controller】,則默認的bean名字為這個類的類名首字母小寫,如果指定value【@Controller(value="UserAction")】或者【@Controller("UserAction")】,則使用value作為bean的名字。

這里的UserAction還使用了@Scope注解,@Scope("prototype")表示將Action的范圍聲明為原型,可以利用容器的scope="prototype"來保證每一個請求有一個單獨的Action來處理,避免struts中Action的線程安全問題。spring 默認scope 是單例模式(scope="singleton"),這樣只會創建一個Action對象,每次訪問都是同一Action對象,數據不安全,struts2 是要求每次次訪問都對應不同的Action,scope="prototype" 可以保證當有請求的時候都創建一個Action對象。

3、@Service

@Service對應的是業務層Bean,例如:

@Service("userService")public class UserServiceImpl implements UserService {………}

@Service("userService")注解是告訴Spring,當Spring要創建UserServiceImpl的實例時,bean的名字必須叫做"userService",這樣當Action需要使用UserServiceImpl的的實例時,就可以由Spring創建好的"userService",然后注入給Action:在Action只需要聲明一個名字叫"userService"的變量來接收由Spring注入的"userService"即可,具體代碼如下:

// 注入userService@Resource(name = "userService")private UserService userService;

注意:

在Action聲明的"userService"變量的類型必須是"UserServiceImpl"或者是其父類"UserService",否則由于類型不一致而無法注入,由于Action中的聲明的"userService"變量使用了@Resource注解去標注,并且指明了其name = "userService",這就等于告訴Spring,說我Action要實例化一個"userService",你Spring快點幫我實例化好,然后給我。

當Spring看到userService變量上的@Resource的注解時,根據其指明的name屬性可以知道,Action中需要用到一個UserServiceImpl的實例,此時Spring就會把自己創建好的名字叫做"userService"的UserServiceImpl的實例注入給Action中的"userService"變量,幫助Action完成userService的實例化,這樣在Action中就不用通過UserService userService = new UserServiceImpl();這種最原始的方式去實例化userService了。

如果沒有Spring,那么當Action需要使用UserServiceImpl時,必須通過UserService userService = new UserServiceImpl();主動去創建實例對象,但使用了Spring之后,Action要使用UserServiceImpl時,就不用主動去創建UserServiceImpl的實例了,創建UserServiceImpl實例已經交給Spring來做了,Spring把創建好的UserServiceImpl實例給Action,Action拿到就可以直接用了。

Action由原來的主動創建UserServiceImpl實例后就可以馬上使用,變成了被動等待由Spring創建好UserServiceImpl實例之后再注入給Action,Action才能夠使用。這說明Action對"UserServiceImpl"類的“控制權”已經被“反轉”了。

原來主動權在自己手上,自己要使用"UserServiceImpl"類的實例,自己主動去new一個出來馬上就可以使用了,但現在自己不能主動去new "UserServiceImpl"類的實例,new "UserServiceImpl"類的實例的權力已經被Spring拿走了,只有Spring才能夠new "UserServiceImpl"類的實例,而Action只能等Spring創建好"UserServiceImpl"類的實例后,再“懇求”Spring把創建好的"UserServiceImpl"類的實例給他,這樣他才能夠使用"UserServiceImpl"。

這就是Spring核心思想“控制反轉”,也叫“依賴注入”,“依賴注入”也很好理解,Action需要使用UserServiceImpl干活,那么就是對UserServiceImpl產生了依賴,Spring把Acion需要依賴的UserServiceImpl注入(也就是“給”)給Action,這就是所謂的“依賴注入”。對Action而言,Action依賴什么東西,就請求Spring注入給他,對Spring而言,Action需要什么,Spring就主動注入給他。

4、@ Repository

@Repository對應數據訪問層Bean ,例如:

@Repository(value="userDao")public class UserDaoImpl extends BaseDaoImpl {………}

@Repository(value="userDao")注解是告訴Spring,讓Spring創建一個名字叫"userDao"的UserDaoImpl實例。

當Service需要使用Spring創建的名字叫"userDao"的UserDaoImpl實例時,就可以使用@Resource(name = "userDao")注解告訴Spring,Spring把創建好的userDao注入給Service即可。

// 注入userDao,從數據庫中根據用戶Id取出指定用戶時需要用到@Resource(name = "userDao")private BaseDao userDao;

Spring常用注解匯總

本文匯總了Spring的常用注解,以方便大家查詢和使用,具體如下:

使用注解之前要開啟自動掃描功能,其中base-package為需要掃描的包(含子包)。

@Configuration把一個類作為一個IoC容器,它的某個方法頭上如果注冊了@Bean,就會作為這個Spring容器中的Bean。

@Scope注解:作用域

@Lazy(true):表示延遲初始化

@Service:用于標注業務層組件

@Controller:用于標注控制層組件(如struts中的action)

@Repository:用于標注數據訪問組件,即DAO組件。

@Component:泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。

@Scope:用于指定scope作用域的(用在類上)

@PostConstruct:用于指定初始化方法(用在方法上)

@PreDestory:用于指定銷毀方法(用在方法上)

@DependsOn:定義Bean初始化及銷毀時的順序

@Primary:自動裝配時當出現多個Bean候選者時,被注解為@Primary的Bean將作為首選者,否則將拋出異常

@Autowired:默認按類型裝配,如果我們想使用按名稱裝配,可以結合@Qualifier注解一起使用。如下:@Autowired @Qualifier("personDaoBean")存在多個實例配合使用

@Resource:默認按名稱裝配,當找不到與名稱匹配的bean才會按類型裝配。

@PostConstruct:初始化注解

@PreDestroy:摧毀注解 默認 單例 啟動就加載

@Async:異步方法調用

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/170016.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息