聊聊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(