spring類結構
beanFactory結構
todo
applicationContext結構
todo
beanDefinition結構
BeanDefinition是頂層接口,定義了bean的各種屬性锤躁,包括是否懶加載荔烧,類名稱等等哼转,所有bean的基本屬性都是應該通過這個接口獲取议街。BeanDefinition直接繼承的是接口AnnotatedBeanDefinition與AbstractBeanDefinition抽象類,AnnotatedBeanDefinition是在BeanDefinition基礎上增加了AnnotationMetadata屬性數據,這個接口可以理解為帶注解的BeanDefinition;AbstractBeanDefinition是對BeanDefinition的基本實現张抄,把BeanDefinition中大部分方法都實現了,然后這個抽象類有三個子類RootBeanDefinition洼怔、ChildBeanDefinition欣鳖、GenericBeanDefinition,對于前面兩個父子類茴厉,是因為我們定義bean的時候泽台,是可以有parent關系的什荣,RootBeanDefinition是一種merged過的BeanDefinition,是完整的BeanDefinition怀酷,而childBeanDefinition是不完整的BeanDefinition稻爬,必須要包含parent的BeanDefinition;GenericBeanDefinition是新的BeanDefinition蜕依,是用來替換那個root跟child的桅锄,后面新的beandefinition都是基于GenericBeanDefinition實現的。再來看下AnnotatedBeanDefinition的子類有兩個ScannedGenericBeanDefinition跟AnnotatedGenericBeanDefinition样眠,這兩個子類都是基于GenericBeanDefinition實現的友瘤,看下這兩個類的實現是差不多的,這兩個類的區(qū)別在與ScannedGenericBeanDefinition是在component-scan的場景下定義的檐束,就是我們注解@ComponentScan或者<context: component-scan>而AnnotatedGenericBeanDefinition應用的場景是springboot的AnnotationConfigApplicationContext里面以及處理@Configuration注解的bean對象的時候用的辫秧。而普通的GenericBeanDefinition注解在xml中定義的bean應用
metadata結構
todo
namespaceHandler結構
todo
spring中的數據結構
todo
spring 的初始化----refresh
spring啟動過程是以ApplicationContext對象的定義來完成bean的初始化與管理的。然后就可以通過這個context的getbean方法獲取對應bean對象被丧。以ClassPathXmlApplicationContext為例盟戏,當我們new一個ClassPathXmlApplicationContext對象的時候,其spring的bean對象已經被加載好了甥桂。
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
上面代碼中是ClassPathXmlApplicationContext的構造函數柿究,configLocations是用戶指定的配置項路徑地址,不是重點黄选,重點在refresh函數
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
prepareRefresh()方法做準備工作蝇摸,實現中沒有做什么事。
bean的加載----obtainFreshBeanFactory
obtainFreshBeanFactory是核心方法步驟办陷,這個方法主要就是構建beanFactory以及加載所有需要定義成bean的對象探入,創(chuàng)建對應的beanDefinition。跟蹤obtainFreshBeanFactory的方法懂诗,發(fā)現springcontext中定義的beanfactory是DefaultListableBeanFactory蜂嗽,這個是spring提供的一個默認的bean工廠實現類。
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
customizeBeanFactory是對這個beanfactory的定制殃恒,這里定制了兩個屬性植旧,一個是allowBeanDefinitionOverriding,就是是否允許bean覆蓋定義离唐,默認是允許的病附,當有兩個相同名字的bean定義時,后者會覆蓋前者亥鬓;另一個是allowCircularReferences完沪,就是是否允許bean的循環(huán)引用,默認是允許的,后面會講spring是如何解決bean的循環(huán)引用的覆积。默認的DefaultListableBeanFactory這兩個配置項是true听皿,不需要修改。
loadBeanDefinitions方法是核心方法宽档,這個方法就是把spring里面所有需要其管理的bean對象給加載起來(只是定義尉姨,沒有初始化)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
這個XmlBeanDefinitionReader是xml文件的bean解析器,代碼到這里吗冤,beanfactory的bean的定義模型beanDefinition的讀取實際是交給beanDefinitionReader這個對象來做的又厉,因為我們開始選擇的是ClassPathXmlApplicationContext,所以這里加載beandefinition是加載的xml形式定義的椎瘟,所以實際上所有的xml中定義的bean的讀取的就是這個對象XmlBeanDefinitionReader完成的覆致。上面的核心代碼在于loadBeanDefinitions(beanDefinitionReader)這個方法,這個方法里面就把applicationContext的loadBeanDefinition動作交給了XmlBeanDefinitionReader去完成肺蔚,實際上就是XmlBeanDefinitionReader進行l(wèi)oadBeanDefinitions
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
這個方法里面是加載bean對象煌妈,getConfigResources獲取資源配置,這個資源配置就是我們在定義ClassPathXmlApplicationContext對象的時候傳入的婆排,如果為空寂拆,則加載默認的配置文件/WEB-INF/applicationContext.xml(用的云服務nuwa容器啟動時候填硕,會將相關的配置資源加載進去)无牵,跟蹤這個loadBeanDefinitions方法可以看到荒叶,reader是遍歷加載configLocations凡伊,由于applicationcontext繼承ResourcePatternResolver伏嗜,說明applicationcontext的resourceLoader是通配符匹配resource路徑垮斯,然后把每個resourcelocation下正則匹配的resource文件進行解析草戈,繼續(xù)跟蹤代碼走到doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
...
}
doLoadBeanDefinitions里面有兩行有效代碼坪创,一個doLoadDocument就是從resource資源文件讀取出來炕婶,加載到Document對象中,這里主要是DOM的解析莱预,不做分析柠掂,另外一個registerBeanDefinitions就是真正將doc中定義的bean解析成beanDefinition對象,注冊到beanfactory中依沮。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
這里BeanDefinitionDocumentReader 對象是用來讀取一個doc文件中的beandefinition的涯贞,每一個resource都被封裝成一個xmlreaderContext (注意這個xmlreaderContext 里面會指定一個NamespaceHandlerResolver,這個resolver是用來解析我們配置的xml的)危喉。調用的方法registerBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
但是這里用了一個BeanDefinitionParserDelegate宋渔,這個delegate是readerContext的代理,這個方法中辜限,核心代碼是parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
解析過程是從root開始的皇拣,每個元素進行解析,根據元素的命名空間區(qū)分是自帶的還是用戶自定義的薄嫡,先看下系統自帶的元素
public static final String ALIAS_ATTRIBUTE = "alias";
public static final String IMPORT_ELEMENT = "import";
public static final String RESOURCE_ATTRIBUTE = "resource";
public static final String NESTED_BEANS_ELEMENT = "beans";
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
可以看出這里就是解析幾種常見的配置bean的元素氧急,注意在處理beans的時候颗胡,是用遞歸的方式處理bean的加載。下面看下custom的方式态蒂,在配置xml中有很多是自定義的杭措,比如<aop/>,<dubbo/>等等,這里講下這些自定義格式的bean的加載與解析钾恢。
自定義標簽----元素解析
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
首先獲取元素的命名空間手素,根據命名空間獲取對應的解析器,然后用解析器去執(zhí)行元素的解析工作瘩蚪,這里看下handler對象是從readerContext中獲取的泉懦,分析下這個handler代碼,getNamespaceHandlerResolver獲取命名空間對應的處理器的解析器疹瘦,spring中提供了一個默認的解析器DefaultNamespaceHandlerResolver崩哩,維護namespace跟handler的解析關系,核心點在于維護一個map言沐,key就是namespace邓嘹,value就是對應的handler
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}
上面的代碼邏輯比較簡單,就是從一個map中獲取這個namespace對應的handler险胰,這個handler對象可以是handler實例本身汹押,也可以是類名稱,如果是類名稱的話起便,就類加載器加載棚贾,NamespaceHandler是一個接口,spring提供了一個適配器類NamespaceHandlerSupport榆综,實現了NamespaceHandler接口的通用方法妙痹,把配置解析綁定到BeanDefinitionParser上,一個配置對應一個BeanDefinitionParser鼻疮,維護到一個map里面怯伊,那么NamespaceHandler的parse接口,就是獲取對應parser來處理判沟。
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
所以我們可以看到一個NamespaceHandler對應的是一種namespace處理器耿芹,一般也是一個xml里面,比如我們說的<dubbo/>對應的就一個DubboNamespaceHandler水评,而一個xml里面可以有多種配置前綴猩系,比如<dubbo/>里面有<dubbo-module/>、<dubbo-protocol/>等中燥,里面每一個小的配置類型對應的是一個parser寇甸,這個parser做的事情就是把對應的配置定義轉換成beanDefinition,注冊到beanfactory中(這個beanfactory在對應的readerContext里面)所以我們看下dubbo的DubboNamespaceHandler的類的定義
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
@Override
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
在init方法地方把每個配置類型以及對應的parser注冊到namespaceHandler里面,然后這個DubboNamespaceHandler又通過SPI方式注冊到NamespaceHandlerResolver里面拿霉,我們看下前面提到的DefaultNamespaceHandlerResolver里面如何加載這些定義的namespaceHandler的吟秩。
private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return this.handlerMappings;
}
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
里面的PropertiesLoaderUtils.loadAllProperties就是用來加載namespaceHandler,這里的this.handlerMappingsLocation 最終初始化的是META-INF/spring.handlers绽淘。至于自定義的parser如何解析這里就不分析了涵防。
里面的PropertiesLoaderUtils.loadAllProperties就是用來加載namespaceHandler,這里的this.handlerMappingsLocation 最終初始化的是META-INF/spring.handlers沪铭。至于自定義的parser如何解析這里就不分析了壮池。
小結
spring對bean的解析(xml)有兩種,原生定義了幾種標簽杀怠,比如<bean>椰憋、<beans>、<import>等赔退,這些spring提供默認的處理橙依,還可以支持拓展的,spring中也拓展了很多bean格式硕旗,比如context標簽窗骑,dubbo也拓展了<dubbo>,拓展bean的標簽的目的是用戶自定義bean的創(chuàng)建方式漆枚。對應的步驟如下:
- 首先要定義dtd文件创译,定義自己要用的標簽元素、屬性以及對應的子元素等等
- 自定義NamespaceHandler子類浪读,可以繼承NamespaceHandlerSupport昔榴,然后對于每個子配置類型辛藻,需要自定義對應的BeanDefinitionParser碘橘,每個parser就是對我們自定義標簽的解析。
- 然后在對應的NamespaceHandler類里面進行注冊----在init方法中調用registerBeanDefinitionParser方法吱肌,把每個parser注冊進去痘拆。
- 在META-INF/spring.handlers文件里面按照SPI配置自定義的NamespaceHandler由DefaultNamespaceHandlerResolver加載。
自定義配置案例分析----componant-scan氮墨、annotation-config配置解析
component-scan配置就是自定義配置的一種纺蛆,就是xml配置中<context/>配置,他的作用是用來掃描包路徑下所有的類文件规揪,對表明@Component注解的類加載成bean對象桥氏。對應的NamespaceHandler是ContextNamespaceHandler,舉例一個配置
<context:component-scan base-package="com.vrv.paw.dao,com.vrv.paw.service,com.vrv.paw.action" />
代碼如下
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
看到component-scan子配置對應的解析類為ComponentScanBeanDefinitionParser猛铅,查看對應的parse實現
public BeanDefinition parse(Element element, ParserContext parserContext) {
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
BASE_PACKAGE_ATTRIBUTE對應的配置項就是 base-package字支,解析獲取對應的package列表,創(chuàng)建ClassPathBeanDefinitionScanner對象scanner,來掃描這些base-packages下的bean注解定義堕伪,然后把掃描出來的beanDefinitions注冊到beanfactory中揖庄,這里的核心方法就是doScan。注意下在doScan之前的方法configureScanner欠雌,這個就是為了獲取一個scanner蹄梢,后面會講到這個方法。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
這個方法就是遍歷所有的basePackage富俄,把對應package下的bean都加載起來禁炒,掃描的方法是findCandidateComponents,進入這個方法(篩選主要部分)
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
...
return candidates;
}
從上面代碼可以看出先用resourcePatternResolver獲取這個basePackage下的class文件霍比,加載成resource齐苛,這個resourcePatternResolver對應的類是PathMatchingResourcePatternResolver,就是類路徑資源解析器桂塞,不進入分析凹蜂。下面是對每個resource獲取對應的MetadataReader,這個MetadataReader對象是用來獲取class類文件的元數據的阁危,包括注解玛痊、Class類元數據等。然后isCandidateComponent方法就是判斷這個類是否有注解
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return isConditionMatch(metadataReader);
}
}
return false;
}
這里就是把metadata數據判斷是否滿足過濾器狂打,也就是我們配置在<context: component-scan/>的子元素<context: include-filter/>中擂煞,這個子元素的配置是可以讓我們自定義bean注解(比如這里我們配置com.huawei.chj.ChjAnnotation,那么@ChjAnnotation注解的類就會被掃描成bean)趴乡,一般的我們不會去配置這個值对省,而是用默認的配置,對應的是屬性use-default-filters=true晾捏,默認就是true蒿涎,所以這里的includeFilters就是默認的filter,可以看下對應的定義惦辛,就是在前面我們調用configureScanner方法里面劳秋,我們回過來看下這個方法實現
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
boolean useDefaultFilters = true;
if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
}
// Delegate bean definition registration to scanner class.
ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
}
try {
parseBeanNameGenerator(element, scanner);
}
catch (Exception ex) {
parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
}
try {
parseScope(element, scanner);
}
catch (Exception ex) {
parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
}
parseTypeFilters(element, scanner, parserContext);
return scanner;
}
protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
readerContext.getEnvironment(), readerContext.getResourceLoader());
}
在這個方法里面就會調用createScanner方法創(chuàng)建scanner(其他的先不關注),里面就是new一個ClassPathBeanDefinitionScanner胖齐,看下這個類的構造函數:
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
到這里可以看到會調用registerDefaultFilters來初始化默認的filter玻淑,進入這個方法看下
javaprotected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
到這里我們就看到了這個filters里面把Component注解類加到filter中去了,這就是我們在類上配置@Component注解就會被掃描成bean的原因呀伙,當然這里不僅僅添加了Component补履,還有javax.annotation.ManagedBean跟javax.inject.Named,所以實際上我們在類上配置@ManagedBean跟@Named都是可以被掃描成bean的剿另。
回到前面講的findCandidateComponents方法箫锤,通過這個方法把所有的basePackage里面的類中注解@Component的加載成beandefinition帅腌,這些都是“候選”bean對象,接下來要對這些對象進行處理麻汰,主要方法是AnnotationConfigUtils.processCommonDefinitionAnnotations速客,進入這個方法分析下:
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
這里所說對common屬性就是定義bean對屬性,包括是否懶加載五鲫,是否有依賴的類溺职,是否有描述的注解等等。這些在xml配置中是不要處理的位喂,會在解析xml對時候就處理了浪耘。
到此doscan已經完成,此時所有對注解對bean都被掃描到了塑崖,但是還沒有初始化七冲,接下來的方法registerComponents很重要,網上資料說<context :component-scan>標簽有了就不需要<context :annotation-config>规婆,包含進去了澜躺,具體實現就在這個方法中:
protected void registerComponents(
XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {
Object source = readerContext.extractSource(element);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
}
// Register annotation config processors, if necessary.
boolean annotationConfig = true;
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
}
if (annotationConfig) {
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
}
}
readerContext.fireComponentRegistered(compositeDef);
}
前面的compositeDef先不用管,直接看到annotationConfig抒蚜,默認這個配置是true掘鄙,那么就會執(zhí)行AnnotationConfigUtils.registerAnnotationConfigProcessors,這個方法比較長嗡髓,但是做對事情比較簡單操漠,就是把ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor饿这、CommonAnnotationBeanPostProcessor(JSR-250)等processor加進來浊伙,這幾個類ConfigurationClassPostProcessor-----處理@Configuration注解;AutowiredAnnotationBeanPostProcessor-----處理Autowired长捧、value嚣鄙、inject注解;CommonAnnotationBeanPostProcessor----處理JSR-250標準對注解唆姐,比如說我們用的@Resource注解拗慨。<context :annotation-config>這個注解對應對parser類就不再分析類廓八,核心功能就是上面這個方法奉芦。
小結
回顧整個component-scan的流程,首先是我們在解析xml中剧蹂,發(fā)現了有自定義的標簽了声功,然后從用resolver解析器找到這個標簽對應的namespaceHandler,這個namespaceHandler是保存在map中宠叼,初始化是通過SPI方式加載進來的(namespace-handler配置)先巴。找到這個namespaceHandler后其爵,解析標簽,找到ComponentScanBeanDefinitionParser解析類伸蚯,這個類就會根據component-scan中配置的basePackage來掃描對應的class類摩渺,把有注解@Component的類作為候選bean,處理下這些類上的其他的類注解:比如是否懶加載剂邮、是否有依賴摇幻、是否有描述等等。處理好了后就把這些beandefinition注冊到beanfactory中挥萌,最后再添加@Configuration绰姻、@Autowire 的注解處理器。這樣這個scan流程就完成了引瀑。
所以可以知道xml中定義的bean跟@Component注解的bean在構建beanfactory的時候就已經加載到beanfactory中狂芋,但是@Configuration注解的類以及類里面@Bean注解的方法此時還沒有加載,以及每個bean中的IOC都沒有做憨栽,這些事情是在后面調用
小結
到這里此時完成了方法obtainFreshBeanFactory()帜矾,僅僅把所有的xml中定義的bean以及@Component注解的bean都已經加載到beanfatcory中了,流程比較清晰屑柔,先創(chuàng)建一個默認的beanfactory黍特,然后把指定location的resource給加載解析,從xml中分析出bean對象來锯蛀,注冊到beanfactory中灭衷,這里的beandefinition是無差別的,不管是普通的bean旁涤,還是factorybean翔曲,還是各種processor。
beanfactory后置處理----invokeBeanFactoryPostProcessors
此時的bean還是一個beanDefinition對象劈愚,沒有初始化瞳遍,只是做了構造創(chuàng)建。接下來prepareBeanFactory菌羽、postProcessBeanFactory做了初步配置掠械,暫時不做分析,下面是invokeBeanFactoryPostProcessors方法注祖,這個是spring的非常核心的一個方法調用猾蒂,很多的業(yè)務定制都在這里完成的,比如說我們的@Configuration是晨。這個方法是調用所有beanfactoryPostProcessor肚菠,執(zhí)行對應的postProcessBeanFactory方法。
spring提供了beanfactoryPostProcessor接口罩缴,這個是spring在加載beandefinition后蚊逢,初始化bean前层扶,做的操作,用來給給我們對beanfactory中的beandefinition做一些定制烙荷。另外還有一個BeanDefinitionRegistryPostProcessor接口镜会,這個接口用來給業(yè)務做自定義的beandefinition的注冊
這個里面主要是用到對應的代理方法:PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,這個方法很長终抽,逐步來分析
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<String>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
稚叹。。拿诸。
這個方法很長扒袖,干的事情很清晰,就是把spring容器中BeanFactoryPostProcessor類型的bean單獨拿出來處理這個流程整理如下:
- 從beanfactory中取出類型BeanDefinitionRegistryPostProcessor的beandefinistion列表
- 過濾出實現接口PriorityOrdered的Processors,然后排序
- 執(zhí)行這些BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
- 重新從beanfactory中取出類型BeanDefinitionRegistryPostProcessor的beandefinistion列表
- 過濾出實現接口Ordered的Processors,然后排序
- 執(zhí)行這些BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
- 重新從beanfactory中取出類型BeanDefinitionRegistryPostProcessor的beandefinistion列表
- 執(zhí)行這些BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
- 執(zhí)行上面這些BeanDefinitionRegistryPostProcessors的postProcessBeanFactory方法
- 從beanfactory中取出類型BeanFactoryPostProcessor的beandefinistion列表
- 按照上面的順序從PriorityOrdered买鸽、Ordered、普通的三種順序來執(zhí)行對應的postProcessBeanFactory
說明1:對于步驟4跟步驟7飒泻,需要重新從beanfactory中獲取beandefinistion列表是因為前面每一次操作都可能會創(chuàng)建新的BeanDefinitionRegistryPostProcessor的beandefinition,所以需要重新獲取
說明2:每次處理低優(yōu)先級的processor時吏廉,都會去檢查已處理列表泞遗,避免被多次執(zhí)行。
這樣整理下流程就比較清晰席覆。前面在處理自定義標簽<context>的時候史辙,在對應的namespaceHandler里面,doScan的時候佩伤,我們注冊了三個processor聊倔,其中有一個是ConfigurationClassPostProcessor,這個是處理@Configuration的生巡,以這個為例分析下BeanDefinitionRegistryPostProcessor的具體處理過程
BeanDefinitionRegistryPostProcessor處理分析----ConfigurationClassPostProcessor
ConfigurationClassPostProcessor是用來處理@Configurtaion的耙蔑,看下對應的處理方法
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 1、從所有的候選的bean中孤荣,篩選出@Configuration注解的bean
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 解析bean
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
public static boolean checkConfigurationClassCandidate(
BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
String className = beanDef.getBeanClassName();
if (className == null || beanDef.getFactoryMethodName() != null) {
return false;
}
AnnotationMetadata metadata;
if (beanDef instanceof AnnotatedBeanDefinition &&
className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
// Can reuse the pre-parsed metadata from the given BeanDefinition...
metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
}
else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
// Check already loaded Class if present...
// since we possibly can't even load the class file for this Class.
Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
BeanPostProcessor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
EventListenerFactory.class.isAssignableFrom(beanClass)) {
return false;
}
metadata = AnnotationMetadata.introspect(beanClass);
}
else {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
metadata = metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not find class file for introspecting configuration annotations: " +
className, ex);
}
return false;
}
}
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
else if (config != null || isConfigurationCandidate(metadata)) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}
// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
return true;
}
- 首先是從所有的beandefinition中獲取@configuration注解的bean甸陌,主要是方法ConfigurationClassUtils.checkConfigurationClassCandidate,這個檢查動作主要就是獲取bean的注解是否是@configuration盐股,是就作為注解類
- 將待處理的bean進行處理钱豁,處理流程主要是在doProcessConfigurationClass方法中完成, 在@Configurtaion中主要處理的事情:
- 處理內部類的注解(包含component遂庄,import寥院,configuration、@bean等等)涛目,這個是一個遞歸處理
- 處理@PropertySource 注解
- 處理@Component-scan注解
- 處理@import @importSource注解
- 處理@Bean注解秸谢,注意這里處理bean注解不是直接解析bean,而是把方法加入到beanMethod中霹肝,待后面處理
注意下估蹄,這里說的各種注解必須是在@Configuration注解下的,否則不會被處理沫换,這是因為這些注解的處理都是在處理@Configuration中處理的臭蚁。@PropertySource 是導入配置文件,configruationPlaceHolder就是處理各種PropertySource對象讯赏,@Import處理導入的對象為bean垮兑,@ImportSource處理導入的xml配置
這里有processMemberClasses的方法,可以看下源碼漱挎,因為是遞歸調用系枪。所以當我們內部類之間是循環(huán)導入的就會出現死循環(huán),報錯磕谅,一般很少出現這樣的問題私爷,而且有個問題待驗證:我們在component-scan的時候,會把類以及內部類都掃描到膊夹,如果有注解才會成bean衬浑,那么對于一個普通的含有內部類的bean,這里的內部類是否不需要再處理了放刨?因為已經被scan了工秩,只有是啟動springcontext的那個啟動類本身才需要處理內部類?這個待驗證
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
bean的初始化--finishBeanFactoryInitialization
經過前面的beanfactorypostprocessor之后进统,當前spring容器的所有的bean都被加載到容器中拓诸,下面就需要進行實例化與初始化了,這部分的代碼會比較長麻昼。
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
上面的流程比較清楚奠支,總結流程如下:
- 獲取加載的beandefinition列表,獲取merged過后的beandefinition對象抚芦,getMergedLocalBeanDefinition方法下面重點分析
- 過濾出非抽象的倍谜,單例的,非懶加載的beandefinition進行初始化
- 判斷是否是factorybean叉抡,如果是尔崔,按照factorybean的方式處理,如果是普通的bean褥民,則調用getbean方式來初始化
- 過濾出實現SmartInitializingSingleton的bean季春,做一些初始化后的后置處理
這里面 有兩個核心方法:getMergedLocalBeanDefinition,getBean
bean的整理--getMergedLocalBeanDefinition
前面加載的beandefinition僅僅是定義了bean以及做了簡單的配置消返,有些bean需要合并些配置载弄,比如說父子bean對象耘拇,需要合并后才是一個完整的beandefinition
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
RootBeanDefinition previous = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without a ConfigurableBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
if (previous != null) {
copyRelevantMergedBeanDefinitionCaches(previous, mbd);
}
return mbd;
}
}
這個方法主要是處理那些不是完整的bean的,因為spring支持bean的繼承(類似我們把公共部分提取到parent中)宇攻,parent不支持實例化惫叛,子bean不能直接實例化,所以才有這個方法的逞刷,看下方法的邏輯
- 從spring容器beandefinitionMap中根據這個beanName獲取beandefinition嘉涌。
- 檢查這個beandefinition是否有parentdefinition,如果沒有夸浅,則說明這個bean就是一個完整的beandefinition仑最,直接將其轉換成RootBeanDefinition。
- 如果這個bean有parentdefinition帆喇,則遞歸去獲取parentbeandefinition警医,然后將子beandefinition 與其合并,調用overrideFrom方法完成番枚。
到此法严,所有的bean都是完整的了。
bean初始化與獲取----getBean
spring容器中葫笼,不管是factorybean還是普通的bean深啤,都是通過方法getBean來進行初始化的。這個方法非常長路星,可以分段分析
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
首先是transformedBeanName溯街,這個是獲取bean的Name,在spring中洋丐,對于factorybean呈昔,beanname是有前綴&的,這個方法就是把這個&給過濾掉友绝。然后getSingleton方法從map中獲取這個bean堤尾,因為我們此時初始化bean是單例的,非單例不在這里初始化迁客,獲取的時候優(yōu)先從這個map中獲取郭宝,沒有才考慮去創(chuàng)建。如果map中有的話掷漱,直接去取粘室,但是bean有兩種,一種是factorybean卜范,一種是普通bean衔统,兩種bean的獲取方式是不一樣的,進入這個方法看下具體的實現getObjectForBeanInstance
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
- 這個方法,首先是用BeanFactoryUtils.isFactoryDereference(name)判斷是否是factorybean锦爵,如果是以&開頭舱殿,則必須是factorybean(但是這里注意下并不是所有的factorybean的name都是以&開頭,對于不去顯示配置beanname的bean棉浸,spring會給他分配一個beanname怀薛,以&開頭)刺彩,然后直接返回這個bean迷郑;
- 如果查詢的name是一個普通的name,對應的bean可能也是factorybean创倔,如果是普通的bean嗡害,那么就直接返回
- 如果是一個factorybean,先從對應的緩存加載畦攘,如果緩存沒有霸妹,則直接從factorybean中創(chuàng)建
factorybean創(chuàng)建bean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (already There != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
代碼里面寫的很長,主要的工作就是getObject知押,從這個方法中獲取bean對象叹螟,對于factorybean本身,spring容器中也有對應bean台盯,但是獲取的時候罢绽,只會獲取對應的object對象
回到前面說的doGetbean方法的else部分,此時在緩存中并沒有對應的bean静盅,需要我們創(chuàng)建
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ′" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
上面的流程可以歸納為如下:
- 檢查這個beandefinition有沒有對應的parentfactory良价,如果有的話并且當前beanfactory中也沒有對應的beandifinition,就用對應的factory創(chuàng)建蒿叠。
- 檢查當前獲取bean是否是檢查明垢,如果是則直接返回
- 檢查當前beandefinition的depend-on屬性,如果有以來市咽,則先實例化所有的依賴的bean
- 根據bean的屬性是否是單例調用對應的createbean方法來實例化bean痊银,然后再調用getObjectForBeanInstance來獲取bean。
核心的方法在于createbean方法
createbean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
整個創(chuàng)建bean的流程還是比較清晰的施绎,主要流程如下:
- 首先檢查容器中是否有InstantiationAwareBeanPostProcessor溯革,這個接口的實現類是用來給我們提供一個拓展能力,進行定制bean粘姜,查看這個接口可以自定義往容器中添加bean鬓照,這個是spring在實例化bean之前,最后一次修改bean的機會孤紧。
- 實例化bean豺裆,可以是根據構造函數創(chuàng)建,也可以是工廠方法創(chuàng)建
- 獲取MergedBeanDefinitionPostProcessor實例,應用到該bean實例上臭猜,比如說我們的@PostConstructor的解析躺酒,@Resource,@Autowire 在這個階段都有處理蔑歌,注意這里只是做簡單的檢驗等處理羹应,并沒有解析。
- populateBean次屠,這個階段處理的事情主要是bean的屬性設置园匹,包括xml中配置的屬性設置,@Autowire方法的注入就是在這里做的劫灶,下面會分析源碼裸违。
- initializebean,初始化bean本昏,這里主要包括Aware接口的調用供汛,@PostConstruct初始化方法,InitializeBean接口的方法涌穆,xml中配置的init的處理方法怔昨。
先看下populateBean這個方法的源碼
populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- 先處理InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation,這個方法就是用來處理當前的bean的實例化有沒有完成宿稀,如果完成了趁舀,那么就直接返回,目前還沒有什么實現類做這個原叮;
- 然后是根據Autowiredmode來處理赫编,這里我們代碼調試mode為AUTOWIRE_NO=0,什么意思呢奋隶,就是不會自動注入擂送,但是顯示的@Autowire方式還是會注入的。這里涉及到一個知識點就是AutowireCapableBeanFactory唯欣,默認的我們的bean的注入會根據bean中有@Autowire的時候會自動注入進來嘹吨,沒有這個注解的話,我們獲取的bean中需要被注入的對象就是null境氢,這個很好理解:A中依賴注入B蟀拷,必須要顯示在屬性B對象上設置@Autowire,這樣我們getbean A的時候里面的屬性B才有萍聊,如果沒有這個顯示注解问芬,屬性B是null,但是如果我們getbean的方法換一種的話寿桨,我們是可以人為的幫A注入B對象此衅,AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
A a = (A) beanFactory.autowire(A.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); B b = a.getB();這樣就獲取到B屬性了强戴。通過這種方式,可以人為的給A這個bean注入屬性B了挡鞍。 - 然后就是處理它的postProcessProperties方法骑歹,這個方法處理的就包含@Autowire的注入,而且還包含一些屬性的設置墨微,比如我們在xml中配置的屬性值初始化道媚,就是在這里完成的。
populatebean方法完成后翘县,我們的依賴注入就完成了最域,前面createbean方法我們創(chuàng)建了bean對象,這里又設置了初始化屬性值以及IOC依賴注入炼蹦,接下來就是初始化這個bean了
initializeBean
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
對于這個方法羡宙,不過多的講細節(jié)了狸剃,注意下流程
- 首先是invokeAwareMethods方法調用掐隐,這個方法就是我們一系列的Aware接口,比如我們BeanNameAware钞馁,ApplicationContextAware就是在這個環(huán)節(jié)做的
- 然后是applyBeanPostProcessorsBeforeInitialization虑省,這個是把所有的BeanPostProcessor里面的postProcessBeforeInitialization執(zhí)行一遍,我們的@PostConstruct注解就是屬于CommonAnnotationBeanPostProcessor這個processor然后被處理的
- 然后是invokeInitMethods僧凰,這個方法里面包含兩部分探颈,首先根據當前的bean有沒有實現InitializingBean這個接口,如果實現了就會去執(zhí)行這個接口的afterPropertiesSet方法進行初始化训措;然后再獲取自定義的初始化方法伪节,比如我們在xml中指定的init-Method方法,就會在這里被找出來绩鸣。
所以我們這個的初始化流程就是
- 構造函數
- IOC依賴注入
- 初始化屬性設置
- Aware鉤子函數
- @PostConstruct注解初始化函數
- afterPropertiesSet初始化方法執(zhí)行
- init-Method初始化方法執(zhí)行怀大。
到此,我們的spring的初始化流程講完呀闻。