Ioc-BeanDefinition的读取与注册 本文内容
本文主要讲述BeanDefinition的读取与注册,主要涉及到的接口是BeanDefinitionReader和BeanDefinitionRegistry。
本文会从这两个接口出发,分析其实现类,不同环境的不同实现,及其优缺点。
BeanDefinitionReader 简介 BeanDefinitionReader接口是个一个BeanDefinition的读取规范定义接口,定义了 “资源” 和 “字符串” 位置参数指定加载方法。
当然,具体的BeanDefinitionReader可以为BeanDefinition添加特定于其BeanDefinition格式的其他加载和注册方法。
具体的BeanDefinitionReader不必实现此接口。它仅对希望遵循标准命名约定的bean定义读者提供建议。
类继承图
老版本中经常使用的是XMLBeanDefinitionReader
,注解驱动版本中经常使用AnnotatedBeanDefinitionReader
。
源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public interface BeanDefinitionReader { BeanDefinitionRegistry getRegistry () ; ResourceLoader getResourceLoader () ; ClassLoader getBeanClassLoader () ; BeanNameGenerator getBeanNameGenerator () ; int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException; int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException; int loadBeanDefinitions (String location) throws BeanDefinitionStoreException; int loadBeanDefinitions (String... locations) throws BeanDefinitionStoreException; }
BeanDefinitionReader重载了不同参数的loadBeanDefinitions
方法用于加载BeanDefinition。
AbstractBeanDefinitionReader
概述 AbstractBeanDefinitionReader是实现了BeanDefinitionReader接口抽象基类。提供常见的属性,例如要处理的BeanFactory以及用于加载bean类的类加载器。
源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader , EnvironmentCapable { private final BeanDefinitionRegistry registry; private ResourceLoader resourceLoader; private ClassLoader beanClassLoader; private Environment environment; private BeanNameGenerator beanNameGenerator = DefaultBeanNameGenerator.INSTANCE; protected AbstractBeanDefinitionReader (BeanDefinitionRegistry registry) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null" ); this .registry = registry; if (this .registry instanceof ResourceLoader) { this .resourceLoader = (ResourceLoader) this .registry; }else { this .resourceLoader = new PathMatchingResourcePatternResolver (); } if (this .registry instanceof EnvironmentCapable) { this .environment = ((EnvironmentCapable) this .registry).getEnvironment(); } else { this .environment = new StandardEnvironment (); } } public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int count = 0 ; for (Resource resource : resources) { count += loadBeanDefinitions(resource); } return count; } }
AbstractBeanDefinitionReader
对BeanDefinitionReader
进行了简单的实现,声明registry
,resourceLoader
,beanClassLoader
,environment
,beanNameGenerator
等属性。
XmlBeanDefinitionReader
概述 XmlBeanDefinitionReader用于读取XML,将实际的XML文档读取委托给BeanDefinitionDocumentReader
接口的实现。
此类加载DOM Document 并将BeanDefinitionDocumentReader应用于该Document。
源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { private Class<? extends BeanDefinitionDocumentReader > documentReaderClass = DefaultBeanDefinitionDocumentReader.class; private NamespaceHandlerResolver namespaceHandlerResolver; private DocumentLoader documentLoader = new DefaultDocumentLoader (); private EntityResolver entityResolver; private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded = new NamedThreadLocal <>("XML bean definition resources currently being loaded" ); public XmlBeanDefinitionReader (BeanDefinitionRegistry registry) { super (registry); } @Override public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource (resource)); } public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet <>(4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException ( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } InputStream inputStream = encodedResource.getResource().getInputStream(); InputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } } protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); return count; } catch (BeanDefinitionStoreException ex) {} catch (SAXParseException ex) {} catch (SAXException ex) {} catch (ParserConfigurationException ex) {} catch (IOException ex) {} catch (Throwable ex) {} } protected Document doLoadDocument (InputSource inputSource, Resource resource) throws Exception { return this .documentLoader.loadDocument(inputSource, getEntityResolver(), this .errorHandler, getValidationModeForResource(resource), isNamespaceAware()); } 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; } protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader () { return BeanUtils.instantiateClass(this .documentReaderClass); } public XmlReaderContext createReaderContext (Resource resource) { return new XmlReaderContext (resource, this .problemReporter, this .eventListener, this .sourceExtractor, this , getNamespaceHandlerResolver()); } public NamespaceHandlerResolver getNamespaceHandlerResolver () { if (this .namespaceHandlerResolver == null ) { this .namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return this .namespaceHandlerResolver; } }
XMLBeanDefinitionReader
实际上只做了Document
文档的解析操作,真正的解析BeanDefinition操作交给了BeanDefinitionDocumentReader
(接口)实例(默认为DefaultBeanDefinitionDocumentReader
)来解析。
示例代码 Xml
1 2 3 <bean name ="iocBean" class ="io.better.spring.ioc.IocBean" init-method ="init" destroy-method ="destroy" > <property name ="name" value ="test-xml" /> </bean >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void testXmlBeanDefinitionReader () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (); BeanDefinitionReader definitionReader = new XmlBeanDefinitionReader (applicationContext); definitionReader.loadBeanDefinitions("Ioc.xml" ); applicationContext.refresh(); IocBean iocBean = (IocBean) applicationContext.getBean("iocBean" ); System.out.println(iocBean); }
1 2 3 IocBean Constructor IocBean custom init IocBean{name='test-xml'}
BeanDefinitionDocumentReader 简介 SPI,BeanDefinitionDocumentReader
用于解析带有BeanDefinition的Xml Document。
源代码 1 2 3 4 5 6 public interface BeanDefinitionDocumentReader { void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException; }
DefaultBeanDefinitionDocumentReader 简介 BeanDefinitionDocumentReader的唯一实现类,封装了解析并组装BeanDefinition的具体操作。
源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT; public static final String NESTED_BEANS_ELEMENT = "beans" ; public static final String ALIAS_ELEMENT = "alias" ; public static final String NAME_ATTRIBUTE = "name" ; 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 PROFILE_ATTRIBUTE = "profile" ; private XmlReaderContext readerContext; private BeanDefinitionParserDelegate delegate; @Override public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); } protected void doRegisterBeanDefinitions (Element root) { BeanDefinitionParserDelegate parent = this .delegate; this .delegate = createDelegate(getReaderContext(), root, parent); preProcessXml(root); parseBeanDefinitions(root, this .delegate); postProcessXml(root); this .delegate = parent; } 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); } } 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)) { doRegisterBeanDefinitions(ele); } } protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) {} getReaderContext().fireComponentRegistered(new BeanComponentDefinition (bdHolder)); } } }
在DefaultBeanDefinitionDocumentReader
中处理Bean标签
的逻辑交给了BeanDefinitionParserDelegate
对象来进行操作,并通过XmlReaderContext
获取到Registry
,最后将解析好的BeanDefinition注册进容器。
伴随着Xml方法的繁琐,笨重,Spring在4.2版本后提供了注解配置的方式来替换Xml配置的方法,那么注解是怎样读取 BeanDefinition的呢?
AnnotatedBeanDefinitionReader
概述 AnnotatedBeanDefinitionReader是个方便的适配器,用于以编程方式注册Bean类。这是ClassPathBeanDefinitionScanner
的替代方法,它应用注解的相同解析,但仅适用于显式注册的类。
该类不仅仅读取BeanDefinition,同时会注册BeanDefinition。
源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public class AnnotatedBeanDefinitionReader { private final BeanDefinitionRegistry registry; private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE; private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver (); private ConditionEvaluator conditionEvaluator; public AnnotatedBeanDefinitionReader (BeanDefinitionRegistry registry) { this (registry, getOrCreateEnvironment(registry)); } public void register (Class<?>... componentClasses) { for (Class<?> componentClass : componentClasses) { registerBean(componentClass); } } public void registerBean (Class<?> beanClass) { doRegisterBean(beanClass, null , null , null , null ); } public void registerBean (Class<?> beanClass, @Nullable String name) { doRegisterBean(beanClass, name, null , null , null ); } public void registerBean (Class<?> beanClass, Class<? extends Annotation>... qualifiers) { doRegisterBean(beanClass, null , qualifiers, null , null ); } private <T> void doRegisterBean (Class<T> beanClass, String name, Class<? extends Annotation>[] qualifiers, Supplier<T> supplier, BeanDefinitionCustomizer[] customizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition (beanClass); if (this .conditionEvaluator.shouldSkip(abd.getMetadata())) { return ; } abd.setInstanceSupplier(supplier); ScopeMetadata scopeMetadata = this .scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this .beanNameGenerator.generateBeanName(abd, this .registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null ) { for (Class<? extends Annotation > qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true ); } else if (Lazy.class == qualifier) { abd.setLazyInit(true ); } else { abd.addQualifier(new AutowireCandidateQualifier (qualifier)); } } } if (customizers != null ) { for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder (abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this .registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this .registry); } }
可以看出AnnotatedBeanDefinitionReader注册Bean的方法明显比XmlBeanDefinitionReader的处理方式简单了很多,
示例代码 1 2 3 4 5 6 7 8 9 @Test public void testAnnotatedBeanDefinitionReader () { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (IocBean.class); IocBean iocBean = applicationContext.getBean(IocBean.class); System.out.println(iocBean); }
AnnotationConfigApplicationContext
类中声明了AnnotatedBeanDefinitionReader
,ClassPathBeanDefinitionScanner
对象,并在构造函数中做了初始化。
ClassPathBeanDefinitionScanner
用于扫描ClassPath
下带@Component,@Repository,@Service,@Controller
注解的类。
总结 至此BeanDefinitionReader的分析完成,我们一共分析了两个BeanDefinitionReader规范实现,分别对应Xml读取(XmlBeanDefinitionReader)
和注解读取(AnnotatedBeanDefinitionReader)
。
XmlBeanDefinitionReader
:内部将BeanDefinition的读取交给了BeanDefinitionDocumentReader来进行操作。
AnnotatedBeanDefinitionReader
:不仅能读取BeanDefinition,并且还能注册BeanDefinition。