1. 程式人生 > >Spring Ioc基於java反射而遠遠高於反射---Spring框架三大核心介面

Spring Ioc基於java反射而遠遠高於反射---Spring框架三大核心介面

關於最基礎的Ioc的概念及其思想,我們在

1、java反射

    那麼,接下來,我們從反射入手,開始Spring征程。看例子:
package com.smart.reflect;

public class Car {
    private String brand;
    private String color;
    private int maxSpeed;

    public Car() {
    }

    public Car(String brand, String color, int maxSpeed) {
        this.brand = brand;
        this
.color = color; this.maxSpeed = maxSpeed; } public void introduce() { System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed); } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public
String getColor() { return color; } public void setColor(String color) { this.color = color; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } }
一般情況下,我們使用如下程式碼示例Car:
Car car = new
Car(); car.setBrand("法拉利");

或者

Car car =  new Car("法拉利", "紅色", 250);
以上兩種方法都是採用傳統的方式,直接呼叫目標類的方法。下面我們通過反射機制一一種間接的方式操控目標類:
package com.smart.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectTest {
    public static Car initByDefaultConst()
            throws ClassNotFoundException,
                    NoSuchMethodException,
                    IllegalAccessException,
                    InvocationTargetException,
                    InstantiationException {
        //①通過類載入器獲取Car物件
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class clazz = classLoader.loadClass("com.smart.reflect.Car");
        /*
        * 也可以通過Class.forName();來獲取Car物件
        */
        //②獲取類的預設構造器物件並通過他例項化Car
        Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
        Car car = (Car) cons.newInstance();

        //③通過反射方法設定屬性
        Method setBrand = clazz.getMethod("setBrand", String.class);
        setBrand.invoke(car, "法拉利");
        Method setColor = clazz.getMethod("setColor", String.class);
        setColor.invoke(car, "紅色");
        Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
        setMaxSpeed.invoke(car, 250);
        return car;
    }

    public static void main(String[] args)
            throws ClassNotFoundException,
            NoSuchMethodException,
            InvocationTargetException,
            InstantiationException,
            IllegalAccessException {
        Car car = initByDefaultConst();
        car.introduce();
    }
}

執行上述程式:
brand:法拉利;color:紅色;maxSpeed:250
這些都是基礎的反射的知識,我們就不詳細給大家說明了。
關於類載入器,類載入機制,詳見
java類載入
這裡我們補充一些ClassLoad的知識。在java中ClassLoad是一個抽象類,位於java.lang包中,下面對該類的一些方法進行分析:

  • Class loadClass(String name):name引數指定類裝載器需要裝載的類的名字,必須使用全限定名,如 com.smart.reflect.Car。該方法有一個過載方法loadClass(String name, boolean resolve),resolve引數告訴類裝載器是否需要解析該類。在初始化類之前,應考慮進行類解析工作,但並不是所有的類都需要解析。如果JVM只需要知道該類是否存在或找出該類的超類,那麼就不需要進行解析。
  • Class defineClass(String name, byte[] b, int off, int len):將類檔案的位元組陣列轉換成JVM內部的java.lang.Class物件。位元組陣列可以從本地檔案系統、遠端網路獲取。引數name為位元組陣列的全限定類名。
  • Class findSystemClass(String name):呼叫該方法來檢視ClassLoader是否已裝入某個類。如果已經裝入,那麼返回java.lang.Class物件;否則,丟擲ClassNotFoundException異常。該方法是JVM預設使用的裝載機制。
  • ClassLoader getParent():獲取類裝載器的父裝載器。除根裝載器外,所有的類裝載器都有且只有一個父類裝載器。ExtClassLoader的父裝載器是根裝載器,因為根裝載器是非java語言寫的,所以無法獲得, 返回null;

    除了JVM預設的三個類載入器外,使用者可以自己編寫自己的第三方類載入器,以實現一些特殊的要求。類檔案被裝載並解析後,在JVM內擁有一個對應的java.lang.Class類描述物件,該類的例項都擁有指向這個類描述物件的引用,而類描述物件用擁有指向關聯ClassLoader的引用
    

    這裡寫圖片描述

反射機制

class反射物件描述類語義結構,可以從Class物件中獲取建構函式,成員變數,方法類等元素的反射物件,並以程式設計的方式通過這些反射物件對目標類進行操作。
除了我們經常使用的Constructor類的建構函式反射類、Method類的方法反射類、Filed類的成員變數反射類之外,java還為包提供了Package反射類,在java5.0中還為註解提供了AnnotatedElement反射類。總之,java的反射體系保證了可以通過程式化的方式訪問目標類中的所有元素,對於private和protected成員變數和方法,只要JVM的安全機制允許,也可以通過反射進行呼叫。具體就不演示了。

2、資源訪問利器

負責任的說,這塊是重點內容。

2.1、資源抽象介面
JDK所提供的訪問資源的類(java.net.URL、File等)並不能很好的滿足各種底層資源的訪問需求,比如缺少從類路徑(classpath:com.smart)或者Web容器的上下文(ServletContexst)中獲取資源的類。鑑於此,Spring設計了一個Resource介面,他為應用提供了更強的底層資源訪問能力。該介面擁有對應不容資源的實現類。先來了解一下Resource介面的主要方法。

  • boolena exists():資源是否存在。
  • boolean isOpen():資源是否已經開啟。
  • URL getURL() throws IoException:如果底層資源可以表示成URL,則方法返回對應的URL物件。
  • File getFile() throws IoException:如果底層資源對應一個檔案,則返回該方法的對應的File物件。
  • InputStream getInputStream() throws IoException:放回資源對應的輸入流。
    Resource在Spring框架中起著不可獲取的作用,Spring框架使用Resource裝載各種資源,包括配置檔案資源,國際化屬性檔案資源等。
    假如有一個檔案位於Web應用的類路徑下,使用者可以通過以下方式對這個檔案資源進行訪問:

  • 通過FileSystemResource以檔案系統絕對路徑的方式進行訪問。

  • 通過ClassPathResource以類路徑的方式進行訪問。
  • 通過ServletContextResource以相對於web應用根目錄的方式進行訪問。

相比於通過JDK的File類訪問檔案資源的方式,Spring的Resource實現類無疑提供了更加靈活便捷的訪問方式,使用者可以根據實際情況選擇適合的Resource實現類訪問資源。下面通過FileSystemResource 和ClassPathResource訪問同一個資源。

package com.smart.resource;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class FileSourceExample {
    public static void main(String[] args) {
        try {
            String filepath = "E:/IdeaProjects/chapter4/src/main/resources/conf/file1.txt";

            //①使用系統檔案路徑方式載入檔案
            WritableResource res1 = new PathResource(filepath);

            //②使用類路徑載入檔案
            Resource res2 = new ClassPathResource("conf/file1.txt");

            //③使用WritableResource介面寫資原始檔
            OutputStream outputStream = res1.getOutputStream();
            outputStream.write("歡迎光臨\nSpring學習基地".getBytes());
            outputStream.close();

            //④使用Resource介面讀資原始檔
            InputStream inputStream1 = res1.getInputStream();
            InputStream inputStream2 = res2.getInputStream();

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int i;
            while((i = inputStream1.read()) != -1) {
                byteArrayOutputStream.write(i);
            }
            System.out.println(byteArrayOutputStream.toString());
            System.out.println("res1:" + res1.getFilename());
            System.out.println("res2:" + res2.getFilename());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

2.2、資源載入
為了訪問不同型別的資源,必須使用相應的Resource實現類,這是比較麻煩的。是否可以在不顯式使用Resource實現類的情況下,僅通過資源地址的特殊標識就可以訪問相應的資源呢?Spring提供了一個強大的載入資源機制,不但能夠通過“classpath”,“file”等資源地址字首識別不同的資源型別,還支援Ant風格帶萬用字元的資源地址。
首先了解一下Spring支援哪些資源型別的地址字首。

  • “classpath:”:從類路徑中載入資源,classpath和classpath:/是等價的,都是相對於類的根路徑。資原始檔可以在標準的檔案系統中,也可以在JAR或ZIP的類包中。
  • “file:”:使用UrlResource從檔案系統目錄中裝載資源,可以採用絕對路徑或相對路徑。
  • “http://”:使用UrlResource從Web伺服器中裝載資源。
  • ftp://”:使用UrlResource從FTP伺服器中裝載資源。
  • 沒有字首:根據ApplicationContext的具體實現類採用對應型別的Resource。
    至於萬用字元就不詳細說明了,大家可以自己查。
    Spring定義了一套資源載入的介面,並提供了實現類。
    這裡寫圖片描述
    ResourceLoader介面僅有一個getResource(String localtion)方法,可以根據一個資源地址載入人間資源。不過,資源地址僅支援帶資源型別字首的表示式,不支援Ant風格的資源路徑表示式。ResourcePatternResolver擴充套件ResourceLoader介面,定義了一個新的路徑表示式。PathMatchingResourcePatternResolver是Spring提供的標準實現類。看一個例子:
package com.smart.resource;

import org.junit.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

import static org.junit.Assert.assertNotNull;

public class PatternResolverTest {
    @Test
    public void getResources() {
        ResourcePatternResolver resolcer = new PathMatchingResourcePatternResolver();

        //①載入所有類包com.smart(及子孫包)一下的.xml為字尾的資源
        try {
            Resource[] resources = resolcer.getResources("classpath*:com/smart/**/*.xml");
            assertNotNull(resources);

            for(Resource resource : resources) {
                System.out.println(resource.getDescription());
            }
        } catch (IOException e) {
            e.printStackTrac`
();
        }
    }
}

file [E:\IdeaProjects\chapter4\target\classes\com\smart\beanfactory\beans.xml]
file [E:\IdeaProjects\chapter4\target\classes\com\smart\beans1.xml]
file [E:\IdeaProjects\chapter4\target\classes\com\smart\beans2.xml]
file [E:\IdeaProjects\chapter4\target\classes\com\smart\context\beans.xml]

由於資源路徑是”classpath*:”,所以PathMatchingResourcePatternResolver將掃描所有類路徑下以及JAR包中對應的com.smart類包下的路徑,讀取所有以.xml為字尾的檔案資源。
提示

用Resource造作檔案時,如果資源配置檔案在專案釋出時會被打包到JAR中,那麼不能使用Resource#getFile()方法,否則會丟擲FileNotFoundException。但可以使用Resource#getInputStream()方法。
這樣的問題在實際專案開發中很容易被疏忽!
2.3 BeanFactory和ApplicationContext

Spring通過一個配置檔案描述Bean及Bean之間的依賴關係。利用java語言的放射功能例項化Bean並建立Bean之間的依賴關係,Spring的Ioc容器在完成這些底層工作的基礎上,還提供了Bean例項快取,生命週期管理,Bean例項代理,事件釋出,資源轉載等高階服務。
Bean工廠(com.springframework.beans.BeanFactory)是Spring框架的最核心的介面,他提供了高階Ioc的配置機制,BeanFactory使管理不同型別的java物件成為可能,應用上下文(com.springframework.beans.ApplicationContext)建立在BeanFactory基礎之上,提供了更多面嚮應用的功能,它提供了國際化支援和框架事件體系,更易於建立實際應用。我們一般稱BeanFactory為Ioc容器,而稱ApplicationContext為應用上下文,但有時為了行文方便,我們也將ApplicationContext成為Spring容器。
對於二者的用途,我們可以進行簡單的劃分,BeanFactory是Spring框架的基礎設施,面向Spring本身,ApplicationContext面向使用Spring框架的開發者,幾乎所有的應用場合都可以直接使用ApplicationContext而非底層的BeanFactory。
2.3.1、BeanFactory介紹
誠如其名,BeanFactory是一個類工廠,但和傳統的類工廠不同,傳統的類工廠僅負責構造一個或幾個類的例項,而BeanFactory是類的通用工廠,他可以建立並管理各種類的物件。這些可被建立和管理的物件本身沒有什麼特別之處,僅僅是一個POJO,Spring稱這些被建立和管理的java物件為Bean。
2.3.1.1BeanFactory的類體系結構
Spring為BeanFactory提供了多種實現,最常用的是XmlBeanFactory,但是在Spring3.2中已經被廢棄,建議使用XmlBeanDefinitionReader、DefaultListableFactory替代。BeanFactory的類繼承體系設計優雅,堪稱經典。通過繼承體系,我們可以很容易的瞭解BeanFactory具有哪些功能。
這裡寫圖片描述
BeanFactory介面位於類結構樹的頂端,他最主要的方法就是getBean(String beanName),該方法從容器中放回特定名稱的Bean。BeanFactory的功能通過其他介面得到不斷擴充套件。
2.3.1.2初始化BeanFactory

<?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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
   <bean id="car" class="com.smart.Car"
         p:brand="紅旗CA72"
         p:maxSpeed="200"/>
</beans>
    下面通過XmlBeanDefinitionReader、DefaultListableBeanFactory實現啟動Spring Ioc容器。
package com.smart.beanFactory;

import com.smart.Car;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

public class BeanFactoryTest {
    @Test
    public void getBean() throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource res = resolver.getResource("classpath:com/smart/beanFactory/beans.xml");

        System.out.println(res.getURL());
        //資源定位
        //file:/E:/IdeaProjects/chapter4/target/classes/com/smart/beanFactory/beans.xml

        //①初始化Ioc 容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //②裝載Spring配置資訊並啟動Ioc容器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(res);

        System.out.println("init BeanFactory");

        //預設使用類名首字母小寫為鍵值
        Car car = factory.getBean("car", Car.class);
        System.out.println("car bean is ready for use");
        car.introduce();
    }
}

通過BeanFactory啟動Ioc容器時,並不會初始化配置檔案中定義的Bean,初始化動作發生在第一個呼叫時。對於單例項(singleton)的Bean來說,BeanFactory會快取Bean例項,所以在第二次使用getBean()獲取Bean時,直接從Ioc容器的快取中獲取Bean例項。
Spring在DefaultSingletonBeanRegistry類中提供了一個用於快取Bean例項的快取器。他是一個用HashMap實現的快取器,單例項的Bean以beanName為鍵值儲存在這個HashMap中。
2.3.2、ApplicationContext介紹
如果說BeanFactory是Spring的“心臟”,那麼ApplicationContext就是整的“身軀”了。ApplicationContext有BeanFactory派生而來,體用了更多面向實際應用的功能。在BeanFactory中,很多功能需要以程式設計的方式實現,而在ApplicationContext中則可以通過配置的方式實現。
2.3.2.1 ApplicationContext類體系結構
ApplicationContext的主要實現類是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者預設從類路徑載入配置檔案,後者預設從檔案系統中裝載配置檔案,下面瞭解一下ApplicationContext的類繼承體系。
這裡寫圖片描述
從圖中可以看出,ApplicationContext繼承了HierarchicalBeanFactory和listableBeanFactory介面。在此基礎上,還通過多個其他的介面擴充套件了BeanFactory的功能。
ConfigurableApplicationContext擴充套件於ApplicationC,它新增了兩個主要的方法,refresh()和close(),讓ApplicationContext具有啟動、重新整理和關閉應用上下文的能力。在應用上下文關閉的情況下呼叫refresh()即可啟動應用上下文已經啟動的狀態下,呼叫close()即可關閉應用上下文。
和BeanFactory初始化相似,ApplicationContext的初始化也很簡單。如果配置檔案放置在類路徑下,則可以優先考慮使用ClassPathXmlApplicationContext實現類。

/*
此時的com/smart/context/beans.xml等同於classpath:com/smart/context/beans.xml
*/
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/smart/context/beans.xml");
如果配置檔案放置在檔案系統的路徑下,則可以優先考慮使用FileSystemXmlApplicationContext實現類。
/*
此時的com/smart/context/beans.xml等同於file:com/smart/context/beans.xml
*/
Application ctx = new FileSystemXmlApplicationContext("com/smart/context/beans.xml");

當然,FileSystemXmlApplicationContext和ClassPathXmlApplication都可以顯示的使用帶資源型別字首的路徑,他們的區別在於如果不是顯示指定資源型別字首,則分別將路徑解析為檔案系統路徑和類路徑。
在獲取ApplicationContext例項之後,就可以像BeanFactory一樣呼叫getBean()方法獲取Bean。但是兩者有一個巨大的區別:BeanFactory在初始化容器時,並未例項化Bean,直到第一次呼叫getBean()才例項化,而ApplicationContext在例項化應用上下文時,就會例項化所有單例Bean。因此,ApplicationContext在初始化時間上會比BeanFactory稍長一些,但是在呼叫時則沒有“一次懲罰”的問題。
Spring支援基於註解的配置,主要功能來自於Spring的一個名為JavaConfig的子專案。JavaConfig現在已經升級為Spring核心框架的一部分。一個標註@Configuration註解的POJO即可提供Sprin所需的Bean配置資訊。

package com.smart.context;

import com.smart.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//表示是一個配置資訊的提供類
@Configuration
public class Beans {
    //定義一個Bean
    @Bean(name="car")
    public Car builder() {
        Car car = new Car();
        car.setBrand("法拉利");
        car.setMaxSpeed(200);
        return car;
    }
}

和基於XML配置的方式相比,類註解的配置方式可以很容易的讓開發者控制Bean的初始化過成功,比基於XML檔案的配置方式更加靈活。
Spring為基於註解類的配置提供了專門的ApplicationContext實現類:AnnotationConfigApplicationContext。來看一個例子:

package com.smart.context;

import com.smart.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.junit.Assert.assertNotNull;

public class AnnotationApplicationContextText {
    @Test
    public void getBean() {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class);

        Car car = ctx.getBean("car", Car.class);
        assertNotNull(car);
    }
}

Spring4.0支援使用Groovy DSL來進行Bean定義配置。其與基於XML檔案的配置類似,只不過基於Groovy指令碼語言,可以實現複雜、靈活的Bean配置邏輯,來看一個例子。
檔案字尾名.groovy

package com.smart.context

import com.smart.Car

beans {
    car(Car) {//名字(型別)
        brand = "法拉利";  //注入屬性
        maxSpeed = "270";
        color = "紅色";
    }
}

基於Groovy的配置方式可以很容易的讓開發者配置複雜的Bean的初始化過程,比基於XML檔案,註解得配置方式更加靈活。
Spring為基於Groovy的配置提供了專門的ApplicationContext實現類,GenericGroovyApplicationContext。來看一個例子:

package com.smart.context;

import com.smart.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericGroovyApplicationContext;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class GroovyApplicationContextText {
    @Test
    public void getBean() {
        ApplicationContext ctx = new GenericGroovyApplicationContext("classpath:com/smart/context/beans.groovy");
        Car car = ctx.getBean("car", Car.class);
        assertNotNull(car);
        assertEquals(car.getColor(), "red");

    }
}

2.3.2.2 WebApplicationContext類體系結構
WebApplicationContext是專門為WEB應用準別的,他允許從相對根目錄的路徑中裝載配置檔案完成初始化工作。從 WebApplicationContext中可以獲得ServletContext的引用,整個web應用上下文物件將作為屬性放置到ServletContext中,以便web應用環境可以訪問Spring的上下文。Spring專門為此提供了一個工具類WebApplicationContextUtils,通過該類的getWebApplication(ServletContext sc)方法,可以從ServletContext中獲取WebApplicationContext例項。
在非Web應用環境下,Beans只有singleton和prototype兩種作用域,WebApplicationContext為Bean添加了三個新的作用域:request、session、global session。
由於web應用比一般的應用擁有更多的特性,因此 WebApplicationContext擴充套件了ApplicationContext。 WebApplicationContext定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文啟動時, WebApplicationContext例項即以此為鍵值存放在ServletContext的屬性列表中,可以通過以下語句從容器中獲取 WebApplicationContext:

 WebApplicationContext wac = ( WebApplicationContext)servletContext.getAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

這正是前面提到的 WebApplicationContextUtils工具類的getWebApplicationContext(ServletContext sc)方法的內部實現方式。這樣,Spring的web應用上下文和web容器的上下文應用就可以互相訪問。
這裡寫圖片描述

ConfigurableWebApplicationContext擴充套件了WebApplicationContext,他允許通過配置的方式例項化WebApplicationContext,同時定義了兩個方法:

  • setServletContext(ServletContext servletContext):為Spring設定web應用上下文,以便二者整合。
  • setConfigLocations(String[] configLocations):設定Spring配置檔案地址,一般情況下,配置檔案地址是相對於WEB根目錄的地址,如/WEB-INF/smart-dao.xml。但是使用者可以使用帶資源型別字首的地址,如classpath:com/smart/beans.xml
    2.3.2.3 WebApplicationContext初始化

WebApplicationContext的初始化方式和BeanFactory、ApplicationContext的初始化方式有所區別。因為WebApplicationContext需要例項化ServletContext,也就是說,他必須在擁有WEB容器的基礎上才能完成啟動工作。有過web開發經歷的同學都知道,可以在web.xml中配置自啟動的Servlet或者定義web容器監聽器(ServletContextListener),藉助二者中的任何一個,就可以完成啟動Spring WEB應用上下文的工作。
Spring分別提供了用於啟動WebApplicationContext的Servlet和web容器監聽器:

  • org.springframework.web.context.ContextLoaderServlet。
  • org.springframework.web.context.ContextLoaderListener。

        二者的內部 都實現了啟動WebApplicationContext例項的邏輯,只要根據web容器的具體情況選擇二者之一,並在web.xml中完成配置即可。
    
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!--指定配置檔案-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>  
                  /WEB-INF/smart-dao.xml, /WEB-INF/smart-service.xml
        </param-value>
    </context-param>

    <!-- 宣告web容器監聽器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

ContextLoaderListener通過web容器上下文引數contextConfigLocation獲取Spring配置檔案的位置。使用者可以指定多個配置檔案,用逗號隔開、空格或冒號隔開。對於未帶資源型別字首的配置檔案路徑,WebApplicationContext預設這些路徑相對於Web的部署根路徑。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!--指定配置檔案-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>  
                  /WEB-INF/smart-dao.xml, /WEB-INF/smart-service.xml
        </param-value>
    </context-param>

    <!-- 宣告自啟動的Servlet-->
    <servlet>
        <servlet-class>
            org.springframework.web.context.ContextLoaderServlet
        </servlet-class>
        <!-- 啟動順序 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

</web-app>

由於WebApplicationContext需要使用日誌功能,所以使用者可以將Log4J的配置檔案放置在類路徑WEN-INF/classes下,這是Log4J引擎即可順利啟動。如果Log4J配置檔案放置在其他位置,那麼使用者必須在web.xml中指定Log4J配置檔案的位置。Spring為啟動Log4J引擎提供了兩個類似於啟動WebApplicationContext的實現類
Log4jConfigServlet和Log4jConfigListener,不管採用那種方式,都必須保證能夠在裝載配置檔案前裝載Log4J.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!--指定配置檔案-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>  
                  /WEB-INF/smart-dao.xml, /WEB-INF/smart-service.xml
        </param-value>
    </context-param>
    <!-- 指定Log4j配置檔案的位置 -->
    <context-param>
       <param-name>Log4jConfigLocation</param-name>
        <param-value>  
                  /WEB-INF/log4j.properties            
         </param-value> 
    </context-param>

    <!-- 裝載Log4J配置檔案的自啟動Servlet -->
    <servlet>
        <servlet-class>
            org.springframework.web.util.Log4jConfigServlet 
        </servlet-class>
        <load-on-startup>1</load-on-startup>
      </setvlet>

    <!-- 宣告自啟動的Servlet-->
    <servlet>
        <servlet-class>
            org.springframework.web.context.ContextLoaderServlet
        </servlet-class>
         <!-- 啟動順序 -->
         <load-on-startup>2</load-on-startup>
    </servlet>
    </web-app>

採用上述配置方法,Spring將自動使用XmlWebApplicationContext啟動Spring容器,即通過xml配置為Spring容器提供Bean配置資訊。
如果使用標註@Configuration的java類提供配置資訊,則web.xml需要按以下方式配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!--通過指定context引數,讓Spring使用GroovyWebApplicationContext而非
    XmlWebApplicationContext或AnnotationConfigWebApplicationContext啟動容器 -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>

    <!-- 指定標註了@Configuration註解的配置類-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            com.smart.AppConfig1
        </param-value>
    </context-param>

    <!-- ContextLoaderListener監聽器將根據上面配置使用
         AnnotationConfigWebApplicationContext根據contextConfigLocation
         指定的配置類啟動Spring容器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

</web-app>

ContextLoaderListener如果發現了配置了contextClass上下文引數,就會使用引數所指定的WebApplicationContext實現類(AnnotationConfigWebApplicationContext)初始化容器,該實現類會根據contextConfigLocation上下文引數指定的標註@Configuration的配置類所提供的Spring配置資訊初始化容器。
如果使用Groovy DSL配置Bean資訊,則web.xml需要按照以下方式配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <!--通過指定context引數,讓Spring使用GroovyWebApplicationContext而非
    XmlWebApplicationContext或AnnotationConfigWebApplicationContext啟動容器 -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.GroovyWebApplicationContext
        </param-value>
    </context-param>

    <!-- 指定標註了Groovy的配置檔案-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:conf/spring-mvc.groovy
        </param-value>
    </context-param>

    <!-- ContextLoaderListener監聽器將根據上面配置使用
         AnnotationConfigWebApplicationContext根據contextConfigLocation
         指定的配置類啟動Spring容器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

</web-app>

GroovyWebApplicationContext實現類會根據ContextConfigLocation上下文引數指定的conf/spring_mvc.groovy所提供的Spring配置資訊初始化容器。
2.3父子容器
通過HierarchicalBeanFactory介面,Spring的Ioc容器可以建立父子層級關聯容器體系,子容器可以訪問父容器的Bean,但父容器不能訪問子容器的Bean。在容器內,Bean的id必須是唯一的,但是子容器可以擁有和父容器id相同的Bean。父子容器層級體系增強了Spring容器架構的擴充套件性和靈活性,因為第三方可以通過程式設計的方式為一個已經存在的容器新增一個或多個特殊用途的子容器,以提供一些額外功能。
Spring使用父子容器實現了很多功能,比如在Spring MVC中,展現層Bean位於一個子容器中,而業務層和持久層Bean位於父容器層,這樣,展現層可以應用業務層和持久層Bean,反之則不能!

3、小結

    為了解開Spring依賴注入的神祕面紗,透視Spring原理,我們對java語言的反射機制進行了快速與學習。掌握這些知識,我們不但可以深刻理解Spring的內部機制,還可以自己動手編寫一個Ioc容器。
    BeanFactory、ApplicationContext、WebApplicationContext是Spring框架的3個核心介面,框架中其他大部分的類都圍繞他們展開,為他們提供服務和支援,在這些支援類中,Resource是一個不可忽視的重要介面,框架通過Resource實現了和具體資源的解耦,不論他們位於何種儲存介質中,都可以返回相同的例項。與Resource配合的另一個介面是ResourceLoader,ResourceLoader採用了策略模式,可以通過傳入資源地址的資訊,自動選擇合適的底層實現類,為上層對資源的引用提供了極大地便利。

相關推薦

Spring Ioc基於java反射遠遠高於反射---Spring框架三大核心介面

關於最基礎的Ioc的概念及其思想,我們在 1、java反射 那麼,接下來,我們從反射入手,開始Spring征程。看例子: package com.smart.reflect; public class Car { privat

Spring完全基於Java和註解配置

進行 要點 servle containe one targe 引入 logs pos 要點: 配置繼承WebApplicationInitializer的類作為啟動類,相當於配置web.xml文件 使用@Configuration註解一個類,在類中的方式使用@Bean註

Spring IOC(基於配置文件的方式)

interface ret ava package www app Coding factory get方法 IDao.java 1 package com.spring.ioc; 2 3 public interface IDao { 4 public Str

spring ioc---基於註解的配置(context包,@Configuration,@Bean,etc)

註解 釋義 @Configuration 宣告一個基於java註解的配置類物件.一般和@Bean組合使用,當然根據不同的場景,可配合其他多種註解使用. 原始碼(部分)文件:Indicates that a class dec

spring ioc---基於註解的配置(beans包@Autowired,@Qualifier,@Required,@Value)

org.springframework.beans.factory.annotation包中的註解 註解 釋義 說明 原始碼註解說明(包含部分) @Autowired 自動裝配

Spring基於Java的配置@Configuration和@Bean用法

Spring中為了減少xml中配置,可以宣告一個配置類(例如SpringConfig)來對bean進行配置。 一、首先,需要xml中進行少量的配置來啟動Java配置: <?xml version="1.0" encoding="UTF-8"?> <bea

Spring--IoC--基於註解的DI-使用Spring的JUnit4測試

不使用junit時: 第一步:加入test jar包 第二步:加註解 測試:刪除test01的實現,執行 報錯原因:當用註解獲取applicationContext時預設從專案根下

Spring-AOP基於JAVA註解實現

1.選擇切面切點或者連線點 定義一個需要切面的介面 //Spring-AOP程式設計是基於方法的切面程式設計,及只能在方法前後進行切面程式設計 //現在就對下面這個介面中的方法進行切面程式設計 public interface Performance{

什麼是Spring IOC、用通俗易懂的舉例講講Spring IOC、面試被問爛的 Spring IOC

在平時面試過程中,大家被問到Spring框架時,都會被問到Spring IOC 和 AOP,讓你說說他們的原理、流程、舉例說明等,今天就用通俗易懂的方式給大家講講Spring IOC。   資料來源: 作者:莫那·魯道 連結:http://thinkinjava.cn &n

自己寫的基於java Annotation(註解)的資料校驗框架

原始碼和UT請見http://download.csdn.net/source/2640884 JavaEE6中提供了基於java Annotation(註解)的Bean校驗框架,Hibernate也有類似的基於Annotation的資料校驗功能,我在工作中,產品也經常需要

Java Web 學習與總結(二)Servlet核心介面+Servlet3.0配置

  Servlet3.0版本對Servlet配置進行了重大變革,Servlet類不需要再麻煩的去編輯web.xml檔案了,只需要在類上面進行註釋就可以了,獲得了 Java 社群的一片讚譽之聲,以下是新增的註解支援。 @WebServlet @WebServlet 用於將一個類宣告為 Servlet,該註解

Spring IOC原理之Java反射機制

1、反射概念以及為什麼要使用反射 我們考慮一個場景,如果我們在程式執行時,一個物件想要檢視自己所擁有的成員屬性,該如何操作? 那再考慮這樣另一個場景,如果我們想要在執行期獲得某個類Class的資訊如它

利用java反射機制模擬spring IOC原理的實現

在Java中反射和動態代理機制很強大,通過反射機制在執行時獲取資訊。用於實現IOC。 代理是Java基本的設計模式,提供向物件插入額外的或不同的操作。Java的動態代理能動態的建立代理物件,以及動態的呼叫代理方法。用於實現AOP。一、Java反射機制1、作用 (1)在執行時判斷任意一個物件所屬的類; (

番外 01:Spring IoC 實現原理簡析,Java反射機制,通過類名建立物件

轉載請註明來源 賴賴的部落格 前景概要 在 01 走進Spring,Context、Bean和IoC 中,我們看到了強大的Spring通過ApplicationContext實現了bean工廠(也就是物件工廠),那究竟是怎麼實現的呢,本次給大家寫一個小D

Java反射機制模擬Spring IOC容器

Ref: java反射機制 package reflection; import java.lang.reflect.Method; public class InvokeTest { public String add(int param1, int p

Spring使用Hibernate和再加SpringData時配置的差別基於Java配置

.sh for packages bean java配置 gem springmvc nbsp mod 只使用Spring+Hibernate 配置DataSource、LocalSessionFactoryBean、HibernateTransactionManager

轉載 JAVA spring ioc原理 原文地址:http://blog.csdn.net/it_man/article/details/4402245

nbsp animal 很難 details 如何實現 拋出異常 感覺 註入 extend 最近,買了本Spring入門書:spring In Action 。大致瀏覽了下感覺還不錯。就是入門了點。Manning的書還是不錯的,我雖然不像哪些只看Manning書的人那樣專註

基於Java反射的map自動裝配JavaBean工具類設計

person urn exception map.entry ati test javabean 好的 declare 我們平時在用Myabtis時不是常常需要用map來傳遞參數,大體是如下的步驟: public List<Role> findRoles(M

Spring(八)之基於Java配置

onf 需要 rgs ava poi .com class 解釋 mes 基於 Java 的配置 到目前為止,你已經看到如何使用 XML 配置文件來配置 Spring bean。如果你熟悉使用 XML 配置,那麽我會說,不需要再學習如何進行基於 Java 的配置是,因為你要

《阿里巴巴MongoDB4.0高階實戰:基於Java Spring Boot 2.0》運維、監控、聚合、叢集、監控等高階面試題

《阿里巴巴MongoDB4.0高階實戰》阿里巴巴技術大牛 資深專家P9葉翔、專家徐雷.  NoSQL排名第一!最流行的NoSQL資料庫;谷歌、阿里巴巴、螞蟻金服、騰訊、百度等一線網際網路公司必備技能。 本系列課程涵蓋:MongoDB入門命令、管理、聚合分析、核心架構、資料庫管理、匯入匯出、索引、