天天看點

Spring入門及bean配置(XML、注解)一、概述二、bean與spring容器的關系三、bean配置四、Bean注入

目錄

一、概述

二、bean與spring容器的關系

三、bean配置

3.1 基于xml配置Bean

3.1.1 Bean基本配置

3.1.2 依賴注入

3.2 使用注解定義Bean

3.2.1 使用注解配置資訊啟動spring容器

3.3 基于java類提供Bean定義

四、Bean注入

4.1 在xml檔案中配置依賴注入

4.1.1 屬性注入

4.1.2 構造方法注入

4.1.3 工廠方法注入

4.2 使用注解的方式注入

4.2.1 使用@Autowired進行自動注入

4.2.2 使用@Autowired的required屬性

4.2.3 使用@Qualifier指定注入Bean的名稱

4.2.4 對類方法進行标注

4.2.5 對标準注解的支援

4.2.6 關于Autowired和@Resource

4.2.7 讓@Resource和@Autowired生效的幾種方式

一、概述

Spring是一個開放源代碼的設計層面架構,他解決的是業務邏輯層和其他各層的松耦合問題,是以它将面向接口的程式設計思想貫穿整個系統應用。Spring是于2003 年興起的一個輕量級的Java 開發架構,由Rod Johnson建立。簡單來說,Spring是一個分層的JavaSE/EE full-stack(一站式) 輕量級開源架構(摘自:百度百科)

二、bean與spring容器的關系

Spring入門及bean配置(XML、注解)一、概述二、bean與spring容器的關系三、bean配置四、Bean注入

Bean配置資訊定義了Bean的實作及依賴關系,Spring容器根據各種形式的Bean配置資訊在容器内部建立Bean定義系統資料庫,然後根據系統資料庫加載、執行個體化Bean,并建立Bean和Bean的依賴關系,最後将這些準備就緒的Bean放到Bean緩存池中,以供外層的應用程式進行調用。

三、bean配置

bean配置有三種方法:

  • 基于xml配置Bean
  • 使用注解定義Bean
  • 基于java類提供Bean定義資訊

3.1 基于xml配置Bean

 對于基于XML的配置,Spring 2.0以後使用Schema的格式,使得不同類型的配置擁有了自己的命名空間,是配置檔案更具擴充性。

Spring入門及bean配置(XML、注解)一、概述二、bean與spring容器的關系三、bean配置四、Bean注入

①預設命名空間:它沒有空間名,用于Spring Bean的定義;

②xsi命名空間:這個命名空間用于為每個文檔中命名空間指定相應的Schema樣式檔案,是标準組織定義的标準命名空間;

③aop命名空間:這個命名空間是Spring配置AOP的命名空間,是使用者自定義的命名空間。

命名空間的定義分為兩個步驟:第一步指定命名空間的名稱;第二步指定命名空間的Schema文檔樣式檔案的位置,用空格或回車換行進行分分隔。

3.1.1 Bean基本配置

在Spring容器的配置檔案中定義一個簡要Bean的配置片段如下所示:

Spring入門及bean配置(XML、注解)一、概述二、bean與spring容器的關系三、bean配置四、Bean注入

一般情況下,Spring IOC容器中的一個Bean即對應配置檔案中的一個<bean>,這種鏡像對應關系應該容易了解。其中id為這個Bean的名稱,通過容器的getBean("foo")即可擷取對應的Bean,在容器中起到定位查找的作用,是外部程式和Spring IOC容器進行互動的橋梁。class屬性指定了Bean對應的實作類。

下面是基于XML的配置檔案定義了兩個簡單的Bean:

<?xml version="1.0" encoding="UTF-8" ?>
<beans   xmlns="http://www.springframework.org/schema/beans" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     <bean id="car" name="#car1" class="com.baobaotao.simple.Car"></bean>  
     <bean id="boss" class="com.baobaotao.simple.Boss"></bean>
</beans>
           

3.1.2 依賴注入

  1. 屬性注入
  2. 構造函數注入
  3. 工廠方式注入

3.2 使用注解定義Bean

我們知道,Spring容器成功啟動的三大要件分别是:Bean定義資訊、Bean實作類以及Spring本身。如果采用基于XML的配置,Bean定義資訊和Bean實作類本身是分離的,而采用基于注解的配置方式時,Bean定義資訊即通過在Bean實作類上标注注解實作。

下面是使用注解定義一個DAO的Bean:

package com.baobaotao.anno;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
//①通過Repository定義一個DAO的Bean

@Component("userDao")
public class UserDao {

}
           

在①處,我們使用@Component注解在UserDao類聲明處對類進行标注,它可以被Spring容器識别,Spring容器自動将POJO轉換為容器管理的Bean。

它和以下的XML配置是等效的:

<bean id="userDao" class="com.baobaotao.anno.UserDao"/>
           

除了@Component以外,Spring提供了3個功能基本和@Component等效的注解,它們分别用于對DAO、Service及Web層的Controller進行注解,是以也稱這些注解為Bean的衍型注解:(類似于xml檔案中定義Bean<bean id=" " class=" "/>

  • @Repository:用于對DAO實作類進行标注;
  • @Service:用于對Service實作類進行标注;
  • @Controller:用于對Controller實作類進行标注;

之是以要在@Component之外提供這三個特殊的注解,是為了讓注解類本身的用途清晰化,此外Spring将賦予它們一些特殊的功能。

3.2.1 使用注解配置資訊啟動spring容器

Spring提供了一個context的命名空間,它提供了通過掃描類包以應用注解定義Bean的方式:

<?xml version="1.0" encoding="UTF-8" ?>
<!--①聲明context的命名空間-->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd"
         >
    <!--②掃描類包以應用注解定義的Bean-->
   <context:component-scan base-package="com.baobaotao.anno"/>
   <bean class="com.baobaotao.anno.LogonService"></bean>
   <!-- context:component-scan base-package="com.baobaotao" resource-pattern="anno/*.class"/ -->
   <!-- context:component-scan base-package="com.baobaotao">
       <context:include-filter type="regex" expression="com\.baobaotao\.anno.*Dao"/>
       <context:include-filter type="regex" expression="com\.baobaotao\.anno.*Service"/>
       <context:exclude-filter type="aspectj" expression="com.baobaotao..*Controller+"/>
   </context:component-scan -->
</beans>
           

在①處聲明context命名空間,在②處即可通過context命名空間的component-scan的base-package屬性指定一個需要掃描的基類包,Spring容器将會掃描這個基類包裡的所有類,并從類的注解資訊中擷取Bean的定義資訊。

如果僅希望掃描特定的類而非基包下的所有類,你們可以使用resource-pattern屬性過濾特定的類,如下所示:

<context:component-scan base-package="com.baobaotao" resource-pattern="anno/*.class"/>
           

這裡我們将基類包設定為com.baobaotao,預設情況下resource-pattern屬性的值為"**/*.class",即基類包裡的所有類。這裡我們設定為"anno/*.class",則Spring僅會掃描基包裡anno子包中的類。

3.3 基于java類提供Bean定義

在普通的POJO類中隻要标注@Configuration注解,就可以為spring容器提供Bean定義的資訊了,每個标注了@Bean的類方法都相當于提供了一個Bean的定義資訊。

package com.baobaotao.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//①将一個POJO标注為定義Bean的配置類
@Configuration
public class AppConf {
        //②以下兩個方法定義了兩個Bean,以提供了Bean的執行個體化邏輯
    @Bean
    public UserDao userDao(){
       return new UserDao();    
    }
    
    @Bean
    public LogDao logDao(){
        return new LogDao();
    }
    //③定義了logonService的Bean
    @Bean
    public LogonService logonService(){
        LogonService logonService = new LogonService();
                //④将②和③處定義的Bean注入到LogonService Bean中
        logonService.setLogDao(logDao());
        logonService.setUserDao(userDao());
        return logonService;
    }
}
           

①處在APPConf類的定義處标注了@Configuration注解,說明這個類可用于為Spring提供Bean的定義資訊。類的方法處可以标注@Bean注解,Bean的類型由方法傳回值類型決定,名稱預設和方法名相同,也可以通過入參顯示指定Bean名稱,如@Bean(name="userDao").直接在@Bean所标注的方法中提供Bean的執行個體化邏輯。

在②處userDao()和logDao()方法定義了一個UserDao和一個LogDao的Bean,它們的Bean名稱分别是userDao和logDao。在③處,又定義了一個logonService Bean,并且在④處注入②處所定義的兩個Bean。

是以,以上的配置和以下XML配置時等效的:

<bean id="userDao" class="com.baobaotao.anno.UserDao"/>
<bean id="logDao" class="com.baobaotao.anno.LogDao"/>
<bean id="logService" class="com.baobaotao.conf.LogonService"
    p:logDao-ref="logDao" p:userDao-ref="userDao"/>
           

基于java類的配置方式和基于XML或基于注解的配置方式相比,前者通過代碼的方式更加靈活地實作了Bean的執行個體化及Bean之間的裝配,但後面兩者都是通過配置聲明的方式,在靈活性上要稍遜一些,但是配置上要更簡單一些。

四、Bean注入

Bean注入的方式有兩種,一種是在XML中配置,此時分别有屬性注入、構造函數注入和工廠方法注入;另一種則是使用注解的方式注入 @Autowired,@Resource,@Required。

4.1 在xml檔案中配置依賴注入

4.1.1 屬性注入

屬性注入即通過setXxx()方法注入Bean的屬性值或依賴對象,由于屬性注入方式具有可選擇性和靈活性高的優點,是以屬性注入是實際應用中最常采用的注入方式。

屬性注入要求Bean提供一個預設的構造函數,并為需要注入的屬性提供對應的Setter方法。Spring先調用Bean的預設構造函數執行個體化Bean對象,然後通過反射的方式調用Setter方法注入屬性值。

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware;

public class LogonService implements BeanNameAware{

    private LogDao logDao;

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setLogDao(LogDao logDao) {
        this.logDao = logDao;
    }
    
    public LogDao getLogDao() {
        return logDao;
    }
    public UserDao getUserDao() {
        return userDao;
    }
    
    public void setBeanName(String beanName) {
        System.out.println("beanName:"+beanName);        
    }
    
    public void initMethod1(){
        System.out.println("initMethod1");
    }
    public void initMethod2(){
        System.out.println("initMethod2");
    }
    
}
           

bean.xml配置

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd"
       default-autowire="byName"
         >
    <bean id="logDao" class="com.baobaotao.anno.LogDao"/>
    <bean id="userDao" class="com.baobaotao.anno.UserDao"/>
   <bean class="com.baobaotao.anno.LogonService">
       <property name="logDao" ref="logDao"></property>
       <property name="userDao" ref="userDao"></property>
   </bean>
</beans>
           

4.1.2 構造方法注入

使用構造函數注入的前提是Bean必須提供帶參數的構造函數。例如

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware;

public class LogonService implements BeanNameAware{

    public LogonService(){}

    public LogonService(LogDao logDao, UserDao userDao) {
        this.logDao = logDao;
        this.userDao = userDao;
    }

    private LogDao logDao;

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setLogDao(LogDao logDao) {
        this.logDao = logDao;
    }
    
    public LogDao getLogDao() {
        return logDao;
    }
    public UserDao getUserDao() {
        return userDao;
    }
    
    public void setBeanName(String beanName) {
        System.out.println("beanName:"+beanName);        
    }
    
    public void initMethod1(){
        System.out.println("initMethod1");
    }
    public void initMethod2(){
        System.out.println("initMethod2");
    }
    
}
           

bean.xml配置

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-3.0.xsd"
       default-autowire="byName">

    <bean id="logDao" class="com.baobaotao.anno.LogDao"/>
    <bean id="userDao" class="com.baobaotao.anno.UserDao"/>
   <bean class="com.baobaotao.anno.LogonService">
      <constructor-arg  ref="logDao"></constructor-arg>
       <constructor-arg ref="userDao"></constructor-arg>
   </bean>

</beans>
           

4.1.3 工廠方法注入

非靜态工廠方法:

有些工廠方法是非靜态的,即必須執行個體化工廠類後才能調用工廠放。

package com.baobaotao.ditype;

public class CarFactory {
   public Car createHongQiCar(){
       Car car = new Car();
       car.setBrand("紅旗CA72");
       return car;
   }
   
   public static Car createCar(){
       Car car = new Car();
       return car;
   }
}
           

工廠類負責建立一個或多個目标類執行個體,工廠類方法一般以接口或抽象類變量的形式傳回目标類執行個體,工廠類對外屏蔽了目标類的執行個體化步驟,調用者甚至不用知道具體的目标類是什麼。

<?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-3.0.xsd">

    <!-- 工廠方法-->
    <bean id="carFactory" class="com.baobaotao.ditype.CarFactory" />
    <bean id="car5" factory-bean="carFactory" factory-method="createHongQiCar">
    </bean>


</beans>
           

靜态工廠方法:

很多工廠類都是靜态的,這意味着使用者在無須建立工廠類執行個體的情況下就可以調用工廠類方法,是以,靜态工廠方法比非靜态工廠方法的調用更加友善。

<?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-3.0.xsd">

    <bean id="car6" class="com.baobaotao.ditype.CarFactory"
        factory-method="createCar"></bean>

</beans>
           

4.2 使用注解的方式注入

4.2.1 使用@Autowired進行自動注入

Spring通過@Autowired注解實作Bean的依賴注入,下面是一個例子:

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
//① 定義一個Service的Bean(不需要在XML中定義Bean)
@Service
public class LogonService implements BeanNameAware{
        //② 分别注入LogDao及UserDao的Bean(不需要在XML中定義property屬性注入)
    @Autowired(required=false)
    private LogDao logDao;
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
    
    public LogDao getLogDao() {
        return logDao;
    }
    public UserDao getUserDao() {
        return userDao;
    }
    
    public void setBeanName(String beanName) {
        System.out.println("beanName:"+beanName);        
    }
    
    public void initMethod1(){
        System.out.println("initMethod1");
    }
    public void initMethod2(){
        System.out.println("initMethod2");
    }
    
}
 
           

在①處,我們使用@Service将LogonService标注為一個Bean,在②處,通過@Autowired注入LogDao及UserDao的Bean。@Autowired預設按類型比對的方式,在容器查找比對的Bean,當有且僅有一個比對的Bean時,Spring将其注入到@Autowired标注的變量中。

4.2.2 使用@Autowired的required屬性

如果容器中沒有一個和标注變量類型比對的Bean,Spring容器啟動時将報NoSuchBeanDefinitionException的異常。如果希望Spring即使找不到比對的Bean完成注入也不用抛出異常,那麼可以使用@Autowired(required=false)進行标注:

@Service
public class LogonService implements BeanNameAware{
    @Autowired(required=false)
    private LogDao logDao;
        ...
}
           

預設情況下,@Autowired的required屬性的值為true,即要求一定要找到比對的Bean,否則将報異常。

4.2.3 使用@Qualifier指定注入Bean的名稱

如果容器中有一個以上比對的Bean時,則可以通過@Qualifier注解限定Bean的名稱,如下所示:

@Service
public class LogonService implements BeanNameAware{
    @Autowired(required=false)
    private LogDao logDao;
    //①注入名為UserDao,類型為UserDao的Bean
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
}
           

這裡假設容器有兩個類型為UserDao的Bean,一個名為userDao,另一個名為otherUserDao,則①處會注入名為userDao的Bean。

4.2.4 對類方法進行标注

@Autowired可以對類成員變量及方法的入參進行标注,下面我們在類的方法上使用@Autowired注解:

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class LogonService implements BeanNameAware{
    
    private LogDao logDao;
    private UserDao userDao;
    
    
    @Autowired
    public void setLogDao(LogDao logDao) {
        this.logDao = logDao;
    }
    
    @Autowired
    @Qualifier("userDao")
    public void setUserDao(UserDao userDao) {
        System.out.println("auto inject");
        this.userDao = userDao;
    }
    
}
           

如果一個方法擁有多個入參,在預設情況下,Spring自動選擇比對入參類型的Bean進行注入。Spring允許對方法入參标注@Qualifier以指定注入Bean的名稱,如下所示:

@Autowired
public void init(@Qualifier("userDao")UserDao userDao,LogDao logDao){
    System.out.println("multi param inject");
    this.userDao = userDao;
    this.logDao =logDao;
}
           

在以上例子中,UserDao的入參注入名為userDao的Bean,而LogDao的入參注入LogDao類型的Bean。

一般情況下,在Spring容器中大部分的Bean都是單執行個體的,是以我們一般都無須通過@Repository、@Service等注解的value屬性為Bean指定名稱,也無須使用@Qualifier按名稱進行注入。

4.2.5 對标準注解的支援

此外,Spring還支援@Resource和@Inject注解,這兩個标準注解和@Autowired注解的功能類型,都是對類變量及方法入參提供自動注入的功能。@Resource要求提供一個Bean名稱的屬性,如果屬性為空,則自動采用标注處的變量名或方法名作為Bean的名稱。

package com.baobaotao.anno;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.stereotype.Component;

@Component
public class Boss {
    
    private Car car;
    
    public Boss(){
        System.out.println("construct...");
    }

//    @Autowired
//    private void setCar(Car car){
//        System.out.println("execute in setCar");
//        this.car = car;
//    }
    
    @Resource("car")
    private void setCar(Car car){
        System.out.println("execute in setCar");
        this.car = car;
    }
    
    @PostConstruct
    private void init1(){
        System.out.println("execute in init1");
    }
    
    @PostConstruct
    private void init2(){
        System.out.println("execute in init1");
    }
    
    @PreDestroy
    private void destory1(){
        System.out.println("execute in destory1");
    }
    
    @PreDestroy
    private void destory2(){
        System.out.println("execute in destory2");
    }

}
           

這時,如果@Resource未指定"car"屬性,則也可以根據屬性方法得到需要注入的Bean名稱。可見@Autowired預設按類型比對注入Bean,@Resource則按名稱比對注入Bean。而@Inject和@Autowired一樣也是按類型比對注入的Bean的,隻不過它沒有required屬性。可見不管是@Resource還是@Inject注解,其功能都沒有@Autowired豐富,是以除非必須,大可不必在乎這兩個注解。(類似于Xml中使用<constructor-arg ref="logDao"></constructor-arg>或者<property name="logDao" ref="logDao"></property>進行注入,如果使用了@Autowired或者Resource等,這不需要在定義Bean時使用屬性注入和構造方法注入了)

4.2.6 關于Autowired和@Resource

[email protected]注入是按照類型注入的,隻要配置檔案中的bean類型和需要的bean類型是一緻的,這時候注入就沒問題。但是如果相同類型的bean不止一個,此時注入就會出現問題,Spring容器無法啟動。 

[email protected]标簽是按照bean的名字來進行注入的,如果我們沒有在使用@Resource時指定bean的名字,同時Spring容器中又沒有該名字的bean,這時候@Resource就會退化為@Autowired即按照類型注入,這樣就有可能違背了使用@Resource的初衷。是以建議在使用@Resource時都顯示指定一下bean的名字@Resource(name="xxx") 

4.2.7 讓@Resource和@Autowired生效的幾種方式

1.在xml配置檔案中顯式指定 

<!-- 為了使用Autowired标簽,我們必須在這裡配置一個bean的後置處理器 -->  
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />   
      
<!-- 為了使用@Resource标簽,這裡必須配置一個後置處理器 -->  
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />   
           

2.在xml配置檔案中使用context:annotation-config 

<context:annotation-config />
           

3.在xml配置檔案中使用context:component-scan 

<context:component-scan base-package="com.baobaotao.anno"/>
           

4.重寫Spring容器的Context,在自定義BeanFactory時調用AnnotationConfigUtils.registerAnnotationConfigProcessors()把這兩個注解處理器增加到容器中。 

一開始使用公司架構的時候發現可以在web層使用@Resource以及@Autowired來注入一些bean,首先這個注解是Spring提供的,自己把這部分代碼抽出來寫了小例子,發現要想使用Spring的這兩注解,必須直接或者間接的引入AutowiredAnnotationBeanPostProcesso以及CommonAnnotationBeanPostProcessor這兩個注解處理器引入到BeanDefinitions中,否則不會實作注入的,但是仔細閱讀公司架構代碼後發現沒有地方直接或間接引入這兩個注解處理器,發現一個細節,公司架構所依賴的Spring版本是2.5.6而我使用的Spring版本是2.5.5,當初的結論是高版本的Spring在容器啟動的時候,自動把這兩個注解處理器加入到BeanDefinitions中,這幾天仔細看了看Spring的源代碼,發現Spring2.5.6并沒有這樣做。然後子寫DEBUG了一下公司架構的源代碼,最後發現原來公司架構有一個自己的XmlWebApplicationContext,在這個context中重寫customizeBeanFactory(),在這個方法中調用了AnnotationConfigUtils.registerAnnotationConfigProcessors()方法把這兩自動注解處理器加入到BeanDefinitions中,這樣公司架構在web層就支援@Resource和@Autowired進行自動注入啦

Spring入門及bean配置(XML、注解)一、概述二、bean與spring容器的關系三、bean配置四、Bean注入
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.citrus.springext.support.context;

import com.alibaba.citrus.springext.ResourceLoadingExtendable;
import com.alibaba.citrus.springext.ResourceLoadingExtender;
import com.alibaba.citrus.springext.support.context.InheritableListableBeanFactory;
import com.alibaba.citrus.springext.support.resolver.XmlBeanDefinitionReaderProcessor;
import java.io.IOException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;

public class XmlWebApplicationContext extends org.springframework.web.context.support.XmlWebApplicationContext implements ResourceLoadingExtendable {
    private ResourceLoadingExtender resourceLoadingExtender;
    private boolean parentResolvableDependenciesAccessible = true;

    public XmlWebApplicationContext() {
    }

    public boolean isParentResolvableDependenciesAccessible() {
        return this.parentResolvableDependenciesAccessible;
    }

    public void setParentResolvableDependenciesAccessible(boolean parentResolvableDependenciesAccessible) {
        this.parentResolvableDependenciesAccessible = parentResolvableDependenciesAccessible;
    }

    public void setResourceLoadingExtender(ResourceLoadingExtender resourceLoadingExtender) {
        if(this.resourceLoadingExtender != null) {
            this.getApplicationListeners().remove(this.resourceLoadingExtender);
        }

        this.resourceLoadingExtender = resourceLoadingExtender;
        if(resourceLoadingExtender instanceof ApplicationListener) {
            this.addApplicationListener((ApplicationListener)resourceLoadingExtender);
        }

    }

    protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
        (new XmlBeanDefinitionReaderProcessor(beanDefinitionReader)).addConfigurationPointsSupport();
    }

    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        super.customizeBeanFactory(beanFactory);
    //AnnotationConfigUtils.registerAnnotationConfigProcessors()方法把這兩自動注解處理器加入到BeanDefinitions中,這樣公司架構在web層就支援@Resource和@Autowired進行自動注入
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory, (Object)null);
    }

    protected DefaultListableBeanFactory createBeanFactory() {
        return (DefaultListableBeanFactory)(this.isParentResolvableDependenciesAccessible()?new InheritableListableBeanFactory(this.getInternalParentBeanFactory()):super.createBeanFactory());
    }

    protected Resource getResourceByPath(String path) {
        Resource resource = null;
        if(this.resourceLoadingExtender != null) {
            resource = this.resourceLoadingExtender.getResourceByPath(path);
        }

        if(resource == null) {
            resource = super.getResourceByPath(path);
        }

        return resource;
    }

    protected ResourcePatternResolver getResourcePatternResolver() {
        final ResourcePatternResolver defaultResolver = super.getResourcePatternResolver();
        return new ResourcePatternResolver() {
            public Resource[] getResources(String locationPattern) throws IOException {
                ResourcePatternResolver resolver = null;
                if(XmlWebApplicationContext.this.resourceLoadingExtender != null) {
                    resolver = XmlWebApplicationContext.this.resourceLoadingExtender.getResourcePatternResolver();
                }

                if(resolver == null) {
                    resolver = defaultResolver;
                }

                return resolver.getResources(locationPattern);
            }

            public ClassLoader getClassLoader() {
                return defaultResolver.getClassLoader();
            }

            public Resource getResource(String location) {
                return defaultResolver.getResource(location);
            }
        };
    }
}
           

轉自:https://www.cnblogs.com/wuchanming/p/5426746.html