we never know, we just believe it.
概述
在Small Spring系列五:annotation Injection(一)中,我们已经通过PackageResourceLoader
将指定包下面的class
文件转变为Resource
资源。本章我们实现通过ASM
读取Resource
中的注解信息并创建BeanDefinition
。关于ASM
读取类信息可参考链接,由于spring
已经封装好读取操作,我们就不重复造轮子了。
修改pom.xml文件
在pom.xml
中增加spring-core-asm-3.2.18.RELEASE.jar
的依赖。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core-asm</artifactId>
<version>3.2.18.RELEASE</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/spring-core-asm-3.2.18.RELEASE.jar</systemPath>
</dependency>
使用ASM读取类信息
ClassMetadataReadingVisitor
读取class文件,获取类名,判断是否为接口,是否抽象,是否final,父类,实现接口数量等,继承ClassVisitor
。关于ClassVisitor
可参考链接。
package com.niocoder.core.type.classreading;
import com.niocoder.util.ClassUtils;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.SpringAsmInfo;
/**
* 读取class文件,获取类名,判断是否为接口,是否抽象,是否final,父类,实现接口数量等
*
* @author zhenglongfei
*/
public class ClassMetadataReadingVisitor extends ClassVisitor {
private String className;
private boolean isInterface;
private boolean isAbstract;
private boolean isFinal;
private String superClassName;
private String[] interfaces;
public ClassMetadataReadingVisitor() {
super(SpringAsmInfo.ASM_VERSION);
}
@Override
public void visit(int version, int access, String name, String signature, String supername, String[] interfaces) {
this.className = ClassUtils.convertResourcePathToClassName(name);
this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0);
this.isFinal = ((access & Opcodes.ACC_FINAL) != 0);
if (supername != null) {
this.superClassName = ClassUtils.convertResourcePathToClassName(supername);
}
this.interfaces = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
this.interfaces[i] = ClassUtils.convertResourcePathToClassName(interfaces[i]);
}
}
public String getClassName() {
return className;
}
public boolean isInterface() {
return isInterface;
}
public boolean isAbstract() {
return isAbstract;
}
public boolean isFinal() {
return isFinal;
}
public boolean hasSuperClass() {
return this.superClassName != null;
}
public String getSuperClassName() {
return superClassName;
}
public String[] getInterfacesNames() {
return this.interfaces;
}
public String[] getInterfaces() {
return interfaces;
}
}
注意 ClassVisitor引用的包名,是org.springframework.asm.ClassVisitor。
AnnotationMetadataReadingVisitor
读取class文件,注解信息如:@Component
package com.niocoder.core.type.classreading;
import com.niocoder.core.annotation.AnnotationAttributes;
import jdk.internal.org.objectweb.asm.Type;
import org.springframework.asm.AnnotationVisitor;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* 读取class文件,注解信息
*
* @author zhenglongfei
*/
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor {
/**
* com.niocoder.stereotype.Component
*/
private final Set<String> annotationSet = new LinkedHashSet<>(4);
/**
* com.niocoder.stereotype.Component
* AnnotationAttributes value->nioCoder
*/
private final Map<String, AnnotationAttributes> attributeMap = new LinkedHashMap<>(4);
public AnnotationMetadataReadingVisitor() {
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
this.annotationSet.add(className);
return new AnnotationAttributesReadingVisitor(className, this.attributeMap);
}
public Set<String> getAnnotationTypes() {
return this.annotationSet;
}
public boolean hasAnnotation(String annotationType) {
return this.annotationSet.contains(annotationType);
}
public AnnotationAttributes getAnnotationAttributes(String annotationType) {
return this.attributeMap.get(annotationType);
}
}
注意,该类继承了ClassMetadataReadingVisitor,并且在访问注解信息时构建了AnnotationAttributesReadingVisitor
AnnotationAttributesReadingVisitor
读取注解的属性信息,如:@Component(value = "nioCoder")
,使用AnnotationAttributes
保存
package com.niocoder.core.type.classreading;
import com.niocoder.core.annotation.AnnotationAttributes;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.SpringAsmInfo;
import java.util.Map;
/**
* 注解中定义的方法信息
*
* @author zhenglongfei
*/
public class AnnotationAttributesReadingVisitor extends AnnotationVisitor {
private final String annotationType;
private final Map<String, AnnotationAttributes> attributesMap;
AnnotationAttributes attributes = new AnnotationAttributes();
public AnnotationAttributesReadingVisitor(
String annotationType, Map<String, AnnotationAttributes> attributesMap) {
super(SpringAsmInfo.ASM_VERSION);
this.annotationType = annotationType;
this.attributesMap = attributesMap;
}
@Override
public final void visitEnd() {
this.attributesMap.put(this.annotationType, this.attributes);
}
@Override
public void visit(String attributeName, Object attributeValue) {
this.attributes.put(attributeName, attributeValue);
}
}
该类继承了AnnotationVisitor
AnnotationAttributes
扩展了LinkedHashMap
,保存注解属性信息,如:@Component(value = "nioCoder")
package com.niocoder.core.annotation;
import com.niocoder.util.Assert;
import java.util.LinkedHashMap;
import static java.lang.String.format;
/**
* 扩展LinkedHashMap 记录注解信息
*
* @author zhenglongfei
*/
public class AnnotationAttributes extends LinkedHashMap<String, Object> {
public AnnotationAttributes() {
}
public String getString(String attributeName) {
return doGet(attributeName, String.class);
}
@SuppressWarnings("unchecked")
private <T> T doGet(String attributeName, Class<T> expectedType) {
Object value = this.get(attributeName);
Assert.notNull(value, format("Attribute '%s' not found", attributeName));
return (T) value;
}
}
ClassReaderTest
测试类,测试上述读取类和注解的信息
public class ClassReaderTest {
@Test
public void testGetClassMetaData() throws Exception {
ClassPathResource resource = new ClassPathResource("com/niocoder/service/v4/NioCoderService.class");
ClassReader reader = new ClassReader(resource.getInputStream());
ClassMetadataReadingVisitor visitor = new ClassMetadataReadingVisitor();
reader.accept(visitor, ClassReader.SKIP_DEBUG);
Assert.assertFalse(visitor.isAbstract());
Assert.assertFalse(visitor.isInterface());
Assert.assertFalse(visitor.isFinal());
Assert.assertEquals("com.niocoder.service.v4.NioCoderService", visitor.getClassName());
Assert.assertEquals("java.lang.Object", visitor.getSuperClassName());
Assert.assertEquals(0, visitor.getInterfaces().length);
}
@Test
public void testGetAnnotation() throws Exception {
ClassPathResource resource = new ClassPathResource("com/niocoder/service/v4/NioCoderService.class");
ClassReader reader = new ClassReader(resource.getInputStream());
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor();
reader.accept(visitor,ClassReader.SKIP_DEBUG);
String annotation = "com.niocoder.stereotype.Component";
Assert.assertTrue(visitor.hasAnnotation(annotation));
AnnotationAttributes attributes = visitor.getAnnotationAttributes(annotation);
Assert.assertEquals("nioCoder",attributes.get("value"));
}
}
类图
时序图
代码下载
优化ASM读取类信息
我们现在想要读取类信息和注解信息需要使用ClassReader
和AnnotationMetadataReadingVisitor
,ClassReader
还是在ASM
包下。这样使用起来不太方便,耦合性很高。因此我们准备在spring
的基础上再次封装一下,类图如下:
封装MetadataReader接口封装读取类信息和注解信息的操作,默认实现类为SimpleMetadataReader
MetadataReader
封装读取类信息和注解信息的所有操作
package com.niocoder.core.type.classreading;
import com.niocoder.core.io.Resource;
import com.niocoder.core.type.AnnotationMetadata;
import com.niocoder.core.type.ClassMetadata;
/**
* 封装 ClassMetadataReadingVisitor和AnnotationMetadataReadingVisitor
*
* @author zhenglongfei
*/
public interface MetadataReader {
/**
* 获取资源信息
*
* @return
*/
Resource getResource();
/**
* 获取类信息
*
* @return
*/
ClassMetadata getClassMetadata();
/**
* 获取注解信息
*
* @return
*/
AnnotationMetadata getAnnotationMetadata();
}
ClassMetadata
封装获取类信息的接口由ClassMetadataReadingVisitor
实现
package com.niocoder.core.type;
/**
* 封装获取类信息的接口
*
* @author zhenglongfei
*/
public interface ClassMetadata {
/**
* 获取类名称
*
* @return
*/
String getClassName();
/**
* 判断是否是接口
*
* @return
*/
boolean isInterface();
/**
* 判断是否抽象
*
* @return
*/
boolean isAbstract();
/**
* 判断是否类是否final
*
* @return
*/
boolean isFinal();
/**
* 是否父类
*
* @return
*/
boolean hasSuperClass();
/**
* 获取父类名称
*
* @return
*/
String getSuperClassName();
/**
* 获取所有的接口名称
*
* @return
*/
String[] getInterfaceNames();
}
AnnotationMetadata
封装获取注解信息的接口,继承ClassMetadata
,由AnnotationMetadataReadingVisitor
负责实现
package com.niocoder.core.type;
import com.niocoder.core.annotation.AnnotationAttributes;
import java.util.Set;
/**
* 封装获取接口信息的接口
*
* @author zhenglongfei
*/
public interface AnnotationMetadata extends ClassMetadata {
/**
* 获取注解信息
*
* @return
*/
Set<String> getAnnotationTypes();
/**
* 判断是否有该注解信息
*
* @param annotationType
* @return
*/
boolean hasAnnotation(String annotationType);
/**
* 获取注解的内容信息
*
* @param annotationType
* @return
*/
AnnotationAttributes getAnnotationAttributes(String annotationType);
}
SimpleMetadataReader
实现了MetadataReader
package com.niocoder.core.type.classreading;
import com.niocoder.core.io.Resource;
import com.niocoder.core.type.AnnotationMetadata;
import com.niocoder.core.type.ClassMetadata;
import org.springframework.asm.ClassReader;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 实现MetadataReader
*
* @author zhenglongfei
*/
public class SimpleMetadataReader implements MetadataReader {
private final Resource resource;
private final ClassMetadata classMetadata;
private final AnnotationMetadata annotationMetadata;
public SimpleMetadataReader(Resource resource) throws IOException {
InputStream is = new BufferedInputStream(resource.getInputStream());
org.springframework.asm.ClassReader classReader;
try {
classReader = new ClassReader(is);
} finally {
is.close();
}
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor();
classReader.accept(visitor, ClassReader.SKIP_DEBUG);
this.annotationMetadata = visitor;
this.classMetadata = visitor;
this.resource = resource;
}
@Override
public Resource getResource() {
return resource;
}
@Override
public ClassMetadata getClassMetadata() {
return classMetadata;
}
@Override
public AnnotationMetadata getAnnotationMetadata() {
return annotationMetadata;
}
}
ClassMetadataReadingVisitor
实现ClassMetadata
public class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
......
}
AnnotationMetadataReadingVisitor
实现AnnotationMetadata
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
......
}
测试类MetadataReaderTest
public class MetadataReaderTest {
@Test
public void testGetMetadata() throws Exception{
ClassPathResource resource = new ClassPathResource("com/niocoder/service/v4/NioCoderService.class");
MetadataReader reader = new SimpleMetadataReader(resource);
AnnotationMetadata amd = reader.getAnnotationMetadata();
String annotation = Component.class.getName();
Assert.assertTrue(amd.hasAnnotation(annotation));
AnnotationAttributes attributes = amd.getAnnotationAttributes(annotation);
Assert.assertEquals("nioCoder",attributes.get("value"));
Assert.assertFalse(amd.isAbstract());
Assert.assertFalse(amd.isInterface());
Assert.assertFalse(amd.isFinal());
}
}
代码下载
创建BeanDefinition
我们已经完成了使用ASM
获取类和注解信息,接下来我们需要根据扫面的注解(Componse
)创建对应的BeanDefinition
并注册到BeanFactory
中。
我们之前通过bean.xml
获取的BeanDefinition
默认为GenericBeanDefinition
,但现在我们需要通过扫描创建BeanDefinition
,为了不影响之前的业务,我们新增一个AnnotatedBeanDefinition
的接口表明为注解得到的BeanDefinition
,默认实现类为ScannedGenericBeanDefinition
。类图如下:
为了完成上述的功能我们需要一个ClassPathBeanDefinitionScanner
类,给你一个包名(com.niocoder.service.v4,com.niocoder.dao.v4
)可以返回包下面所有的BeanDefinition
。
AnnotatedBeanDefinition
表明当前的BeanDefinition
由注解生成
package com.niocoder.beans.factory.annotation;
import com.niocoder.beans.BeanDefinition;
import com.niocoder.core.type.AnnotationMetadata;
/**
* 注解的BeanDefinition接口
*
* @author zhenglongfei
*/
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* 获取注解信息
*
* @return
*/
AnnotationMetadata getMetadata();
}
ScannedGenericBeanDefinition
继承GenericBeanDefinition
实现AnnotatedBeanDefinition
package com.niocoder.context.annotation;
import com.niocoder.beans.factory.annotation.AnnotatedBeanDefinition;
import com.niocoder.beans.factory.support.GenericBeanDefinition;
import com.niocoder.core.type.AnnotationMetadata;
/**
* 实现 AnnotatedBeanDefinition 接口
*
* @author zhenglongfei
*/
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
public ScannedGenericBeanDefinition(AnnotationMetadata metadata) {
super();
this.metadata = metadata;
setBeanClassName(this.metadata.getClassName());
}
@Override
public AnnotationMetadata getMetadata() {
return metadata;
}
}
GenericBeanDefinition
增加无参构造方法和setBeanClassName
和setId
方法
public class GenericBeanDefinition implements BeanDefinition {
......
public GenericBeanDefinition() {
}
......
public void setBeanClassName(String className) {
this.beanClassName = className;
}
public void setId(String id) {
this.id = id;
}
}
ClassPathBeanDefinitionScanner
里面含有doScan
方法,给定包名,包下面所有被@Component
标记的类会被创建BeanDefinition
并返回一个集合
package com.niocoder.context.annotation;
import com.niocoder.beans.BeanDefinition;
import com.niocoder.beans.factory.BeanDefinitionStoreException;
import com.niocoder.beans.factory.support.BeanDefinitionRegistry;
import com.niocoder.beans.factory.support.BeanNameGenerator;
import com.niocoder.core.io.Resource;
import com.niocoder.core.io.support.PackageResourceLoader;
import com.niocoder.core.type.classreading.MetadataReader;
import com.niocoder.core.type.classreading.SimpleMetadataReader;
import com.niocoder.stereotype.Component;
import com.niocoder.util.StringUtils;
import lombok.extern.java.Log;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* 扫描component注解定义的bean
*
* @author zhenglongfei
*/
@Log
public class ClassPathBeanDefinitionScanner {
/**
* 注册到BeanFactory中,所以需要BeanDefinitionRegistry
*/
private final BeanDefinitionRegistry registry;
/**
* 扫描包下的文件返回Resource
*/
private PackageResourceLoader resourceLoader = new PackageResourceLoader();
/**
* 生成Bean的名称beanName
*/
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this.registry = registry;
}
/**
* 核心方法,给定包名,包下面所有被@Component会被创建BeanDefinition并返回
*
* @param packagesToScan
* @return
*/
public Set<BeanDefinition> doScan(String packagesToScan) {
String[] basePackages = StringUtils.tokenizeToStringArray(packagesToScan, ",");
Set<BeanDefinition> beanDefinitions = new LinkedHashSet<BeanDefinition>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
beanDefinitions.add(candidate);
registry.registerBeanDefinition(candidate.getId(), candidate);
}
}
return beanDefinitions;
}
/**
* 查找被Component标记的类并返回
*
* @param basePackage
* @return
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
Resource[] resources = this.resourceLoader.getResource(basePackage);
for (Resource resource : resources) {
try {
MetadataReader metadataReader = new SimpleMetadataReader(resource);
if (metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName())) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader.getAnnotationMetadata());
String beanName = this.beanNameGenerator.generateBeanName(sbd, this.registry);
sbd.setId(beanName);
candidates.add(sbd);
}
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
}
BeanNameGenerator
生成beanName
的一个接口,因为@Component(value = "nioCoder")
的value
不是必填项
package com.niocoder.beans.factory.support;
import com.niocoder.beans.BeanDefinition;
/**
* 生成扫描bean 名称的接口
*
* @author zhenglongfei
*/
public interface BeanNameGenerator {
/**
* 根据bean的定义生成bean的名称
* @param definition
* @param registry
* @return
*/
String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
AnnotationBeanNameGenerator
实现了BeanNameGenerator
,生成beanName
如果 (@Component(value = "nioCoder")
) value
不为空取value
内容,如果value
为空则默认类名称首字母转小写
package com.niocoder.context.annotation;
import com.niocoder.beans.BeanDefinition;
import com.niocoder.beans.factory.annotation.AnnotatedBeanDefinition;
import com.niocoder.beans.factory.support.BeanDefinitionRegistry;
import com.niocoder.beans.factory.support.BeanNameGenerator;
import com.niocoder.core.annotation.AnnotationAttributes;
import com.niocoder.core.type.AnnotationMetadata;
import com.niocoder.util.ClassUtils;
import com.niocoder.util.StringUtils;
import java.beans.Introspector;
import java.util.Set;
/**
* 实现BeanNameGenerator
*
* @author zhenglongfei
*/
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
@Override
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
/**
* 从value中获取beanName
*/
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
return beanName;
}
}
return buildDefaultBeanName(definition, registry);
}
/**
* 根据类名称获取beanName
*
* @param definition
* @param registry
* @return
*/
private String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
return Introspector.decapitalize(shortClassName);
}
/**
* 获取value值
* @param definition
* @return
*/
private String determineBeanNameFromAnnotation(AnnotatedBeanDefinition definition) {
AnnotationMetadata amd = definition.getMetadata();
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
AnnotationAttributes attributes = amd.getAnnotationAttributes(type);
if (attributes.get("value") != null) {
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
beanName = strVal;
}
}
}
}
return beanName;
}
}
ClassPathBeanDefinitionScannerTest
测试ClassPathBeanDefinitionScanner
public class ClassPathBeanDefinitionScannerTest {
@Test
public void testParseScannerBean() {
DefaultBeanFactory factory = new DefaultBeanFactory();
String basePackages = "com.niocoder.service.v4,com.niocoder.dao.v4";
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(factory);
scanner.doScan(basePackages);
String annotation = Component.class.getName();
testAnnotationTest(factory, annotation);
}
public static void testAnnotationTest(DefaultBeanFactory factory, String annotation) {
{
BeanDefinition bd = factory.getBeanDefinition("nioCoder");
Assert.assertTrue(bd instanceof ScannedGenericBeanDefinition);
ScannedGenericBeanDefinition sbd = (ScannedGenericBeanDefinition) bd;
AnnotationMetadata amd = sbd.getMetadata();
Assert.assertTrue(amd.hasAnnotation(annotation));
AnnotationAttributes attributes = amd.getAnnotationAttributes(annotation);
Assert.assertEquals("nioCoder", attributes.getString("value"));
}
{
BeanDefinition bd = factory.getBeanDefinition("accountDao");
Assert.assertTrue(bd instanceof ScannedGenericBeanDefinition);
ScannedGenericBeanDefinition sbd = (ScannedGenericBeanDefinition) bd;
AnnotationMetadata amd = sbd.getMetadata();
Assert.assertTrue(amd.hasAnnotation(annotation));
}
{
BeanDefinition bd = factory.getBeanDefinition("itemDao");
Assert.assertTrue(bd instanceof ScannedGenericBeanDefinition);
ScannedGenericBeanDefinition sbd = (ScannedGenericBeanDefinition) bd;
AnnotationMetadata amd = sbd.getMetadata();
Assert.assertTrue(amd.hasAnnotation(annotation));
}
}
}
XmlBeanDefinitionReader
读取配置文件时,根据namespace
来创建不同的BeanDefinition
@Log
public class XmlBeanDefinitionReader {
......
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
public static final String CONTEXT_NAMESPACE_URI = "http://www.springframework.org/schema/context";
private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
......
/**
* 具体解析bean.xml的方法 使用dom4j
*
* @param resource
*/
public void loadBeanDefinition(Resource resource) {
try (InputStream is = resource.getInputStream()) {
SAXReader reader = new SAXReader();
Document doc = reader.read(is);
Element root = doc.getRootElement();
Iterator<Element> elementIterator = root.elementIterator();
while (elementIterator.hasNext()) {
Element ele = elementIterator.next();
String namespaceUri = ele.getNamespaceURI();
if (this.isDefaultNamespace(namespaceUri)) {
// 解析xml中定义的bean
parseDefaultElement(ele);
} else if (this.isContextNamespace(namespaceUri)) {
// 解析xml中定义的 扫描bean 例如<context:component-scan>
parseComponentElement(ele);
}
}
} catch (Exception e) {
throw new BeanDefinitionStoreException("IOException parsing XML document", e);
}
}
private void parseComponentElement(Element ele) {
String basePackages = ele.attributeValue(BASE_PACKAGE_ATTRIBUTE);
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.doScan(basePackages);
}
public boolean isDefaultNamespace(String namespaceUri) {
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
}
public boolean isContextNamespace(String namespaceUri) {
return (!StringUtils.hasLength(namespaceUri) || CONTEXT_NAMESPACE_URI.equals(namespaceUri));
}
private void parseDefaultElement(Element ele) {
String id = ele.attributeValue(ID_ATTRIBUTE);
String beanClassName = ele.attributeValue(CLASS_ATTRIBUTE);
BeanDefinition bd = new GenericBeanDefinition(id, beanClassName);
if (ele.attribute(SCOPE_ATTRIBUTE) != null) {
bd.setScope(ele.attributeValue(SCOPE_ATTRIBUTE));
}
parseConstructorArgElements(ele, bd);
parsePropertyElement(ele, bd);
this.registry.registerBeanDefinition(id, bd);
}
......
}
XmlBeanDefinitionReaderTest
测试读取xml
中 component-scan
标签的读取
/**
* 测试读取xml中 component-scan标签的读取
*/
public class XmlBeanDefinitionReaderTest {
@Test
public void testParseScannerBean() {
DefaultBeanFactory factory = new DefaultBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinition(new ClassPathResource("bean-v4.xml"));
String annotation = Component.class.getName();
ClassPathBeanDefinitionScannerTest.testAnnotationTest(factory, annotation);
}
}