Spring核心技術--IoC container用法詳解
一直在使用Spring提供的IoC容器, 但是始終沒有系統化的梳理一下. 今天在這裡寫下, 也是以備以後參考之用.
Ioc container的核心是BeanFactory
介面, 它提供的方法能夠管理任何型別的物件. ApplicationContext
是它的子介面, 集成了Spring AOP的特性.
BeanFactory or ApplicationContext?
BeanFactory目前只是Spring為了維持向後相容性而保留的介面, 任何新開發的框架或者程式應該使用
ApplicationContext
而不是BeanFactory
.
那麼ApplicationContext
BeanFactory
提供了哪些好處呢? 簡單的來說就是很多增強的功能, 更細粒度的干預bean生命週期的定製, AOP, 國際化, 事件支援等, 詳見下表:
所有的bean在使用前都需要在ApplicationContext
註冊(register), 常用的有以下幾種形式:
- xml形式定義的;
- 註解定義;
- Java Config
- 手動註冊在Spring容器之外例項化的bean;
Dependency Injection的實現方式
一共有三種方法: 構造器注入, 設值注入和方法注入. 構造器注入在設值注入之前.
- 構造器注入: 注入強制性的依賴.
- 設值注入: 注入可選依賴或配置(例如
@ConfigurationProperties
@Required
標識, 就會變成一個強制性依賴. - 方法注入: 通常是在bean構造後對bean進行增強設定.
Constructor-based
構造器注入是推薦的方式, 能夠實現一個immutable的bean, 確保所有的依賴不是
null
. 並能夠保證呼叫者使用時, 依賴是例項化完成的.
無需提供getter/setter方法.
setter-based
設值注入應被僅用於注入可選依賴, 或者是能夠被賦予預設值的依賴.
使用設值注入的好處是, 能夠在之後通過setter
方法進行注入的變更, 在JMX MBeans管理上必須使用此種方式.
方法注入
下面是一個例子:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired // 自動注入--方法注入引數auth, 對已建立的AuthenticationManagerBuilder型別的bean進行增強.
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("USER");
}
}
依賴解析步驟
如果bean是單例的, 並且被標註為pre-instantiated(預設就是這個)會在容器建立的時候被建立. 否則的話會按需建立.
lazy-initialized beans
通常來講單例bean會在容器建立的時候初始化, 並且會按照依賴關係順次進行初始化, 但是你也可以通過指定
lazy-init=true
到某個bean
上使其在第一次使用的時候才被初始化.
注意: 即使某個bean開啟了lazy-init, 也不一定是延遲初始化的, 因為如果依賴它的bean是單例的, 且沒有開啟延遲初始化, 那麼Spring容器為了保證準確性, 會將這個bean也立即初始化.
Bean作用域(Bean Scopes)
bean一共有七種作用域:
作用域 | 描述 |
---|---|
singleton | 預設, 單例, 通常用於無狀態bean, 如dao. service, controller等 |
prototype | 原型, 每次呼叫產生一個新的例項, 通常用在domain object上. 相當於java的new 關鍵字, Spring在例項化bean之後, 執行完initialization lifecycle callback, 之後就不在負責這個bean的生命週期了, 完全交給客戶端負責 |
request | HTTP 請求範圍 |
session | HTTP Session範圍 |
application | 和ServletContext 的生命週期一致, 也就是web應用的範圍 |
websocket | 和一個WebSocket 的生命週期一致 |
request, session, application, websocket作用域
這些作用域需要執行緒與Http Request或者Http Sesson物件繫結. 當使用Spring MVC時, 自動繫結.
使用以下註解在bean上顯式指定:
- @RequestScope
- @SessionScope
- @ApplicationScope
application scope
是ServletContext
級別的, 作為一個ServletContext
的attribute存取, 這個範圍非常像singleton範圍, 但是有以下兩點主要區別:
- 它是與
ServletContext
繫結, 不是與ApplicatinContext
繫結. 一個ServletContext
可以有多個ApplicationContext
. 也就是說, application scope的bean是與ApplicationContext
平行的, 二者都是ServletContext
的一個屬性. - 它是
ServletContext
的一個屬性.
代理
一般有兩種型別:
- interface-based proxy, 典型的是JDK內建的動態代理
- 一種是inherated-based proxy, 典型的是CGLIB
interface-based proxy
優點是不需要引入額外的庫依賴, 缺點是想要代理的方法必須是在被代理類實現的介面中定義的.
inherated-based proxy
缺點是需要引入額外依賴, 優點是可以代理所有的共有型別方法.
Bean生命週期(lifecycle)
- initialization callback 使用
@PostConstruct
- destruction callback 使用
@PreDestroy
以下是一個使用的例子:
public class CachingMovieLister {
@PostConstruct // 該方法會在bean初始化之後被回撥
public void populateMovieCache() {
// populates the movie cache upon initialization...
}
@PreDestroy // 該方法會在容器銷燬bean之前被回撥
public void clearMovieCache() {
// clears the movie cache upon destruction...
}
}
Startup and shotdown callbacks
是容器啟動和容器停止的回撥, 發生在所有的bean建立之前和銷燬之前.
優雅的關閉非web應用下的Spring IoC容器
需要為ApplicationContext
在JVM裡註冊一個shutdown hook. 這會確保所有自定義的destroy
方法被正確呼叫.
ApplicationContextAware and BeanNameAware
是bean用來感知容器存在的介面, 通常不需要實現這個介面, 因為通常bean是不需要顯式感知容器的存在的, 而且這樣做會導致與Spring框架耦合.
使用註解指導依賴注入
@Autowired
@Autowired
是按照注入的型別名進行依賴查詢, 當同一個型別有多種實現bean的時候, 產生歧義並報錯.
@[email protected]
當有兩個以上相同型別的bean時, 單獨的@Autowired
會產生歧義, 可以用額外的@Qualifier("這裡是bean的名字")
註解按bean的名字進行注入.
@Resource
相當於@Autowired
+@Qualifire
的組合.
自定義@Qualifier
@Qualifier
註解支援繼承, 這樣我們就可以擴充套件@Qualifier
的語義, 進行更細力度的@Quelifier
定義, 例如:
// 擴充套件@Quelifier語義
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Offline {
}
@Configuration
public class MovieConfiguration {
@Bean
@Offline // 使用自定義的@Qualifier子類區分bean
public MovieCatalog firstMovieCatalog() { ... }
@Bean
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
public class MovieRecommender {
@Autowired
@Offline // 根據自定義的@Qualifier子類注入bean
private MovieCatalog offlineCatalog;
// ...
}
下面是一個更復雜的例子:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {
String genre();
Format format();
}
public enum Format {
VHS, DVD, BLURAY
}
public class MovieRecommender {
@Autowired
@MovieQualifier(format=Format.VHS, genre="Action")
private MovieCatalog actionVhsCatalog;
@Autowired
@MovieQualifier(format=Format.VHS, genre="Comedy")
private MovieCatalog comedyVhsCatalog;
@Autowired
@MovieQualifier(format=Format.DVD, genre="Action")
private MovieCatalog actionDvdCatalog;
@Autowired
@MovieQualifier(format=Format.BLURAY, genre="Comedy")
private MovieCatalog comedyBluRayCatalog;
// ...
}
使用Java Config指導依賴注入
核心是使用@Configuration
和@Bean
註解.
@Bean
@Bean是一個方法級的註解, 它的返回值將作為一個singleton的bean註冊到spring的IoC容器中.
如果一個@Bean
的建立依賴於其他bean的建立, 那麼需要將所有依賴作為方法的引數, 會觸發類似@Autowired
的效果.
下面是一個例子:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
這種配置方式特別像contructor-based注入, 可以參照理解
@Configuration
所有的通過
@Bean
方式手動建立bean, 都建議在@Configuration
的類中進行定義.
@Configuration
標註的類會在執行時被CGLIB動態代理, 所有對原類方法的呼叫都會被攔截.
這個動態代理做了以下重要的事:
- 通過快取singleton bean, 防止原類中重複例項化同一個名字的singleton bean.
@Import
@Import
是用來組合多個@Configuration
的定義. 使通過Java Config進行手動bean定義的配置檔案集中到一起.
下面是一個使用@Configuration
+ @Import
進行跨檔案bean組裝的例子:
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
組合xml, 註解, Java Config形式的依賴注入
只需要在一個@Configuration
類上加上@ImportResource
註解即可, 以下是一個例子:
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
// 正常的bean定義
}
Environment abstraction
環境允許通過定義多個profile檔案, 允許在不同環境(開發, 測試, 生產)使用不同的配置.
下面是一個例子:
@Configuration
@Profile("dev")
public class StandaloneDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
@Configuration
@Profile("production")
public class JndiDataConfig {
@Bean(destroyMethod="")
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}
想要啟動一個特定的配置, 在全域性配置中加上如下屬性設定即可:
# 啟用dev profile
spring.profiles.active=dev
除此以外, 我們還可以提供個一個預設的profile:
@Configuration
@Profile("default")
public class DefaultDataConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.build();
}
}
上述配置在沒有顯式指定spring.profiles.active
時自動啟用.
小結
以上.
參考連結:
相關推薦
Spring核心技術--IoC container用法詳解
一直在使用Spring提供的IoC容器, 但是始終沒有系統化的梳理一下. 今天在這裡寫下, 也是以備以後參考之用. Ioc container的核心是BeanFactory介面, 它提供的方法能夠管理任何型別的物件. ApplicationContext是它的
SPRING MVC 中的 MULTIACTIONCONTROLLER 用法詳解 (轉載)
http://www.blogjava.net/wuhen86/articles/288966.html Spring MVC 中 Controller 的層次實在是多,有些眼花繚亂了。在單個的基礎上,再新加兩三個叫做豐富,再多就未必是好事,反而會令人縮手新聞片腳,無
Spring筆記(9) - IOC實現方式詳解
IOC概念 控制反轉(Inversion of Control,IOC),是面向物件程式設計中的一種設計原則,它建議將不需要的職責移出類,讓類專注於核心職責,從而提供鬆散耦合,提高優化軟體程式設計。它把傳統上由程式程式碼直接操控的物件的呼叫權(new、get等操作物件)交給容器,通過容器來實現物件元
spring(7)---深入理解Spring核心技術——Spring中的各模組詳解
深入理解Spring核心技術——Spring中的各模組詳解 Spring框架的兩個基本概念IOC容器和AOP,相信大家現在對Spring中的這兩個部分的基本概念有了一定的認識,好了,那麼今天我們就來正式的進入Spring框架的學習了。 前面提到過,
Spring之IOC、核心容器和Bean概念詳解
這一週忙了很多與程式碼無關的事,感覺心態上還是有些急躁,週中挑幾個晚上看了一些文章,上午起來總結了一下,下午開始寫部落格,因為沒有時間擼程式碼,所以就打算先把看到的概念梳理梳理,磨刀不誤砍柴工。 首先來看一看什麼是IOC,他的全稱是Inversion of Co
Spring核心思想,IoC與DI詳解(如果還不明白,放棄java吧)
1.IoC是什麼? IoC(Inversion of Control)控制反轉,IoC是一種新的Java程式設計模式,目前很多輕量級容器都在廣泛使用的模式。 2.IoC解決了什麼問題? 在IoC出現以前,元件之間的協調關係是由程式內部程式碼來控制的,或者說,以前我們使用New關鍵字來實現兩組
Spring MVC 學習筆記(二):@RequestMapping用法詳解
一、@RequestMapping 簡介 在Spring MVC 中使用 @RequestMapping 來對映請求,也就是通過它來指定控制器可以處理哪些URL請求,相當於Servlet中在web.xml中配置 <servlet>
Spring AOP用法詳解
trace 方法名 java 範式 advice work 配對 中文翻譯 roc 什麽是AOP AOP:Aspect Oriented Programming,中文翻譯為”面向切面編程“。面向切面編程是一種編程範式,它作為OOP面向對象編程的一種補充,用於處理系統中分布於
Spring中@Async用法詳解及簡單例項
Spring中@Async用法 引言: 在Java應用中,絕大多數情況下都是通過同步的方式來實現互動處理的;但是在處理與第三方系統互動的時候,容易造成響應遲緩的情況,之前大部分都是使用多執行緒來完成此類任務,其實,在spring 3.x之後,就已經內建了@Async來完美解決這個問題,本文將完成
Spring MVC的一些關於請求的註解用法詳解
這段時間一直在著手於RESTful風格的介面設計。springmvc的RESTful風格的url是通過@RequestMapping 及@PathVariable annotation提供的。為此我好好研究了一下關於Springmvc請求這方面的內容,也借鑑了前人的
Spring框架 IOC(原理詳解)(一)
一、Spring開源框架的簡介 Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中闡述的部
Spring核心技術(一)——IoC容器和Bean簡介
IoC容器和Bean簡介 這章包括了Spring框架對於IoC規則的實現。Ioc也同DI(依賴注入)。而物件是通過建構函式,工廠方法,或者一些Set方法來定義物件之間的依賴的。容器在建立這些Bean物件的時候同時就會注入這些依賴。這個過程是根本上的反轉了,不再
Spring Boot中@RequestMapping 用法詳解之地址對映(轉)
引言 前段時間使用springboot來開發專案,並且需要使用到傳輸JSON資料,並且踩了很多坑,無意中找到了這篇文章,詳細的說明了@RequestMapping的使用 簡介: @RequestMapping RequestMappin
spring RestTemplate用法詳解
前面介紹過Spring的MVC結合不同的view顯示不同的資料,如:結合json的view顯示json、結合xml的view顯示xml文件。那麼這些資料除了在WebBrowser中用JavaScript來呼叫以外,還可以用遠端伺服器的Java程式、C#程式來呼叫。也就是說現
JavaEE基礎(02):Servlet核心API用法詳解
本文原始碼:GitHub·點這裡 || GitEE·點這裡 一、核心API簡介 1、Servlet執行流程 Servlet是JavaWeb的三大元件之一(Servlet、Filter、Listener),它屬於動態資源。Servlet的作用是處理請求,伺服器會把接收到的請求交給Servlet來處理,在Se
Spring IoC getBean 方法詳解
前言 本篇文章主要介紹 Spring IoC 容器 getBean() 方法。 下圖是一個大致的流程圖: 正文 首先定義一個簡單的 POJO,如下: public class User { private Long id; private String name; pu
Spring IoC createBean 方法詳解
# 前言 本篇文章主要分析 Spring IoC 的 `createBean()` 方法的流程,以及 `bean` 的生命週期。 下面是一個大致的流程圖: ![Spring IoC createBean 方法流程.png](http://ww1.sinaimg.cn/large/006Vpl27gy1g
Spring IoC @Autowired 註解詳解
# 前言 本系列全部基於 `Spring 5.2.2.BUILD-SNAPSHOT` 版本。因為 Spring 整個體系太過於龐大,所以只會進行關鍵部分的原始碼解析。 我們平時使用 Spring 時,想要 **依賴注入** 時使用最多的是 `@Autowired` 註解了,本文主要講解 Spring 是如
Spring IoC 公共註解詳解
# 前言 本系列全部基於 `Spring 5.2.2.BUILD-SNAPSHOT` 版本。因為 Spring 整個體系太過於龐大,所以只會進行關鍵部分的原始碼解析。 什麼是公共註解?公共註解就是常見的Java註解,特別是JSR-250中的註解。例如:`@Resource`、`@PostConstruct
JavaScript中return的用法詳解
style 返回 www log tle blog 意思 charset fun 1、定義:return 從字面上的看就是返回,官方定義return語句將終止當前函數並返回當前函數的值,可以看下下面的示例代碼: <!DOCTYPE html><html l