聊聊Spring自动扫描

Posted 香农随笔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊聊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));
        }
    }
}

 

以上是关于聊聊Spring自动扫描的主要内容,如果未能解决你的问题,请参考以下文章

Spring 3.0 学习-DI 依赖注入_创建Spring 配置-使用一个或多个XML 文件作为配置文件,使用自动注入(byName),在代码中使用注解代替自动注入,使用自动扫描代替xml中bea(

聊聊spring之贯穿全局的重要对象BeanDefinition

spring使用注解,自动扫描类的时候怎么注入

Spring常用注解,自动扫描装配Bean

Spring IoC 源码分析 (基于注解) 之 包扫描

Spring_自动组件扫描