Spring IoC的一點(diǎn)總結(jié)

1. 前言

Spring IoC(Inversion of Control萝招,控制反轉(zhuǎn))和 AOP(Aspect Orient Programming反症,面向切面編程)是Spring的兩大核心辛块,本文聊聊對Spring Ioc的一點(diǎn)點(diǎn)理解。

IoC又稱為DI(Dependency Injection铅碍,依賴注入)润绵,當(dāng)A對象依賴B對象時(shí),并不是由A對象直接創(chuàng)建B對象胞谈,而是由Spring創(chuàng)建B對象尘盼,并注入到A對象中,最終實(shí)現(xiàn)了解耦烦绳。

2. 依賴注入的方式

依賴注入的方式常用的包括:構(gòu)造器注入卿捎、屬性(setter)注入,其中最常用的是屬性(Setter)注入爵嗅。在討論依賴注入之前,我們先來認(rèn)識@Resource和@Autowired注解笨蚁。

2.1 @Resource和@Autowired

  1. @Resource和@Autowired都可以用來裝配Bean睹晒,二者都可以作用在類的屬性(域)和setter方法上趟庄;@Autowired還可以作用在構(gòu)造器上,@Resource則不可以伪很。

  2. @Resource為JSR-250標(biāo)準(zhǔn)的注解戚啥,屬于J2EE的,使用該注解可以減少代碼和Spring的耦合锉试;@Autowired是Spring定義的注解猫十。

  3. @Autowired默認(rèn)按照類型來裝配Bean,默認(rèn)情況下呆盖,必須要求依賴對象存在拖云;如果要允許null,可以設(shè)置它的required屬性為false应又,例如@Autowired(required=false) 宙项。如果想要使用name(名稱)來裝配Bean,需要配合@Qualifier一起使用株扛。下面是@Autowired使用的例子尤筐。

     @Autowired(required = true) 
     @Qualifier("baseDao")
     private BaseDao baseDao;
    
  4. @Resource默認(rèn)按照名稱來裝配Bean,如若沒有指定名稱洞就,則按照屬性名稱來查找盆繁;當(dāng)無法通過名稱找到匹配的Bean時(shí),才按照類型裝配旬蟋。如果name屬性一旦指定油昂,就只會按照名稱來裝配Bean。下面是@Resource使用的例子咖为。

     @Resource(name="baseDao")
     private BaseDao baseDao;
    

和@Resource相關(guān)的秕狰,還有兩個(gè)注解,分別是@PostConstruct和@PreDestroy躁染。在方法上加上注解@PostConstruct鸣哀,這個(gè)方法就會在Bean初始化之后被Spring容器執(zhí)行;在方法上加上注解@PreDestroy吞彤,這個(gè)方法就會在Bean銷毀前被Spring容器執(zhí)行我衬。

2.2 構(gòu)造器注入

在構(gòu)造器上使用@Autowired和@Qualifier注入依賴Bean。前面已經(jīng)提到了饰恕,@Resource不能作用在構(gòu)造器上挠羔。

@Repository
public class CustomerDao extends SqlMapClientDaoSupport {

    @Autowired(required = true)
    public CustomerDao(@Qualifier(value="sqlMapClient4A") SqlMapClient sqlMapClient) {
        super.setSqlMapClient(sqlMapClient);
    }
}

2.3 屬性注入(setter注入)

在類的域上,或者該域的setter方法上使用@Autowired或者@Resource注解埋嵌,注入依賴對象破加。

@Service
public class UserService {

    @Resource(name="userDao")
    private UserDao userDao;

    public User QueryUser(String id){
        return userDao.selectById(id);
    }
    /* setter注入要多寫一個(gè)方法,沒有屬性注入寫著方便雹嗦。
    @Resource(name="userDao")
    public UserDao setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    */
}

3. Spring容器

Spring容器管理的基本單位是Bean范舀,Bean可以是任何的java對象合是。Spring負(fù)責(zé)創(chuàng)建這些Bean的實(shí)例,管理Bean的生命周期锭环,也管理Bean和Bean之間的依賴關(guān)系聪全。

Spring容器最核心的兩個(gè)接口是BeanFactory和ApplicationContext。BeanFactory負(fù)責(zé)配置辅辩、創(chuàng)建和管理Bean难礼;ApplicationContext繼承了BeanFactory接口,被稱為Spring上下文玫锋。觀察Spring Boot Web工程的啟動(dòng)日志可以發(fā)現(xiàn)蛾茉,使用的是AnnotationConfigEmbeddedWebApplicationContext,看名字就知道是ApplicationContext的一個(gè)實(shí)現(xiàn)景醇。

BeanFactory包含的基本方法

// 根據(jù)Bean的name返回Bean對象
Object getBean(String name) throws BeansException;

// 根據(jù)Bean的name和requiredType返回Bean對象
<T> T getBean(String name, Class<T> requiredType) throws BeansException;

// 根據(jù)requiredType返回Bean對象
<T> T getBean(Class<T> requiredType) throws BeansException;

// 判斷Spring容器是否包含了key為name的Bean臀稚。
boolean containsBean(String name);

Bean的生命周期 如下所示。

1. Instantiate 實(shí)例化一個(gè)Bean
        ↓
2. Populate properties 設(shè)置Bean的屬性值
        ↓
3*. 調(diào)用BeanNameAware的setBeanName()                   
        ↓                                                   
4*. BeanFactoryAware的setBeanFactory()                     
        ↓                                                  
5*. 調(diào)用BeanPostProcessors的ProcessBeforeInitialization()   
        ↓
6*. 調(diào)用InitializingBean的afterPropertiesSet()
        ↓
7. 調(diào)用調(diào)用Bean定義的init-method
        ↓
8*. BeanPostProcessors的ProcessaAfterInitialization()
        ↓
[上面是Bean的創(chuàng)建階段]
[Bean的正常使用階段]
[下面是Bean的銷毀階段三痰,例如容器銷毀的時(shí)候]
            
9. 調(diào)用DisposableBean的destroy()
        ↓
10. 調(diào)用Bean中自定義的destroy-method

其中吧寺,Bean自身的方法包括:本身正常使用的方法,通過<bean>或者@Bean配置的init-method和destroy-method方法散劫。在一般的開發(fā)過程中稚机,我們只需要關(guān)心Bean自身的方法即可。

剩余的都是Bean級別的生命周期的接口方法获搏,包括BeanNameAware赖条、BeanFactoryAware、InitializingBean和DiposableBean這些接口的方法常熙,只有Bean實(shí)現(xiàn)了這些接口纬乍,才會在生命周期中執(zhí)行接口的相關(guān)方法。

4. Bean的屬性

4.1 id

  • xml配置方式里裸卫,id是Bean的唯一標(biāo)識仿贬。
  • 注解方式中,@Bean 里并沒有id這個(gè)屬性墓贿。

4.2 name

name是該Bean的一個(gè)或者多個(gè)別名茧泪,配置多個(gè)別名可以用“,”分割。當(dāng)使用@Bean注解方式時(shí)聋袋,如果沒有配置name队伟,那么默認(rèn)使用方法名。

4.3 class

class 指定該Bean 的全限定名幽勒,例如com.example.dao.UserDao嗜侮。這個(gè)屬性也是用于xml配置方式里,注解里自然用不到,因?yàn)楸蛔⒔獾姆椒ㄉ嫌衏lass的信息锈颗。

4.4 autowire

  1. no: 不適用自動(dòng)裝配缠借。這是autowire的默認(rèn)值。指必須顯示的指定依賴宜猜。
  2. byName: 根據(jù)屬性名自動(dòng)裝配。
  3. byType: 根據(jù)屬性的類型自動(dòng)裝配

4.5 initMethod

該Bean的初始化方法硝逢。

4.6 destroyMethod

該Bean的銷毀方法姨拥。

4.7 Scope

Scope用來聲明Bean的生存空間,最基本類型是singleton和prototype渠鸽;如果我們沒有指定Bean的Scope類型叫乌,那么默認(rèn)是singleton。

  1. singleton徽缚,單例憨奸。如果某個(gè)Bean的scope被設(shè)置成為singleton,那么Sping容器里只有一個(gè)實(shí)例凿试,所有對該類型Bean的依賴排宰,都引用這個(gè)單一實(shí)例。
  2. prototype那婉,原型板甘。容器在接收到該類型對象的請求的時(shí)候,Spring都會新建一個(gè)Bean的實(shí)例详炬,并返回給程序盐类。在這種情況下,Spring容器僅僅使用new關(guān)鍵字創(chuàng)建了Bean的實(shí)例呛谜,一旦創(chuàng)建成功在跳,容器不再擁有該Bean的引用,完全交由調(diào)用方管理該對象的生命周期隐岛,包括對象的銷毀猫妙。
  3. 除此以外,還有request礼仗、session吐咳、application、globalSession元践,只適用于web程序韭脊。大體上,request单旁、session沪羔、application分別對應(yīng)servlet規(guī)范中三種scope:request、session、application蔫饰;globalSession只應(yīng)用于基于Portlet規(guī)范的Web程序琅豆,對應(yīng)于portlet的global范圍的session。

5. Bean注冊的方式

Bean的注冊是指把Bean的信息注冊到Spring容器中篓吁,既可以通過xml配置的方式茫因,也可以通過注解的方式。如果使用注解的方式把Bean信息注冊到Spring容器中杖剪,我們最熟悉的是:@Component冻押。如果一個(gè)類使用了@Component注解,代表了這是Spring的一個(gè)Bean盛嘿。@Controller洛巢、@Service和@Repository都和@Component等效。

  • @Component次兆,泛指組件稿茉,當(dāng)Bean不好歸類的時(shí)候,就可以使用這個(gè)注解芥炭。

  • @Controller漓库,顧名思義,用于標(biāo)記web層的Controller园蝠。同樣用于標(biāo)記web層Controller的還有@RestController米苹,它相當(dāng)于是@Controller和@ResponseBody的組合。

  • @Service砰琢,用于標(biāo)注業(yè)務(wù)層組件蘸嘶。

  • @Repository,用于標(biāo)注數(shù)據(jù)訪問組件陪汽。

除此之外训唱,注冊Bean還會用到另外兩個(gè)注解,分別是@Configuration和@Bean挚冤。這兩個(gè)注解通常用于注冊配置信息况增,或者把引入的類注冊到Spring 容器中,例如數(shù)據(jù)源的注冊训挡、外部jar中Servlet澳骤、Filter等的注冊先壕。下面看一個(gè)向Spring 容器注冊Druid數(shù)據(jù)庫連接池監(jiān)控Serlvet和Filter的例子侦另。

@Configuration
public class DruidConfiguration {
  // Bean的name沒有配置骂倘,默認(rèn)使用method的name志于。    
  @Bean
  public ServletRegistrationBean druidServlet() {
    ServletRegistrationBean bean = new ServletRegistrationBean();
    bean.setServlet(new StatViewServlet());
    bean.addUrlMappings("/druid/*");
    Map<String, String> initParameters = new HashMap<String, String>();
    initParameters.put("loginUsername", "admin");// 用戶名
    initParameters.put("loginPassword", "admin");// 密碼
    initParameters.put("resetEnable", "false");// 禁用HTML頁面上的“Reset All”功能
    initParameters.put("allow", ""); // IP白名單 (沒有配置或者為空,則允許所有訪問)
    //initParameters.put("deny", "192.168.20.38");// IP黑名單 (存在共同時(shí)抗斤,deny優(yōu)先于allow)
    bean.setInitParameters(initParameters);
    return bean;
  }

  @Bean
  public FilterRegistrationBean filterRegistrationBean() {
    FilterRegistrationBean bean = new FilterRegistrationBean();
    bean.setFilter(new WebStatFilter());
    bean.addUrlPatterns("/*");
    bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
    return bean;
  }

}

6. 總結(jié)

以上是對Spring IoC的一些總結(jié)肾筐,到了最后不要忘記IoC的宗旨枫疆,它就是為了實(shí)現(xiàn)對象之間的松耦合。凡事有得必有失棋枕,IoC容器生成對象通過反射方式白修,在運(yùn)行效率上有一定的損耗,同時(shí)也增加了不少的配置工作重斑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末兵睛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子窥浪,更是在濱河造成了極大的恐慌卤恳,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寒矿,死亡現(xiàn)場離奇詭異,居然都是意外死亡若债,警方通過查閱死者的電腦和手機(jī)符相,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蠢琳,“玉大人啊终,你說我怎么就攤上這事“列耄” “怎么了蓝牲?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泰讽。 經(jīng)常有香客問我例衍,道長,這世上最難降的妖魔是什么已卸? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任佛玄,我火速辦了婚禮,結(jié)果婚禮上累澡,老公的妹妹穿的比我還像新娘梦抢。我一直安慰自己,他們只是感情好愧哟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布奥吩。 她就那樣靜靜地躺著,像睡著了一般蕊梧。 火紅的嫁衣襯著肌膚如雪霞赫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天肥矢,我揣著相機(jī)與錄音绩脆,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛靴迫,可吹牛的內(nèi)容都是我干的惕味。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼玉锌,長吁一口氣:“原來是場噩夢啊……” “哼名挥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起主守,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤禀倔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后参淫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體救湖,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年涎才,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鞋既。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耍铜,死狀恐怖邑闺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棕兼,我是刑警寧澤陡舅,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站伴挚,受9級特大地震影響靶衍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜茎芋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一摊灭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧败徊,春花似錦帚呼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沪哺,卻和暖如春沈自,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背辜妓。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工枯途, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留忌怎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓酪夷,卻偏偏與公主長得像榴啸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子晚岭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容