1. 程式人生 > >【Spring4揭祕 基礎5】BeanDefinition及讀取、註冊

【Spring4揭祕 基礎5】BeanDefinition及讀取、註冊

一、 BeanDefinition及其實現類

BeanDefinition介面

這個介面描述bean的結構,對應XML中的< bean >或者配置類中的@Bean
它繼承了BeanMetadataElement和AttributeAccessor介面,如下圖
這裡寫圖片描述

【AttributeAccessor介面】

類似於map,具有儲存和訪問name/value屬性的能力。

public interface AttributeAccessor { 
    void setAttribute(String name, Object value); 
    Object getAttribute(String
name); Object removeAttribute(String name); boolean hasAttribute(String name); String[] attributeNames(); }

【BeanMetadataElement介面】

具有訪問source(配置源)的能力。

public interface BeanMetadataElement { 
    Object getSource(); 
}

【BeanDefinition介面】

定義了設定、獲取一個BeanDefinition屬性方便方法(比如獲取scope屬性直接使用getScope())

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    //單例或原型
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; 
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

     //Bean角色
    int ROLE_APPLICATION = 0; 
    int ROLE_SUPPORT = 1
; int ROLE_INFRASTRUCTURE = 2; // 返回/設定父BeanDefinition String getParentName(); void setParentName(String parentName); //返回/設定 當前的BeanClassName(不等於最終Bean的名稱) String getBeanClassName(); void setBeanClassName(String beanClassName); //返回設定 factory bean name String getFactoryBeanName(); void setFactoryBeanName(String factoryBeanName); String getFactoryMethodName(); void setFactoryMethodName(String factoryMethodName); String getScope(); void setScope(String scope); boolean isLazyInit(); void setLazyInit(boolean lazyInit); String[] getDependsOn(); void setDependsOn(String... dependsOn); boolean isAutowireCandidate(); void setAutowireCandidate(boolean autowireCandidate); boolean isPrimary(); void setPrimary(boolean primary); ConstructorArgumentValues getConstructorArgumentValues(); MutablePropertyValues getPropertyValues(); boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); int getRole(); String getDescription(); String getResourceDescription(); BeanDefinition getOriginatingBeanDefinition(); }

BeanDefinition的子介面和實現類

這裡寫圖片描述

【AnnotatedBeanDefinition 介面】

這個介面可以獲取BeanDefinition註解相關資料

public interface AnnotatedBeanDefinition extends BeanDefinition { 
    AnnotationMetadata getMetadata(); 
    MethodMetadata getFactoryMethodMetadata(); 
}

【AbstractBeanDefinition】

這個抽象類的構造方法設定了BeanDefinition的預設屬性,重寫了equals,hashCode,toString方法。

【ChildBeanDefinition】

可以從父BeanDefinition中整合構造方法,屬性等

【RootBeanDefinition】

代表一個從配置源(XML,Java Config等)中生成的BeanDefinition

GenericBeanDefinition

GenericBeanDefinition是自2.5以後新加入的bean檔案配置屬性定義類,是ChildBeanDefinition和RootBeanDefinition更好的替代者

【AnnotatedGenericBeanDefinition】

對應註解@Bean

@Component("t")
public class Tester {
    public static void main(String[] args) throws Exception {
        AnnotatedGenericBeanDefinition beanDefinition=new AnnotatedGenericBeanDefinition(Tester.class);
        System.out.println(beanDefinition.getMetadata().getAnnotationTypes());
        System.out.println(beanDefinition.isSingleton());
        System.out.println(beanDefinition.getBeanClassName()); 
    }
}

==========輸出==============
[org.springframework.stereotype.Component]
true
Tester

二 、BeanDefinitionHolder

BeanDefinitionHolder

持有一個BeanDefinition,名稱,和別名陣列。在Spring內部,它用來臨時儲存BeanDefinition來傳遞BeanDefinition。
它的部分方法如下:

public class BeanDefinitionHolder implements BeanMetadataElement {

    private final BeanDefinition beanDefinition;
    private final String beanName;
    private final String[] aliases; 

    public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, String[] aliases) {
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        Assert.notNull(beanName, "Bean name must not be null");
        this.beanDefinition = beanDefinition;
        this.beanName = beanName;
        this.aliases = aliases;
    }  
    public BeanDefinition getBeanDefinition() {
        return this.beanDefinition;
    } 
    public String getBeanName() {
        return this.beanName;
    } 
    public String[] getAliases() {
        return this.aliases;
    }
    //其他方法...省略

三、BeanDefinitionRegistry介面

這個介面定義了‘註冊/獲取BeanDefinition’的方法 。
介面定義:

public interface BeanDefinitionRegistry extends AliasRegistry {
    //註冊一個BeanDefinition  
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException; 
    //根據name,從自己持有的多個BeanDefinition 中 移除一個 
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    // 獲取某個BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; 
    boolean containsBeanDefinition(String beanName);//是否包含 
    String[] getBeanDefinitionNames();//獲取所有名稱 
    int getBeanDefinitionCount();//獲取持有的BeanDefinition數量 
    boolean isBeanNameInUse(String beanName); //判斷某個BeanDefinition是否在使用
}

實現類一般使用Map儲存多個BeanDefinition,如下:

Map<String, BeanDefinition> beanDefinitionMap = new HashMap<String, BeanDefinition>();

實現類有SimpleBeanDefinitionRegistry,DefaultListableBeanFactoryGenericApplicationContext等。

SimpleBeanDefinitionRegistry

SimpleBeanDefinitionRegistry是最基本的實現類。
使用:

public static void main(String[] args) throws Exception {

    //例項化SimpleBeanDefinitionRegistry
    SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();

    //註冊兩個BeanDefinition
    BeanDefinition definition_1 = new GenericBeanDefinition();
    registry.registerBeanDefinition("d1", definition_1);

    BeanDefinition definition_2 = new RootBeanDefinition();
    registry.registerBeanDefinition("d2", definition_2);

    //方法測試
    System.out.println(registry.containsBeanDefinition("d1"));//true
    System.out.println(registry.getBeanDefinitionCount());//2
    System.out.println(Arrays.toString(registry.getBeanDefinitionNames()));//[d1, d2] 
}

================結果==================
true
2
[d1, d2]

四、BeanDefinitionReader介面

BeanDefinitionRegistry介面一次只能註冊一個BeanDefinition,而且只能自己構造BeanDefinition類來註冊。BeanDefinitionReader解決了這些問題,它一般可以使用一個BeanDefinitionRegistry構造,然後通過#loadBeanDefinitions(..)等方法,把“配置源”轉化為多個BeanDefinition並註冊到BeanDefinitionRegistry中 。
可以說BeanDefinitionReader幫助BeanDefinitionRegistry實現了高效、方便的註冊BeanDefinition。

BeanDefinitionReader介面定義如下:

public interface BeanDefinitionReader {
    //獲取BeanDefinitionRegistry 
    BeanDefinitionRegistry getRegistry();

    ResourceLoader getResourceLoader();

    ClassLoader getBeanClassLoader(); 

    //獲取Bean的名稱生成器
    BeanNameGenerator getBeanNameGenerator();

    //載入BeanDefinition
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

     //載入BeanDefinition
    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

     //載入BeanDefinition
    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

     //載入BeanDefinition
    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

}

類的體系結構

這裡寫圖片描述

AbstractBeanDefinitionReader:實現了EnvironmentCapable,提供了獲取/設定環境的方法。定義了一些通用方法,使用策略模式,將一些具體方法放到子類實現。
XmlBeanDefinitionReader:讀取XML檔案定義的BeanDefinition
PropertiesBeanDefinitionReader:可以從屬性檔案,Resource,Property物件等讀取BeanDefinition
GroovyBeanDefinitionReader:可以讀取Groovy語言定義的Bean

實現類:XmlBeanDefinitionReader

把xml配置檔案轉化成beanDefinition

這個類就不做演示了

實現類: PropertiesBeanDefinitionReader

可以從Properties檔案讀取BeanDefinition,檔案可以是如下結構:

#bean名稱.(屬性)=值
==========================
mybean.(class)=PropertyReaderTest
mybean.(abstract)=true 
mybean.(lazy-init)=true
mybean.(scope)=prototype    

程式例項:

public class PropertyReaderTest {
    public static void main(String[] args) {
        //定義BeanDefinitionRegistry 
        BeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry(); 
        //使用BeanDefinitionRegistry例項 構造BeanDefinitionReader
        PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(registry);
        //載入檔案
        reader.loadBeanDefinitions("config.properties");

        System.out.println(registry.getBeanDefinition("mybean"));
    }
} 

================輸出=================
.......//日誌資訊 略
Generic bean: class [PropertyReaderTest]; scope=prototype; abstract=true; lazyInit=true; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

五、讀取註解定義的BeanDefinition

註解相關的BeanDefinitionReader並沒有實現BeanDefinitionReader介面,有如下類:

AnnotatedBeanDefinitionReader類

使用如下:

SimpleBeanDefinitionRegistry registry= new SimpleBeanDefinitionRegistry();
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
reader.register(Tester.class);
System.out.println( registry.getBeanDefinitionCount());

=========================
7 

我們只註冊了一個Bean,為什麼出現7個呢?原來是AnnotatedBeanDefinitionReader 向BeanDefinitionRegistry自動註冊了6個BeanDefinition。這個在以後章節中詳解。

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner 繼承自ClassPathScanningCandidateComponentProvider
類結構如下:
這裡寫圖片描述

【ClassPathScanningCandidateComponentProvider】
這個類的findCandidateComponents可以掃描到@Component @Repository @Service @Controller 的BeanDefinition,並加入Set 集合中

ClassPathScanningCandidateComponentProvider provider=new ClassPathScanningCandidateComponentProvider(true); 
Set<BeanDefinition> definitionSet= provider.findCandidateComponents("com.jazz.web");
System.out.println(definitionSet.size());

【ClassPathBeanDefinitionScanner】

這裡寫程式碼片