获取指定路径,扫描路径下指定类(仿Spring)

本文目标:传入指定路径,扫描对应路径下符合要求的类,并添加到指定的集合中。


其原型是Spring中初始化容器类的一部分。当然本例仅仅完成基本功能,没有考虑过多功能——即Spring中配置对应的CompontScan路径,并在类上添加@Component注解,即可完成将一个类添加到Spring容器。




自定义两个注解(2个):类比理解Spring中@Component、@ComponentScan注解

自定义MobianContext容器类(1个):类比理解Spring中AnnotationConfigApplicationContext

自定义MobianBeanDefinition类(1个):类比理解Spring中的BeanDefinition

自定义MobianConfig配置类(1个):类比理解Spring中的我们自己自定义的配置类




1、文件整体目录结构

请添加图片描述




2、自定义注解

这两个注解仅有最基础的功能,且必须配置对应的value值

MobianScan的value用于配置扫描路径

MobianComponent的value用来配置类的别名

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MobianScan {
    
    
	String value();
}
@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MobianComponent {
    
    
	String value();
}




3、编写被测试对象类

随便写的几个类,部门类添加指定的注解,并且配置别名信息

@MobianComponent("teacher")
public class TeacherService {
    
    
}
public class StudentService {
    
    
}
public interface SchoolService {
    
    
	void show();
}
@MobianComponent("schoolService")
public class SchoolServiceImpl implements  SchoolService {
    
    

	@Override
	public void show() {
    
    
	}
}




4、编写一个配置类

初始化context容器时使用

其创建是为了模仿spring的配置类,本例中仅需要使用配置的路径

@MobianScan("pers.imitationspring.service")
public class MobianConfig {
    
    
}




5、编写BeanDefinition类

这里的作用和Spring中对应的类作用相同,用来存放所有Bean的初始化信息,只是本例中比较简单

public class MobianBeanDefinition {
    
    
	private Class clazz;

	public Class getClazz() {
    
    return clazz;}
	public void setClazz(Class clazz) {
    
    this.clazz = clazz;}
}




6、编写容器类(重点)

具体细节以在代码中给出注释,主要步骤分为以下几步:

  1. 解析传入配置类上@MobianComponentScan注解配置的包路径
  2. 将包路径转化为url路径
  3. 根据url路径定位到具体的文件位置,完成文件夹下文件的遍历
  4. 将具体文件的文件位置,转化为类加载能够识别的包路径
  5. 使用类加载器加载具体的,此时可以完成类的加载
  6. 解析类上的@MobianComponent配置的类的别名信息
  7. 将类的别名信息以及类信息存储到beanDefinitionMap中
public class MobianContext {
    
    

	// 存放所有扫描出来的Bean,等价于Spring中的beanDefinitionMap集合
	ConcurrentHashMap<String, MobianBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

	public MobianContext(Class config) throws ClassNotFoundException {
    
    

		if (config.isAnnotationPresent(MobianScan.class)) {
    
    
			MobianScan scanAnno = (MobianScan) config.getAnnotation(MobianScan.class);
			// 获取注解中配置的路径
			String scanPath = scanAnno.value();

			// 将对应的路径转化为路径格式
			String scanUrl = scanPath.replace(".", "/");

			// 通过类加载器,传入相对于当前项目的路径(target/classes目录下),查找指定的资源
			// scanUrl:pers/imitationspring/service
            ClassLoader loader = MobianContext.class.getClassLoader();
			URL resource = loader.getResource(scanUrl);

			// resource : file:/E:/Softwareworkspace/ideaworkspace/writespring/target/classes/pers/imitationspring/service
			if (resource != null) {
    
    
				// 获取对应路径资源下的所有文件
				File files = new File(resource.getFile());

				// 遍历对应的文件
				for (File file : files.listFiles()) {
    
    

					// 获取当前文件的绝对路径
					String path = file.getAbsolutePath();
					// 切割路径字符串,拿到相对路径
					String classPath = path.substring(path.indexOf("pers"), path.indexOf(".class"));
					// 将相对路径转换为包结构
					classPath = classPath.replace("\\", ".");

					// 根据类的路径去创建一个对象,此时已经能获取到对应的类信息
					Class<?> aClass = loader.loadClass(classPath);
					System.out.println(aClass);
					// 获取类上对应的注解
					MobianComponent componentAnno = aClass.getAnnotation(MobianComponent.class);
					if (componentAnno != null) {
    
    
						// 在Component注解不为空的情况下,获取注解内的信息(即类注册的别名)
						String beanName = componentAnno.value();
						MobianBeanDefinition beanDefinition = new MobianBeanDefinition();
						beanDefinition.setClazz(aClass);
						// 将类别名和类信息存储到beanDefinitionMap中
						beanDefinitionMap.put(beanName, beanDefinition);
					}
				}
			}
		}
	}


	// 获取beanDefinitionMap集合中存储的所用信息
	public void printBeanDefinitionMap() {
    
    
		for (Map.Entry<String, MobianBeanDefinition> bd : beanDefinitionMap.entrySet()) {
    
    
			System.out.println(bd.getKey() + " : " + bd.getValue().getClazz());
		}
	}
}




7、测试类

初始化Context容器类,打印beanDefinitionMap集合内容(所有满足要求的类)

public class Test {
    
    
	public static void main(String[] args) throws ClassNotFoundException {
    
    

		MobianContext context = new MobianContext(MobianConfig.class);
		System.out.println("====");
		context.printBeanDefinitionMap();
	}
}

测试结果:

请添加图片描述



即我们配置的扫描路径下面包含3个类1个接口,但是符合要求的(@MobianComponent)类只有2个,满足要求的类的别名分别时teacher和是schoolService。

猜你喜欢

转载自blog.csdn.net/qq_44377709/article/details/120102686