<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring注解方式管理Bean

          共 5908字,需瀏覽 12分鐘

           ·

          2022-03-10 08:49

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          作者?|?汪偉俊

          ?|?公眾號(hào):Java技術(shù)迷(JavaFans1024)

          雖然Spring以簡(jiǎn)化開(kāi)發(fā)著稱(chēng),但在學(xué)習(xí)的過(guò)程中我們發(fā)現(xiàn),每新建一個(gè)類(lèi),就需要在配置文件中進(jìn)行配置,并且類(lèi)與類(lèi)之間的關(guān)系也需要配置在標(biāo)簽中,好像這并沒(méi)有簡(jiǎn)化我們的開(kāi)發(fā),反而增加了很多繁瑣的配置。別擔(dān)心,本篇文章我們就來(lái)學(xué)習(xí)一下用注解方式來(lái)管理Bean。


          組件掃描


          大家不要對(duì)組件這個(gè)詞感到陌生,在Spring中,一個(gè)類(lèi)可以被稱(chēng)為Bean,也被稱(chēng)為一個(gè)組件,回想一下,在之前,我們?nèi)绾螌⒁粋€(gè)組件注冊(cè)到IOC容器中呢?沒(méi)錯(cuò),我們需要寫(xiě)一段配置,例如:

          "user" class="com.wwj.spring.demo.User">
          "name" value="zs"/>
          "age" value="22"/>

          為了讓大家從繁瑣的配置中解脫出來(lái),Spring提供了一種基于注解的管理方式,Spring提供了以下注解用來(lái)注冊(cè)一個(gè)組件:

          1.@Component2.@Controller3.@Service4.@Repository

          這四個(gè)注解都可以用來(lái)注冊(cè)一個(gè)組件,不過(guò)每個(gè)注解都有其意義,比如@Controller,它是用來(lái)注冊(cè)一個(gè)前端控制器的,我們將在SpringMVC中對(duì)其進(jìn)行詳解;而@Service是用來(lái)注冊(cè)一個(gè)服務(wù)層對(duì)象的;@Repository是用來(lái)注冊(cè)一個(gè)持久層對(duì)象的。來(lái)體驗(yàn)一下它們的強(qiáng)大吧:

          @Component
          public class User {
          private String name;
          private Integer age;
          }

          public interface UserService {
          }

          @Service
          public class UserServiceImpl implements UserService {
          }

          @Repository
          public interface UserRepository {
          }

          我們從容器中取出所有的組件,看看注冊(cè)是否成功了:

          public static void main(String[] args) throws Exception {
          ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
          String[] beanDefinitionNames = context.getBeanDefinitionNames();
          for (String beanDefinitionName : beanDefinitionNames) {
          System.out.println(beanDefinitionName);
          }
          }

          當(dāng)你運(yùn)行這段測(cè)試代碼時(shí)你會(huì)發(fā)現(xiàn)控制臺(tái)沒(méi)有任何輸出,是我們獲取的方式不對(duì)嗎?不對(duì),其實(shí)我們還需要進(jìn)行一項(xiàng)配置:

          base-package="com.wwj.spring.demo"/>

          運(yùn)行結(jié)果:

          user
          userRepository
          userServiceImpl
          org.springframework.context.annotation.internalConfigurationAnnotationProcessor
          org.springframework.context.annotation.internalAutowiredAnnotationProcessor
          org.springframework.context.annotation.internalCommonAnnotationProcessor
          org.springframework.context.event.internalEventListenerProcessor
          org.springframework.context.event.internalEventListenerFactory

          可以看到我們的組件確實(shí)注冊(cè)到Spring中了,剩下的是一些Spring內(nèi)置的組件,我們無(wú)需關(guān)系。

          context:component-scan標(biāo)簽是用來(lái)進(jìn)行組件掃描的,其中base-package屬性用于配置需要掃描的包,一般情況下我們會(huì)掃描項(xiàng)目的頂包,即:最外層的包,這樣所有項(xiàng)目中的組件都會(huì)被掃描到并注冊(cè)。

          事實(shí)上,@Component、@Controller、@Service、@Repository四個(gè)注解的作用是完全一樣的,你也可以在組件上隨意地使用它們,比如:

          @Repository
          public class UserServiceImpl implements UserService {
          }

          @Service
          public interface UserRepository {
          }

          這是完全沒(méi)有問(wèn)題的,因?yàn)锧Service、@Controller、@Repository注解是由@Component注解衍生出來(lái)的,但為了規(guī)范,還是建議將注解添加到指定的組件上。

          自動(dòng)注入


          還記得Spring中的屬性注入嗎?如果不記得的話,我們來(lái)回顧一下:

          public class User {
          private Pet pet;
          }

          若是想將一個(gè)對(duì)象屬性注入進(jìn)去,我們需要進(jìn)行配置:

          "pet" class="com.wwj.spring.demo.Pet"/>
          "user" class="com.wwj.spring.demo.User">
          "pet" ref="pet"/>

          但Spring提供了一種更加便捷的注入方式,自動(dòng)注入

          public class User {

          @Autowired
          private Pet pet;
          }

          只需在User類(lèi)的對(duì)象屬性上添加@Autowired注解即可將Pet對(duì)象自動(dòng)注入進(jìn)來(lái),而且它非常智能,我們對(duì)程序進(jìn)行一些改造,首先去掉Pet類(lèi)的@Component注解:

          public class Pet {

          private String name;
          private Integer age;
          }

          然后添加一個(gè)Dog類(lèi)繼承Pet,并注冊(cè):

          @Component
          public class Dog extends Pet{
          private String name;
          private Integer age;
          }

          來(lái)測(cè)試一下:

          public static void main(String[] args) throws Exception {
          ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
          User user = context.getBean("user", User.class);
          System.out.println(user.getPet().getClass());
          }

          運(yùn)行結(jié)果:

          class com.wwj.spring.demo.Dog

          這樣Dog類(lèi)就被自動(dòng)注入到User中了,但如果我們又創(chuàng)建了一個(gè)類(lèi)繼承Pet并注冊(cè):

          @Component
          public class Cat extends Pet{
          }

          此時(shí)程序就會(huì)報(bào)錯(cuò):

          Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.wwj.spring.demo.Pet' available: expected single matching bean but found 2: cat,dog

          這是Spring中比較常見(jiàn)的一個(gè)異常,意思是期望單個(gè)匹配的Bean:Pet,但是匹配到了兩個(gè)Bean:cat、dog。錯(cuò)誤非常好理解,因?yàn)镻et的子類(lèi)有兩個(gè),所以Spring也不清楚我們到底想要哪一個(gè)Bean,所以拋出了異常。

          這一問(wèn)題會(huì)在Service層中出現(xiàn),比如:

          public interface UserService {
          }

          @Service
          public class UserServiceImpl implements UserService {
          }

          @Service
          public class EmployeeServiceImpl implements UserService {
          }

          現(xiàn)在我們有一個(gè)UserService接口,并且有兩個(gè)實(shí)現(xiàn)類(lèi),當(dāng)自動(dòng)注入U(xiǎn)serService時(shí)顯然會(huì)報(bào)錯(cuò),那么如何解決這一問(wèn)題呢?我們可以使用@Qualifier注解:

          @Component
          public class User {

          @Autowired
          @Qualifier("userServiceImpl")
          private UserService userService;
          }

          該注解的值即為需要注入的組件名,如果沒(méi)有配置組件名,則默認(rèn)是類(lèi)名且首字母小寫(xiě),當(dāng)然了,我們也可以進(jìn)行配置:

          @Service("esi")
          public class EmployeeServiceImpl implements UserService {
          }

          注入方式如下:

          @Component
          public class User {

          @Autowired
          @Qualifier("esi")
          private UserService userService;
          }

          這一問(wèn)題也可以使用@Primary注解解決:

          @Service
          @Primary
          public class UserServiceImpl implements UserService {
          }

          當(dāng)出現(xiàn)多個(gè)類(lèi)型相同的類(lèi)導(dǎo)致Spring無(wú)法選擇時(shí),如果某個(gè)類(lèi)標(biāo)注了@Primary,Spring將優(yōu)先將該組件注冊(cè)到IOC容器,不過(guò)這種方式確實(shí)不太優(yōu)雅。


          @Resource注解


          剛才的問(wèn)題其實(shí)可以通過(guò)換一個(gè)注解來(lái)解決,我們不妨試試看:

          @Component
          public class User {

          @Resource
          private UserService userService;
          }

          @Resource注解是JSR-250定義的注解,它和Spring沒(méi)有關(guān)系,但能夠?qū)崿F(xiàn)和@Autowired注解相同的功能,我們先來(lái)介紹一下這兩個(gè)注解之間的區(qū)別:

          ?@Autowired默認(rèn)按類(lèi)型進(jìn)行注入,若要按名稱(chēng)注入,則需要配合@Qualifier注解一起使用;@Resource既支持類(lèi)型注入,也支持名稱(chēng)注入,默認(rèn)為名稱(chēng)注入?@Autowired能夠標(biāo)注在構(gòu)造器、方法、參數(shù)、成員變量、注解上;@Resource只能標(biāo)注在類(lèi)、成員變量和方法上?@Autowired是Spring提供的注解,脫離了Spring框架則無(wú)法使用;@Resource是JSR-250定義的注解,可以脫離任何框架使用

          現(xiàn)在問(wèn)題就解決了嗎?其實(shí)并沒(méi)有,當(dāng)你運(yùn)行測(cè)試代碼時(shí)程序仍然會(huì)拋出異常,這是因?yàn)殡m然@Resource默認(rèn)為名稱(chēng)注入,但是在使用名稱(chēng)找不到組件的情況下,會(huì)繼續(xù)使用類(lèi)型注入,所以眼熟的異常就又出現(xiàn)了。

          我們已經(jīng)知道,Spring在掃描組件時(shí)會(huì)將類(lèi)名且首字母小寫(xiě)作為組件的名稱(chēng)注入到IOC容器中,所以像這樣注入就是沒(méi)有問(wèn)題的:

          @Component
          public class User {

          @Resource
          private UserService userServiceImpl;
          }

          不過(guò)一般情況下我們不會(huì)這么寫(xiě),而是像這樣:

          @Component
          public class User {

          @Resource(name = "employeeServiceImpl")
          private UserService userService;
          }

          通過(guò)@Resource注解,我們就解決了@Autowired和@Qualifier兩個(gè)注解組合才能解決的問(wèn)題,至于到底用哪個(gè),還是看大家的使用習(xí)慣了。


          @Value


          可能有同學(xué)有疑問(wèn)了,我知道對(duì)象類(lèi)型的屬性如何注入了,那基本類(lèi)型數(shù)據(jù)如何注入呢?@Value注解能夠幫助到你,使用方法如下:

          @Component
          public class User {

          @Value("zs")
          private String name;
          @Value("20")
          private Integer age;
          }

          不過(guò)一般情況下,我們都不會(huì)把數(shù)據(jù)這樣寫(xiě)死,都會(huì)將其放到配置文件中:

          jdbc.url=jdbc:mysql:///test
          jdbc.driver=com.mysql.jdbc.Driver
          jdbc.username=root
          jdbc.password=root

          此時(shí)需要借助一個(gè)新注解@PropertySource將值注入到指定的組件中:

          @Component
          @PropertySource("classpath:jdbc.properties")
          public class User {

          @Value("${jdbc.url}")
          private String url;
          @Value("${jdbc.driver}")
          private String driver;
          @Value("${jdbc.username}")
          private String username;
          @Value("${jdbc.password}")
          private String password;
          }

          @Value還能夠注入操作系統(tǒng)屬性:

          @Component
          public class User {

          @Value("#{systemProperties['os.name']}")
          private String name;
          }

          還可以注入表達(dá)式計(jì)算后的結(jié)果:

          @Component
          public class User {

          @Value("#{ T(java.lang.Math).random() * 100.0 }")
          private String result;
          }

          本文作者:汪偉俊?為Java技術(shù)迷專(zhuān)欄作者?投稿,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載

          ????

          1來(lái)開(kāi)發(fā)SQL沒(méi)

          2?Chrome會(huì)沒(méi)個(gè)

          3個(gè)SpringBoot44Java

          4QQ個(gè)

          5SpringBoot?開(kāi)發(fā)過(guò)

          點(diǎn)

          點(diǎn)

          點(diǎn)點(diǎn)

          點(diǎn)

          瀏覽 82
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日日骚av无码 | 婷婷在线看 | 久久久久久久久国产精品 | 夜夜嗨日日Av | 91麻豆精品91久久久ios版 |