前言
前几篇我们实现了配置的方式实现Bean的生成和注入,接下来我们将要通过注解的方式来实现这一过程。这是学习刘欣老师《从零开始造Spring》课程的学习笔记。在实现的过程中我们需要用到ASM的技术,具体可以参考ASM技术
实现思路
- 读取XML文件
- 对指定的package 进行扫描(scan) ,找到那些标记为@Component的类,创建BeanDefinition
2.1 把一个package下面的class变成resource
2.2 使用ASM读取Resource中的注解
2.3 创建BeanDefinition - 通过BeanDefinition创建Bean实例,根据注解来注入。
具体实现
我们首先来了解下相关的注解,在此处,我们首先实现了两个最基本的注解@Component
注解和@Autowired
注解,注解的本质就是元数据。我们已@Autowired
为例。
/**
*
* 注解本质上就是元数据,
* @Target 标注注解的使用地方
* @Documented 说注解就是一个元素,可以被文档化
* Created by xiang.wei on 2018/7/14
*
*/
//构造器,字段,方法。
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
//保留到运行时
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
我们通过PackageResourceLoader
类来将base-package
中配置的包下加载出对应的Resource
关键代码如下:
public Resource[] getResources(String basePackage) throws IOException {
Assert.notNull(basePackage, "basePackage must not be null");
String location = ClassUtils.convertClassNameToResourcePath(basePackage);
ClassLoader cl = getClassLoader();
URL url = cl.getResource(location);
File rootDir = new File(url.getFile());
Set<File> matchingFiles = retrieveMatchingFiles(rootDir);
Resource[] result = new Resource[matchingFiles.size()];
int i = 0;
for (File file : matchingFiles) {
result[i++] = new FileSystemResource(file);
}
return result;
}
调试如下:
实现两个Visitor,实现SimpleMetaDataReader 这两步参考ASM在Spring中的应用
实现Scanner(对ASM的抽象)
如类图所示,我们抽象了一个MetadataReader
接口,该接口依赖于AnnotationVisitor
抽象类和ClassVisitor
抽象类,而AnnotationAttributesReadingVisitor
类和ClassMetadataReadingVisitor
类又是这两个抽象类的实现。由此我们就完全隐藏了AnnotationAttributesReadingVisitor
类和ClassMetadataReadingVisitor
类
测试代码
public class MetadataReaderTest {
@Test
public void testGetMetadata() throws IOException {
ClassPathResource resource = new ClassPathResource("com/jay/spring/service/v4/PetStoreService.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("petStoreService", attributes.get("value"));
Assert.assertFalse(amd.isAbstract());
Assert.assertFalse(amd.isFinal());
Assert.assertEquals("com.jay.spring.service.v4.PetStoreService", amd.getClassName());
}
}
ClassMetadataReadingVisitor
类
/**
* @param version
* @param access
* @param name
* @param signature
* @param supername
* @param interfaces
*
*
* 这个涉及到了Java的字节码, 在Java字节码中,常量池结束之后,
* 有两个字节表示访问标识(access_flags),
* 这个标识用于识别一些类或者接口层次的访问信息,
* 例如这个Class是类或者接口,是否为public ,abstract ,final 等等
* 对类的处理,判断类的基本情况
*
*/
//
@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]);
}
}
AnnotationMetadataReadingVisitor
类
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
private final Set<String> annotationSet = new LinkedHashSet<String>(4);
private final Map<String, AnnotationAttributes> attributeMap = new LinkedHashMap<String, AnnotationAttributes>(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);
}
@Override
public Set<String> getAnnotationTypes() {
return this.annotationSet;
}
@Override
public boolean hasAnnotation(String annotationType) {
return this.annotationSet.contains(annotationType);
}
@Override
public AnnotationAttributes getAnnotationAttributes(String annotationType) {
return this.attributeMap.get(annotationType);
}
@Override
public boolean hasSuperClass() {
return false;
}
}
SimpleMetadataReader
类
public SimpleMetadataReader(Resource resource) throws IOException {
// 提高一点性能吧
InputStream inputStream = new BufferedInputStream(resource.getInputStream());
ClassReader classReader;
try {
classReader = new ClassReader(inputStream);
} finally {
inputStream.close();
}
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor();
classReader.accept(visitor, ClassReader.SKIP_DEBUG);
this.annotationMetadata = visitor;
this.classMetadata = visitor;
this.resource = resource;
}
用ScannedGenericBeanDefinition
专门用来表达通过Scann扫描出的BeanDefiniton。
ClassPathBeanDefinitionScanner
类
/**
* 1. 给定一个package的名称列表,例如
org.litespring.service.v4,org.litespring.dao.v4"
2. 对指定的package 进行扫描(scan),找到那些标记为@Component 的类,创建ScannedGenericBeanDefinition,并且注册到BeanFactory中。
* Created by xiang.wei on 2018/7/15
*
* @author xiang.wei
*/
public class ClassPathBeanDefinitionScanner {
private final BeanDefinitionRegistry registry;
private PackageResourceLoader resourceLoader = new PackageResourceLoader();
private final Log logger = LogFactory.getLog(getClass());
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this.registry = registry;
}
/**
*
* @param packagesToScan 传入的base-package 字符串
* @return
*/
public Set<BeanDefinition> doScan(String packagesToScan) {
String[] basePackages = StringUtils.tokenizeToStringArray(packagesToScan, ",");
Set<BeanDefinition> beanDefinitions = new LinkedHashSet<BeanDefinition>();
// 对每一个basePackages进行循环
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
beanDefinitions.add(candidate);
registry.registerBeanDefinition(candidate.getID(), candidate);
}
}
return beanDefinitions;
}
/**
*
* @param basePackage
* @return
*/
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
try {
// 先拿到Resource
Resource[] resources = this.resourceLoader.getResources(basePackage);
for (Resource resource : resources) {
try {
MetadataReader metadataReader = new SimpleMetadataReader(resource);
// 通过metadataReader 获取AnnotationMetadata 看看其是否有Component注解
if (metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName())) {
//实例化一个ScannedGenericBeanDefinition
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 e) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", e);
}
return candidates;
}
}
ScannedGenericBeanDefinition
类
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 this.metadata;
}
}
对XmlBeanDefinitionReader
类的修改
private void parseComponentElement(Element element) {
String basePackages = element.attributeValue(BASE_PACKAGE_ATTRIBUTE);
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.doScan(basePackages);
}