最全的Spring註解詳解

来源:https://www.cnblogs.com/haizai/archive/2019/05/12/10853669.html
-Advertisement-
Play Games

@Configuration : 配置類 == 配置文件,告訴Spring這是一個配置類@ComponentScan(value="com.atguigu",excludeFilters = { @Filter(type=FilterType.ANNOTATION,classes={Controll ...


@Configuration : 配置類 == 配置文件,告訴Spring這是一個配置類
@ComponentScan(value="com.atguigu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
@ComonentScan value : 指定要掃描的包(這個註解可以定義多個)
excludeFilters = Filter[] : 指定掃描的時候按照什麼規則排除那些組件
includeFilters = Filter[] : 指定掃描的時候只需要包含那些組件
useDefaultFilters = false : 表示去掉預設掃描
FilterType.ANNOTATION : 按照註解類型 例如 : Controller.class
FilterType.ASSIGNABLE_TYPE : 按照給定的類型 例如 : UserService.class
FilterType.ASPECTJ : 使用ASPECTJ表達式
FilterType.REGEX : 使用正則指定
FilterType.CUSTOM : 使用自定義規則

自定義規則需要實現TypeFilter介面
public class MyTypeFilter implements TypeFilter {
/**
metadataReader : 讀取到的當前正則掃描的類的信息
metadataReaderFactory : 可以獲取到其他任何類的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
// 獲取當前類註解的信息
AnnotationMetadata annotationMetadate = metadataReader.getAnnontationMetadata();
// 獲取當前正在掃描的類的類信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 獲取當前類資源(類的路徑)
Resource resource = metadataReader.getResource();
// 獲取這個類名
String className = classMetadata.getClassName();
// 自定義匹配規則
if(className.contains("er")) {
return true;
}
return false;
}
}


@ComponentScans(
value {
@ComponentScan(value="com.atguigu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
}, useDefaultFilters = false)
}
) : 裡面可以定義多個@ComponentScan

@Bean : 給容器中註冊一個Bean;類型為返回值的類型,id預設是用方法名作為id

@Scope("") : 表示這個對象或者這個bean的創建作用域範圍(調整作用域).
prototype : 多實例的,ioc容器時並不會調用方法創建對象放在容器中.每次獲取的時候才會調用方法創建對象.
singleton : 單實例的(預設值),ioc容器啟動會調用方法創建對象放到ioc容器中.以後每次獲取就是直接從容器(map.get())中拿.
request : 同一次請求創建一個實例
session : 同一個session創建一個實例

@Lazy : 懶載入
單實例bean,預設在容器啟動的時候創建對象.
懶載入: 容器啟動不創建對象,第一次調用(獲取)Bean創建對象,並初始化.

@Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件給容器中註冊bean(可以放在@Bean上,或者類上)
例如 :
//放在類上統一設置
// 類中組件統一設置,滿足當前條件,這個類中配置的所有bean註冊才能生效.
@Conditional({WindowsCondition.class})
@Configuration

//實現介面Condition
public class LinuxCondition implements Condition {
/**

*/
public boolean matchs(CondititContext context, AnnotatedTypeMetadata metadada) {
// 是否linux系統
// 1. 能獲取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2.獲取類載入器
ClassLoader classLoader = context.getClassLoader();
// 3.獲取當前環境信息
Environment environment = context.getEnvironment();
// 4.獲取到bean定義的註冊類(可以判斷容器中的bean註冊情況,也可以給容器中註冊bean)
BeanDefinitionRegistry registry = context.getRegistry();
// 判斷容器中是否包含bean
boolean definition = registry.containsBeanDefinition("persion");

String property = environment.getProperty("os.name");
if (property.contains("linux")){
return true;
}
return false;
}

}

// 獲取bean名稱
String[] namesForType = applicatinContext.getBeanNamsForType();
// 動態獲取環境變數的值,獲取容器運行環境例如 : windows,liunx
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 獲取操作系統的名稱
String property = environment.getProperty("os.name");

給容器中註冊組件 :
1 : 包掃描+組件標註註解(@Controller/@Service/@Repository/@Component)
2 : @Bean[導入的第三方包裡面的組件]
3 : @Import[快速給容器中導入一個組件]
1) : @Import(要導入到容器中的組件);容器中就會自動註冊這個組件,id預設是組件的全類名(也可以導入多個組件)
2) : ImportSelector : 返回需要導入的組件的全類名數組.
3) : ImportBeanDefinitionRegistrar : 手動註冊Bean到容器中
4 : 使用Spring提供的FactoryBean(工廠Bean)
1) : 預設獲取到的是工廠bean調用getObject創建的對象
2) : 要獲取工廠Bean本身,我們需要給id前面加一個&
&colorFactoryBean

@Import(要導入到容器中的組件 例如 : Color.class) : 方在類上,導入組件,容器中就會自動註冊這個組件,id預設是組件的全類名(也可以導入多個組件)
(2) ImportSelector : 返回需要導入的組件的全類名數組.
例如 :
//自定義邏輯返回需要導入的組件
public class MyImportSelector implements ImportSelector {
// 返回值,就是導入到容器中的組件全類名
// AnnotationMetadata : 當前標註@Import註解的類的所有註解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 方法不要返回null值
return new String[];
}
}
@Import({Color.class,Red.class,MyImportSelector.class})
(3) ImportBeanDefinitionRegistrar : 手動註冊Bean到容器中
例如 :
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
// AnnotationMetadata : 當前類的註解信息
// BeanDefinitionRegistry : BeanDefinitionRegistry註冊類;
// 把所有需要添加到容器中的bean : 調用 BeanDefinitionRegistry.registryBeanDefinition手工註冊進來
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
// 通過bean名稱,判斷bean是否在容器中
booean definition = registry.containsBeanDefinition("red");
boolean definition1 = registry.containsBeanDefinition("blue");
if (definition && definition1) {
// 指定bean定義信息 : (Bean的類型,Bean...)
RootBeanDefinition bean = new RootBeanDefinition(RainBow.class);
// 註冊一個Bean,指定Bean名
registry.registryBeanDefinition("rainBow", bean);
}
}
}

4 : 例子 :
// 創建一個Spring定義的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一個Color對象,這個對象會添加到容器中
@Override
public Color getObject() throws Exception {
return new Color();
}

public Class<?> getObjectType() {
return Color.class;
}

//是單例?
//true : 這個bean是單例,在容器中保存一份
//false : 多實例,每次獲取都會創建一個新的bean
@Override
public boolean isSingleton() {
return false
}
}

@Bean
public ColorFactoryBean getBean() {
return new ColorFactoryBean();
}

public void test() {
//工廠Bean獲取的是調用getObject創建的對象;實際上獲取的是Color對象
Object bean2 = applicatinContext.getBean("colorFactoryBean");
//這個是獲取的ColorFactoryBean對象,因為在FactoryBean介面中定義了一個字元串,表示以&開頭的就是獲取實現FactoryBean介面的對象
Object bean3 = applicatinContext.getBean("&colorFactoryBean");
}
Bean的生命周期
bean創建 -- 初始化 -- 銷毀的過程
容器管理bean的生命周期 :
我們可以自定義初始化和銷毀方法;容器在bean進行到當前生命周期的時候來調用我們自定義的初始化和銷毀的方法
構造(對象創建)
單實例 : 在容器啟動的時候創建對象
多實例 : 在每次獲取的時候創建對象

BeanPostProcessor.postProcessBeforeInitialization
初始化 :
對象創建完成,並賦值好,調用初始化方法...
BeanPostProcessor.postProcessInitialization

銷毀 :
單實例 : 容器關閉的時候
多實例 : 容器不會管理者bean,容器不會調用銷毀方法.

遍歷得到容器中所有的BeanPostProcessor : 挨個執行beforeInitialization,一旦返回null,跳出for迴圈,不會執行後面的BeanPostProcessor.postProcessBeforeInitialization

BeanPostProcessor的原理
populateBean(beanName, mdb, instanceWrapper) : 給bean進行屬性賦值
initializeBean
{
appliyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
}

1) : 指定初始化和銷毀方法:
通過@Bean指定init-method和destory-method;
2) : 通過讓Bean實現InitializingBean(定義初始化邏輯),DisposableBean(定義銷毀邏輯)
3) : 可以使用JSR250;
@PostConstruct : 在bean創建完成並且屬性賦值完成;來執行初始化方法(在對象創建並賦值之後調用)
@PreDestroy : 在容器銷毀bean之前通知我們進行清理工作.

例如 :
public class Dog{
public Dog() {
System.out.println("");
}

//對象創建並賦值之後調用
@PostConstruct
public void init() {
System.out.println("11");
}

//容器移除對象之前
@PreDestroy
public void detory(){
}
}
4) : BeanPostProcessor[interface] : bean後置處理器;
在bean初始化前後進行一些處理工作;
postProcessBeforeInitialization : 在初始化之前工作
postProcessInitialization : 在初始化之後工作

Spring底層對BeanPostProcessor的使用 :
bean賦值,註入其他組件,@Autowired,生命周期註解功能。@Async, xxx BeanPostProcessor;

@Value : 給屬性賦值。
1. 基本數值 例如 : @Value("111")
2. 可以寫SpEL. 例如 : @Value("#{20-2}")
3. 可以寫${},取出配置文件中的值(在運行環境變數裡面的值) 例如 : @Value("${name}")
@PropertySource讀取外部配置文件中的k/v保存到運行的環境變數中;載入完外部的配置文件以後使用${}取出配置文件的值。
例如 :
AnnotationConfigApplicationContext applicatinContext = new AnnontationConfigApplicationContext();
pringBeans(applicationContext);
Person person = (Person)applicationContext.getBean("person");
ConfigurableEnvironment environment = applicatinContext.getEnvironment();
// 這是根路徑下的.properties配置文件中的k/v值
Sting property = environment.getProperty("person.nickName);
applicatinContext.close();

自動裝配 :
Spring利用依賴註入(DI),完成對IOC容器中各個組件的依賴關係賦值;
1) . 預設優先按照類型去容器中找對應的組件 : applicationContext.getBean(BookDao.class);找到就賦值
2) . 如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找
3) . @Qualifier("bookDao") : 使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名。
4) . 自動裝配預設一定要將屬性賦值好,沒有就會報錯。(可以通過更改屬性值.例如 : @Autowired(required=false);這樣就在沒有這個組件時,不會進行自動裝配)
5) . @Primary : 讓Spring進行自動裝配的時候,預設使用首選的bean;
也可以繼續使用@Qualifier指定需要裝配的bean的名字。
applicatinContext.getBean("bookDao");
BookService{
@Autowired
BookDao bookDao
}
(2):Spring還支持使用@Resource(JSR250)和@Inject(JSR330)【Java規範的註解】
@Resource
可以和@Autowired一樣實現自動裝配功能;預設是按照組件名稱進行裝配的;
沒有能支持@Primary功能沒有支持 @Autowired(reqiured = false);
@Inject
需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;
@Autowired : Spring定義的; @Resouce和@Inject都是java規範。
Spring的@Autowired的底層使用AutowiredAnnotationBeanPostProcessor : 解析完成自動裝配功能。
(3):@Autowired : 構造器,參數,方法,屬性
@Componetnt : 預設載入ioc容器中的組件,容器啟動會調用無參構造器創建對象,再進行初始化賦值等操作
1): 標註在方法位置 : @Bean + 方法參數;參數從容器中獲取;預設不寫@Autowired效果是一樣的,都能自動裝配
2): 標註在構造器上 : 如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件換是可以自動從容中獲取.
3):標註在參數位置
@Bean標註的方法創建對象的時候,方法參數的值從容器中獲取。
(4) : 自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx);自定義組件實現xxxAware;在創建對象的時候,會調用介面規定的方法註入相關組件;Aware
把Spring底層一些組件註入到自定義的Bean中;
xxxAware: 功能使用xxxProcessor;
ApplicationContextAware ==> ApplicationContextAwareProcessor;
@Profile : 指定組件在哪個環境的情況下才能被註冊到容器中。
1) : 加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中。預設是default環境。
2) : 寫在配置上,只有是指定的環境的時候,整個配置類裡面的所有配置才能開始生效。

激活方式 :
(1) : 使用命令行動態參數 : 在虛擬機參數位置載入 -Dspring.profiles.active=test
(2) :代碼的方式激活某種環境。
(3) : 沒有標註環境標識的bean在任何環境下都是載入的。
例如 :
AnnotationConfigApplicationContext applicatinContext = new AnnontationConfigApplicationContext();
//1。創建一個applicationContext
//2. 設置需要激活的環境
applicatinContext.getEnvironment().setActiveProfiles("dev");
//3.註冊主配置類
applicatinContext.registry(MainConfigOrProfile.class);
//4.啟動刷新容器
applicatinContext.refresh();









您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 新聞 "介紹.NET 5" "發佈.NET Core 3.0預覽版5以及F 的REPL" "OpenFsharp CFP開啟" "F 的Giraffe服務端stub生成器被添加到openapi generator中" "FsToolkit.ErrorHandling現在支持TaskResult" " ...
  • python初體驗 ——>>> 模擬體育競技 一、排球訓練營 1. 簡介: 模擬不同的兩個隊伍進行排球的模擬比賽。 2. 模擬原理: 通過輸入各自的能力值(Ⅰ),模擬比賽的進行( P ),最後輸出模擬的結果( O )。 P 簡介:通過產生隨機數得到每局比賽的難度,若小於能力值則表示贏得本局比賽,反之 ...
  • 背景 由於項目的新版本有大改動,需求是將一些舊表的數據轉移到新表來,於是使用PHP寫了數據腳本,對MySQL的數據進行讀取,計算,轉移,插入等處理,實現千萬級別數據的計算和轉移。這裡面也遇到一些問題,這裡做下總結: 需求 將幾個舊表的數據拷到新表來,有些欄位發生了變化,有些欄位的值需要計算; 單表數 ...
  • #while print('111')while true: print('我們不一樣') print('在人間') print('光輝歲月')print('222'),,,,,,count = 1flag = true while flag: print(count) count = count ...
  • leepcode 作業詳解 1、給定一個整數數組,判斷是否存在重覆元素。如果任何值在數組中出現至少兩次,函數返回 true。如果數組中每個元素都不相同,則返回 false。 正確解答 第一次用字典去解題,出現bug,雖然在pycharm裡面代碼運行正常,但是leepcode顯示錯誤。 2、給定一個整 ...
  • 引入依賴: 啟動類上添加@EnableFeignClients註解: 寫調用介面: 直接@Autowired註入服務調用介面: 底層使用了動態代理,對介面進行了實現。 並且封裝了RestTemplate遠程調用的代碼。 測試: 搞定~ 補充知識點: ...
  • 力扣題目彙總 1.兩數之和 1.題目描述 給定一個整數數組 和一個目標值 ,請你在該數組中找出和為目標值的那 兩個 整數,並返回他們的數組下標。 你可以假設每種輸入只會對應一個答案。但是,你不能重覆利用這個數組中同樣的元素。 示例: 2.解答 2.迴文數 1題目描述 示例 1: 示例 2: 示例 3 ...
  • 文/開源智造聯合創始人老楊 本文來自《OdooERP系統部署架構指南》的試讀章節。書籍尚未出版,請勿轉載。歡迎您反饋閱讀意見。 從web瀏覽器到PostgreSQL,多層與其他層交互以處理數據 單伺服器架構 易於理解和部署,這是最常見的情況。一個實例或多個實例 多伺服器架構 更難部署和維護,需要更高 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...