Java Web系列:Spring依賴注入基礎

1、Spring簡介

1.Spring簡化Java開發html

Spring Framework是一個應用框架,框架通常是半成品,咱們在框架的基礎上能夠不用每一個項目本身實現架構、基礎設施和經常使用功能性組件,而是能夠專一業務邏輯。所以學習Spring Framework在架構和模式方面的結構和原理,對咱們在架構和模塊級別的理解幫助極大。Spring Framework(參考1)的宗旨是簡化Java開發,主要的手段以下:java

(1)在架構上解耦:經過DI(依賴注入)管理類型依賴,經過AOP分離關注點,減小重複代碼。web

(2)在設計上普遍採用DIP(依賴倒置)和ISP(接口隔離)等原則和Facade(外觀)等模式:提供簡化的調用接口並封裝了衆多出色的第三方組件。spring

(3)在語言層面上採用註解:經過配置文件和Annotation(參考.NET Attribute)簡化應用配置。express

2.Spring Framework的架構和模塊:架構

Spring Framework自己的架構是典型的鬆散分層,外層能夠按需引用所有內層,內層不能引用外層。Spring的基礎組件以下圖所示:框架

從圖中能夠看出,開始的模塊只有從core\beans\aop\context四個組件,後來添加了context-support【1.2】擴展模塊、expression【3.0】擴展模塊和beans-groovy【4.0】擴展模塊。yii

Spring上述模塊的基礎上,內建和封裝了衆多的實用的通用組件,主要的組件如圖所示:ide

 從圖中能夠看出,spring-oxm、spring-jdbc和spring-web是衆多模塊依賴的核心,spring-oxm提供了Object和XML的映射支持。函數

2、基礎知識

1.DIP:DIP(依賴倒置原則)是DI(依賴注入)的核心(參考2)。

(1)高層模塊不該該依賴於低層模塊。二者都應該依賴於抽象。

(2)抽象不該該依賴於細節。細節應該依賴於抽象。

說人話就是:將對具體類的引用轉換成對其接口的引用,具體類只引用接口(引用==依賴,接口==接口或抽象類)。事實上咱們調用具體類的時候在頭腦裏也是隻關心其提供的API而非實現,DIP則經過在設計和重構階段在技術手段上保證瞭解耦。

2.DI:DI(依賴注入)讓咱們沒必要手寫工廠代碼來管理接口和實現類的映射、對象的建立和生命週期的管理。

(1)接口注入:必須實現特定的接口才能夠,侵入性太強,如今已經無人關心和使用。

(2)構造函數注入:依賴體如今構造函數的參數上。

(3)屬性注入:依賴體如今屬性上。

因爲在實現時,能夠將類型註冊爲本身的兼容類型,這樣依賴注入就能夠直接替代new實例化對象,這樣理解和使用依賴注入工具還不如不使用或手寫工廠了。依賴注入工具在實現時確定會實現成一個支持不一樣配置和不一樣生命週期的對象工廠,但即便沒有提供一套添加依賴倒置原則限制的API,也不意味着咱們把它當成new的替代品。如同映射工具雖然在實現時能夠任意映射,但不是用來取代賦值的,而是用來處理領域實體和視圖模型等有實際對應關係的對象之間的映射。

(1)依賴配置:依賴配置是依賴注入實現的基礎。依賴注入工具都至少支持代碼配置和文件配置。Java中能夠經過Annotation(.NET中經過Attribute)簡化配置。

(2)對象工廠:根據配置返回一個或多個對象。這是核心功能。

(3)生命週期管理:通常提供至少4種級別的支持:做用域、單例、線程、HTTP請求範圍。

大多數依賴注入工具在支持依賴倒置原則的基礎上,在技術手段上實現了更多的功能,如類型的兼容轉換、對依賴命名、在配置時直接傳入對象等。

3、Spring依賴注入的要點

Bean在Spring中就是POJO(.NET的POCO)。

Spring依賴注入須要掌握的核心是3個類型BeanDefinitionBeanFactoryApplicationContext

1.BeanFactory

BeanFactory是spring中依賴注入的核心接口,其設計主要採用了ISP(接口隔離原則),經過多層次的接口繼承即保證了單個接口的內聚又保證了整個體系的簡潔。這裏咱們要關注的核心是DefaultListableBeanFactory

如圖所示,查看XmlBeanFactory代碼,能夠看到XmlBeanFactory只是經過XmlBeanDefinitionReader載入了BeanDefinition配置,XmlBeanDefinitionReader負責將配置解析到BeanDefinition。DefaultListableBeanFactory是真正的實現類,其中定義了類型爲Map<String, BeanDefinition>的beanDefinitionMap列表用於存儲依賴配置。

2.BeanDefinition:

BeanDefinition定義了配置元數據,不管使用java code、xml、Annotation仍是Groovy腳本方式,不一樣的配置方式經過不一樣的BeanDefinitionReader解析爲BeanDefinition。

3.ApplicationContext

ApplicationContext的核心都是將對象工廠功能委託給BeanFactory的實現類DefaultListableBeanFactory。目前最經常使用的是基於註解的AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext

4、Spring依賴注入快速上手

1.使用Java配置代替xml配置

Java配置的核心是@Configuration和@Bean。定義生命週期使用@Scope,須要引入其餘配置文件時使用@Import

(1)@Configuration:應用了@Configuration註解的POCO成爲了配置類。至關於xml配置文件。

(2)@Bean:配置類中應用了@Bean註解的方法成爲了配置項。至關於xml中的Bean節點。

package me.test.spring_ioc;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext container = new AnnotationConfigApplicationContext(AppConfig.class);
        String message = container.getBean(IAppService.class).Test();
        System.out.println(message);
        container.close();
    }
}

@Configuration
class AppConfig {
    @Bean
    public IAppService IAppService() {
        return new AppService(new Repository<SimpleEntity>());
    }
}

class SimpleEntity {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

interface IAppService {
    String Test();
}

interface IRepository<T> {
    String Test();
}

class AppService implements IAppService {

    private IRepository<SimpleEntity> _repo;

    public AppService(IRepository<SimpleEntity> repo) {
        _repo = repo;
    }

    @Override
    public String Test() {
        return this._repo.Test();
    }

}

class Repository<T> implements IRepository<T> {

    @Override
    public String Test() {
        return this.getClass().getName();
    }

}

若是是Web應用程序,應該使用AnnotationConfigWebApplicationContext,在JSP中可經過WebApplicationContextUtils獲取ApplicationContext對象。

<%@page import="swp.IAppService"%>
<%@page import="org.springframework.web.context.WebApplicationContext"%>
<%@page
    import=" org.springframework.web.context.support.WebApplicationContextUtils"%>
<html>
<body>
    <%
        WebApplicationContext context = WebApplicationContextUtils
                .getRequiredWebApplicationContext(this.getServletContext());
        String message = context.getBean(IAppService.class).print();
        out.print(message);
    %>
</body>
</html>

2.基於Annotation的自動裝配

自動裝配主要使用@ComponentScan@Component@Autowired

(1)@ComponentScan:做用在配置類上,啓用組件掃描。掃描並註冊標註了@Component(@Controller\@Service\@Repository)的類型。@Configuration已經應用了@Component註解。

(2)@Autowired:按類型自動裝配。@Autowired和使用@Inject(JSR-330)或@Resource(JSR-250)的效果是相似的。@Autowired和@Inject默認按類型注入,@Resource默認按名稱注入。

package me.test.spring_ioc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext container = new AnnotationConfigApplicationContext(AppConfig.class);
        String message = container.getBean(IAppService.class).Test();
        System.out.println(message);
        container.close();
    }
}

@Configuration
@ComponentScan
class AppConfig {

    /*@Bean
    public IAppService IAppService() {
        return new AppService(new Repository<SimpleEntity>());
    }*/

}

class SimpleEntity {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

interface IAppService {
    String Test();
}

interface IRepository<T> {
    String Test();
}

@Component
class AppService implements IAppService {

    private IRepository<SimpleEntity> _repo;

    @Autowired
    public AppService(IRepository<SimpleEntity> repo) {
        _repo = repo;
    }

    @Override
    public String Test() {
        return this._repo.Test();
    }

}

@Component
class Repository<T> implements IRepository<T> {

    @Override
    public String Test() {
        return this.getClass().getName();
    }

}

 

小結:

你至少應該知道的:

(1)BeanFactory和BeanDefinition

(2)DefaultListableBeanFactory和ApplicationContext

(3)AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext

(4)@Configuraton和@Bean

Spring的依賴注入在配置上是基於對象而不是類型,最早支持的是xml而不是註解,到如今也沒有比較方便的代碼配置機制。雖然如今已經從xml過渡到了註解方式,但基於對象的基礎仍然是影響不少方面的缺點。

參考

1.http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/overview.html

2.https://en.wikipedia.org/wiki/Dependency_inversion_principle

3.http://www.ibm.com/developerworks/cn/java/j-guice.html

4.https://www.ibm.com/developerworks/cn/webservices/ws-springjava/

5.http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-iocannt/

6.https://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/

7.http://www.ibm.com/developerworks/cn/java/j-lo-beanannotation/

8.http://www.ibm.com/developerworks/cn/java/j-guice.html

9.http://www.yiibai.com/spring/spring-dependency-checking-with-required-annotation.html

相關文章
相關標籤/搜索