1. 程式人生 > >Spring原始碼學習[email protected]註解和啟動自動掃描的三種

Spring原始碼學習[email protected]註解和啟動自動掃描的三種

引用文章地址:

前言:

@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)的方式來解決歧義性問題.

<4>方法三

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

四、 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中就會提示找不到類的錯誤資訊,這就避免了這種情況下的執行時異常,因此是更加安全的.

相關推薦

Spring原始碼學習<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3b16167b7a4e4f544c52495e5f">[email&#160;protected]a>註解啟動自動掃描

引用文章地址: 前言: @Autowired註解程式碼定義 @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,

spring boot 原始碼解析<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="37060e1a77745859535e435e5859565b">[email&#160;protected]a>

前言 之前在分析spring boot 原始碼時匯出可見@ConditionalOnBean 之類的註解,那麼它到底是如何使用的以及其工作流程如何,我們這裡就圍繞以下幾點來分析: @Conditional系列與Condition的關係 @Condition

Spring學習<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f1dddfc2dddcd7dcc6e1d1d3dc">[email&#160;protected]a>註解

Spring的配置主要有兩種方式,一種是基於xml配置檔案,另一種是基於JavaConfig註解配置,由於基於註解的配置能夠保證型別安全,使用起來更加方便,得到了越來越多使用者的青睞。@ComponentScan是一個使用非常頻繁的註解,該類的作用使得Spring定義Bean

Spring高級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email&#160;protected]a>***註解的工作原理

sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe

spring <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="62000d0d16222103010a0703000e07">[email&#160;protected]a>中value的理解

先看原始碼 /** * Names of the caches in which method invocation results are stored. * <p>Names may be used to determine the target cache (or cac

SpringBoot學習<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b7e8f7e7c5d8c7d2c5c3cee4d8c2c5d4d2">[email&#160;protected]a>&am

文章目錄 @PropertySource:載入指定的配置檔案 @ImportResource:匯入Spring的配置檔案,讓配置檔案裡面的內容生效; @Bean @PropertySource:載入指定的配置檔案

Spring Boot入門篇<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cde08d9fa8bcb8a8beb99dacbfaca0">[email&#160;protected]a>/@Req

請求引數註解問題 當前臺介面使用GET或POST方式提交資料時,資料編碼格式由請求頭的ContentType指定。 分為以下幾種情況: application/x-www-form-urlencoded 這種情況的資料@RequestParam、@Mode

spring宣告式事務管理方式( 基於txaop名字空間的xml配置<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0922495d7b68677a686a7d6066676865">[email&#

轉自:https://www.cnblogs.com/niceyoo/p/8732891.html 1. 宣告式事務管理分類 宣告式事務管理也有兩種常用的方式, 一種是基於tx和aop名字空間的xml配置檔案,另一種就是基於@Transactional註解。 顯然基於註解的方式更簡單

Spring】@<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4b0824253f392427272e390b192e3a3e2e383f062a3b3b22252c">[email&#160;pr

一 淺顯的感性理解 向瀏覽器宣告 @Controller 其作用簡單來說就是對瀏覽器宣告,此類為控制器類 @ResponseBody 作用在方法上,表明此函式返回的內容直接寫入HTTP Response物件 @RestController 是@ResponseBo

spring事務(4)-----複習<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3a494a4853545d7a7b4f4e554d53485f5e">[email&#160;protected]<

什麼是註解 傳統的Spring做法是使用.xml檔案來對bean進行注入或者是配置aop、事物,這麼做有兩個缺點: 1、如果所有的內容都配置在.xml檔案中,那麼.xml檔案將會十分龐大;如果按需求分開.xml檔案,那麼.xml檔案又會非常多。總之這將導致配置檔案的可讀性與可維護性變得很低 2、在開發中

Spring中@<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c1a2aeafb5b3aeadada481b2a4b3b7a8a2a4">[email&#160;protected]a>@<a h

我是一名Spring 小白 跟單位的小牛牛學習spring框架,總結以下 @controller 控制器(注入服務) 用於標註控制層,相當於struts中的action層 @service 服務(注入dao) 用於標註服務層,主要用來進行業務的邏輯處理 @re

spring <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e5878a8a91a5a08b84878980bdbdbdbd">[email&#160;protected]a>註解程式設計模型分析

@EnableXXXX程式設計模型 在spring boot中,@EnableXXX註解的功能通常是開啟某一種功能。根據某些外部配置自動裝配一些bean,來達到開啟某些功能的目的。光說很抽象,要具體分析。 @Enable模型的實現方式基本有3種。一個基本的@

Spring boot使用總結()校驗<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="311c1c717f5e45735d505f5a">[email&#160;protected]a> 使用

spring boot 1.4預設使用 hibernate validator 5.2.4 Final實現校驗功能。hibernate validator 5.2.4 Final是JSR 349 Bean Validation 1.1的具體實現。 一 初步使用

Spring註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7e53533e2e0c111817121b">[email&#160;protected]a>的使用

@Profile的作用:當容器根據標識啟用對應的@Profile註解時,其所關聯的bean類才會註冊到容器。但容器不能或找不到對應的@Profile,就不生成bean例項。 建立配置類MainConf

Spring註解開發<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="96a5bbbbd6dffbe6f9e4e2">[email&#160;protected]a> , FacotryBean 註冊

目錄 @ComponentScan註解用於掃描自己寫的類(@Controller,@Service,@Component,@Repository),用於加入IOC容器中 @Bean 可以把其他包或者自己寫的類加到IOC容器中 @Import 也可以辦

Spring 註解中 @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="622c0d162c170e0e222c0d16270f12161b">[email&#160;protected]a>,@N

首先要清楚的是下邊1,2,3; 且空格是有長度的: 1  @NotNull:不能為null,但可以為empty,沒有Size的約束 2  @NotEmpty :不能為null,且Size>0 3  @NotBlank:只用於String,不能為null且trim()之

Spring中Bean的生命週期之<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="476a6a6a6a6a0705222629">[email&#160;protected]a>方法進行物件的初始化

方法:通過@Bean指定init-method和destroy-method; 注:單例項和原型模式物件的建立時間和初始化銷燬的時間順序不同。 一、單例項模式 1、建立Car例項物件,並建立初始化和銷燬方法 package com.atguigu.bean; imp

spring給容器中註冊元件的幾方式,1.包掃描+元件標註註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0634284664636768">[email&#160;protected]a>(

              給容器中註冊元件;        1)、包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)[

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="95d8d0d6d5dfd4c3d4">[email&#160;protected]a>@入門學習@03

Java與C語言的幾點異同 八大基本型別 首先由在C語言中就接觸過的六種型別:char、short、int、long、float、double, 以及初具Java特色的兩種型別:byte和boolean, 其中boolean型別是布林型,其取值只有兩種,true和fa

SpringSpring高階話題-計劃任務<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a68be6e3c8c7c4cac3f5c5cec3c2d3cacfc8c1">[email&#160;pr

進行本示例的演示,需要先配置好Maven和spring哦、 見:  http://blog.csdn.net/qq_26525215/article/details/53010442 分析 要實現計劃任務,首先通過在配置類註解@EnableScheduling來開