【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,DefaultListableBeanFactory,GenericApplicationContext等。
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】
這裡寫程式碼片