@Autowired注解和啟動自動掃描的三種方式(spring bean配置自動掃描功能的三種方式)


前言:

@Autowired注解代碼定義

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,
                        ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

從上述定義中,我們可以得出@Autowired注解只有一個屬性即required屬性,此屬性的默認值為true,即默認情況下它要求依賴對象必須存在,如果不存在會出現空指針等錯誤;如果允許為null,可以設置它required屬性為false.其中@Autowired注解和標注的變量的類的set和get方法無關,自動裝配的實現並不是依賴set方法的方式實現的.在xml中利用

<property name="" value="" />

這種方式是依賴對應類的set方法的方式實現的 @Autowired注解使用之前首先確定判斷一下此處能夠使用@Autowired注解.


 

一、 @Autowired注解使用場景介紹

(1)構造函數
(2)成員變量
(3)Setter方法
(4)普通方法

二、 @Autowired注解所涉及的原理部分

其實在啟動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找需要的bean,並裝配給該對象的屬性

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>  

注意事項:

在使用@Autowired時,首先在容器中查詢對應類型的bean,     

  • 如果查詢結果剛好為一個,就將該bean裝配給@Autowired指定的數據          
  • 如果查詢的結果不止一個,那么@Autowired會根據名稱來查找。          
  • 如果查詢的結果為空,那么會拋出異常。解決方法時,使用required=false  

上述過程說明了@Autowired注解默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在如果允許為null,可以設置它required屬性為false,如果想按照名稱來轉配注入,則需要結合@Qualifier一起使用;

三、 處理使用@Autowired注解出現自動裝配的歧義性問題

使用@Autowired注解的過程中,如果出現NoUniqueBeanDefinitionException異常,大多是因為自動裝配或者其他方式裝配所導致的歧義性.即一個接口存在兩個以上的實現類.即在自動裝配的時候,可能出現因重名問題導致的NoUniqueBeanDefinitionException異常.

@Autowired是按類型進行裝配的,那么我一個接口UserInterface,有多個實現類

AImpl(@service(name="userInterface1")),BImpl(@service(name="userInterface2")

等等這些實現類都加入了Spring容器,當在一個類中使用如下語句:

@Autowired private IUserInterface userInterface;

在下面列舉一下了一下,上述問題以及類似的裝配歧義性解決問題方法.

方法一

首先加上注解@Qualifier來區分不同的實例.通過在實現接口的類上通過value屬性去命名不同的名稱,對於@Repository、@Service 和 @Controller 和 @Component四個注解都有類似value屬性可以設置,例如:

@Service(value="userServiceImpl")
public class UserServiceImpl implements IUserService{

}

@Autowired
@Qualifier("userServiceImpl")
private IUserService userServiceImpl;

方法二

因為一個接口存在兩個以上的實現類,也可以通過標識首選哪個bean,來解決歧義性問題.例如:

@Component
@Primary
public class UserServiceImpl implements IUserService{

}

 

此時,如果引用到了IUserService接口的實現類注入,則首先注入@Promary注解標注的類,但是此時有一個問題,在同一個接口的實現類中,你只能使用一次@Primary,如果對於AImpl和BImpl都使用了@primary,則還是會發生裝配的歧義性.此時,建議使用(1)的方式來解決歧義性問題.

方法三

最后一種方式,可以使用自定義的限定符注解,但是此種情況很少出現,再次就不做介紹,可自行百度.

四、 Spring通過哪些特性實現自動裝配的?

Spring從兩個角度來實現自動化裝配:

(1)組件掃描(component scanning):Spring會自動發現應用上下文中所創建的bean.
(2)自動裝配(autowiring):Spring自動滿足bean之間的依賴.

組件掃描和自動裝配組合在一起就能發揮出強大的威力,它們能夠將你的顯示配置降低到最少.

 

五、@Autowired和@Resource之間的區別

在本文只列舉出@Autowired和@Resource之間常見的表面區別,至於區別的原因需要查看Spring官方文檔中的@Autowired注解實現方式和Java中@Resource注解實現方式.

(1)、@Autowired默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在如果允許為null,可以設置它required屬性為false,如果想按照名稱來轉配注入,則需要結合@Qualifier一起使用;

(2)、@Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean才會按照類型來裝配注入;

(3)、@Resource注解是由J2EE提供,而@Autowired是由spring提供,故減少系統對spring的依賴建議使用@Resource的方式;

(4)、@Resource和@Autowired都可以書寫標注在字段或者該字段的setter方法之上

(5)、@Resource默認按照名稱裝配,當找不到與名稱匹配的bean才會按照類型裝配,可以通過name屬性指定,如果沒有指定name屬 性,當注解標注在字段上,即默認取字段的名稱作為bean名稱尋找依賴對象,當注解標注在屬性的setter方法上,即默認取屬性名作為bean名稱尋找 依賴對象.注意:如果沒有指定name屬性,並且按照默認的名稱仍然找不到依賴的對象時候,會回退到按照類型裝配,但一旦指定了name屬性,就只能按照名稱裝配了.

 

六、Spring是如何啟動自動掃描的

在這里列舉出三種啟動自動掃描的方式.

方式一:此種情況下,針對比較特殊的情形,即項目中運用了SpringBoot,則可以利用@SpringBootApplication注解的方式啟動自動掃描功能.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

方式二:通過XML配置方式,啟動自動掃描功能.XML配置方式

<?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:context="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 http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.tianmaying" />
</beans>

標簽將會開啟Spring Beans的自動掃描,並可設置base-package屬性,表示Spring將會掃描該目錄以及子目錄下所有被@Component標注修飾的類,對它們進行裝配。

方式三:通過Java配置方式,啟動自動掃描功能.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.cn.config")
public class BlogSystemConfig {
    /**
     * 在這里實現java方式的配置,
     */
}

 

在這里給出一個具體的實例:

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "com.cn.config")
public class DataSourceConfig {

    @Bean(name="dataSource")//java配置方式,配置數據源(dataSource)
    public BasicDataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/center_db?useUnicode=true&characterEncoding=UTF-8");
        dataSource.setUsername("postgres");
        dataSource.setPassword("123456");
        dataSource.setInitialSize(5);
        dataSource.setMaxActive(10);
        return dataSource;
    }

}

 

關於@Configuration和@ComponentScan兩個注解:
(1)@Configuration表示這個Java文件是一個配置文件,這類Java代碼的作用在於配置,要和普通的Java代碼區分開發,因此一般我們需要將其放在一個專門的包中,在代碼例子中是com.cn.config。

(2)@ComponentScan表示開啟Spring Beans掃描,類似於XML配置,這里也可以可以設置basePackages屬性。 

如果@ComponentScan注解沒有顯示去給其他的屬性賦值的話,比如此處給basePackages賦值了,如果沒有的話,@ComponentScan注解會掃描與配置類相同的包.

注意:

關於@Repository、@Service 和 @Controller 和 @Component四個注解的使用情形
在持久層、業務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋.這里就是說把這個類交給Spring管理,重新起個名字叫userManager,由於不好說這個類屬於哪個層面,就用@Component.

七、Spring存在幾種裝配方式?

目前,在Spring中,一共提供三種裝配方式:

    (1)基於標注的自動裝配
    (2)基於XML配置的顯式裝配
    (3)基於Java配置的顯式裝配

在實際項目中,一般是上述三種裝備方式都可能存在,不過基於標注的自動裝配方式是在項目中最常用的.通過給Java類增加相應的標注,就能夠啟用Spring隱式的Bean發現機制,並自動完成裝配過程.我們在開發中應該盡可能使用自動裝配,足以應付開發中的絕大多數情況.在某些情況下,基於XML配置和基於Java配置的顯式裝配會有用武之地,比如實例化一個第三方庫中的Bean.這種情況下,Java配置和XML配置我們優先使用Java配置,因為這是一種類型安全的方式,能夠在編譯時就盡早發現錯誤.
關於上述所說的類型安全可以這樣理解:
如果使用字符串的形式,在xml中類名或其他硬編碼方式提供的信息,在開發時是發現不了的,會在運行時拋出異常。而使用Java配置形式,類名或其他硬編碼配置信息寫錯的話,編譯時就會提示錯誤,比如Eclipse中就會提示找不到類的錯誤信息,這就避免了這種情況下的運行時異常,因此是更加安全的.

八、@Configuration 中使用@ Autowired 注解 IDE 報錯

在 Spring Boot 項目中會用 @Configuration 注解來初始化配置, 這時可以通過 @autowired 自動注入封裝好的model對象, 方便使用yml中的配置的數據。
這樣做代碼運行沒問題,通過該對象也可以成功的獲取yml配置文件中的數據,但是 IDE 卻給出 “Could not autowird. No beans of'RedisConfig' type found.” 的錯誤提示。

 
我們手動的在 @Configuration 注解下面添加 @ComponentScan 注解並指定所需model類的包地址就可以解決整個問題了。
原因估計是因為在項目的啟動的最初階段,IDE 還沒有掃描到model類,無法發現對應的 bean ,於是就需要我們手動的給其指定需要掃描的包了。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM