聊聊、Spring自动扫描器

一、项目

 

 二、自定义注解

package org.rockcode.annotations;

import java.lang.annotation.*;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface EnableFruit {

  String name() default "EnableFruit";

}

 

三、services 目录 

package org.rockcode.services;

public interface Fruit {

public String getName();

}

  

package org.rockcode.services;

import org.rockcode.annotations.EnableFruit;

@EnableFruit

public class Apple implements Fruit{

@Override public String getName() {

return "Apple";

}

}

 

 三、扫描services目录下面@EnableFruit的类 

public class ClassPathEnableEnumScanner {

//解析路径下的 class
private static final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//转换成 MetaData 读取类
private static final SimpleMetadataReaderFactory register = new SimpleMetadataReaderFactory();

public static void getClazzFromAnnotation(String pkgPath, Class<? extends Annotation> annotationClass) {

//获取spring的包路径
String pathPackage = "classpath*:org/rockcode/services/**/*.class";

// 返回的是 FileSystemResource 数组
// file [E:\idea\SpringIOC\target\classes\org\rockcode\services\Apple.class]
// file [E:\idea\SpringIOC\target\classes\org\rockcode\services\Banana.class]
// file [E:\idea\SpringIOC\target\classes\org\rockcode\services\Fruit.class]
// file [E:\idea\SpringIOC\target\classes\org\rockcode\services\Orange.class]
Resource[] resources = new Resource[0];
try {
//加载路径下的资源
resources = resolver.getResources(pathPackage);
} catch (IOException e) {

}
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];

MetadataReader metadataReader = null;
try {
//读取资源
// 返回 classMetadata annotationMetadata
metadataReader = register.getMetadataReader(resource);
} catch (IOException e) {
continue;
}

//读取资源的注解配置
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();

//判断是否包含注解,如果有则继续,没有就重新遍历
if (!annotationMetadata.hasAnnotation(annotationClass.getName())) continue;

//类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();

//类全名
String className = classMetadata.getClassName();
try {
//加载类
Class<?> clazz = Class.forName(className);
// 这里的逻辑是注册到 beanDefinitionMap,实现方式很多,通过 clazz 实例化对象,调用相关方法,等等
// todo

} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
getClazzFromAnnotation("org.rockcode.services", EnableFruit.class);
}
}

 

  

四、通过继承 ClassPathBeanDefinitionScanner 实现扫描器

在 Spring 体系中,ClassPathBeanDefinitionScanner 占有很重要的地位,如果要实现无 xml 化,就需要注解,有注解就需要自动扫描器。

package org.rockcode.scanner;

import org.rockcode.annotations.EnableFruit;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.type.filter.AnnotationTypeFilter;

public class MyClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

    public MyClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry){
        super(registry,false);
    }

    public void registerTypeFilter(){
        addIncludeFilter(new AnnotationTypeFilter(EnableFruit.class));
    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        MyClassPathBeanDefinitionScanner myClassPathBeanDefinitionScanner = new MyClassPathBeanDefinitionScanner(context);
        myClassPathBeanDefinitionScanner.registerTypeFilter();
        myClassPathBeanDefinitionScanner.scan("org.rockcode.services");
        // 启动容器,也就是将扫描到的class实例化,并注册到beanFactory中,存入beanDefinitionMap
        context.refresh();
        //这里会拿到所有的bean实例
                String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(context.getBean(beanDefinitionName));
        }
    }
}

 

posted @ 2020-02-28 15:03  香农随笔  阅读(566)  评论(0编辑  收藏  举报