一个模拟Spring初始化Ioc容器的demo

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/klli15/article/details/98450406

一个模拟Spring初始化Ioc容器的demo

在李刚老师的《JAVA疯狂讲义》的最后一节中,讲到一个 ObjectPoolFactory-对象池工厂,说是就是Spring框架的核心,用于创建对象以及获取对象,以此为基础写了这个demo。因为我还没看过spring的源码,所以可能会有不同,请各位斧正!

  • 涉及的知识
  1. Annotation -注解类的自定义
  2. reflect- 反射的了解,如 Class.forName(String className)class.getDeclareFields()
  3. classpath的理解
  • 这个demo实现的功能
  1. 模拟Spring:只加载具有指定Annotation类的类到IoC容器中
  2. 模拟Spring:只扫描指定包下的相关类,其他包的不管
  • IoC容器-对象池工厂ObjectPoolFactory的主要代码
package springbootCopy;

import springbootCopy.annotation.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * Create by Lingo
 */

public class ObjectPoolFactory {
   private static Map<String,Object> pool = new HashMap<>();  //初始化对象池
	//这是加载类时调用的方法,这是静态方法
    public static void createObject(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            Class<?> clazz = Class.forName(className); //记住,这个方法的参数的格式是 `com.xx.xx`这种形式
            //如果这个类没有 Component 注解,则不加载到对象池中
            if (clazz.getDeclaredAnnotation(Component.class) == null){
                return;
            }
            pool.put(className,clazz.newInstance());
    }
	//这是获取类的时候调用的,如果找不到则抛出 ClassNotFoundException  异常
    public static Object getObject(String className) throws ClassNotFoundException {
        Object object = pool.get(className);
        if (null == object){
            throw new ClassNotFoundException(className);
        }
        return object;
    }
}
  • 创建注解类
package springbootCopy.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Create by Lingo
 * 主要功能是指明这个类需要被加载到 ioc 容器中
 */
 
//指明注解在运行时仍然存在
@Retention(RetentionPolicy.RUNTIME)
//指明这个注解只能用在 类 上
@Target(ElementType.TYPE)
public @interface Component {
}
package springbootCopy.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Create by Lingo
 * 指明扫描哪个包下的类
 */
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value();
}
  • 创建2个类,用于测试是否加载成功
package springbootCopy.classes;

import springbootCopy.annotation.Component;

/**
 * Create by Lingo
 */

@Component
public class Animal {
	private String type;
    private Integer age;
    //初始化块
    {
        type = "我是 Animal";
        age = 10;
    }
}
package springbootCopy.classes;

/**
 * Create by Lingo
 */

public class Person {
    String name;
    Integer age;
}
  • 启动主程序
package springbootCopy;
import springbootCopy.annotation.ComponentScan;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;

/**
 * Create by Lingo
 */


@ComponentScan("springbootCopy.classes")  /// Ⅰ号代码
public class Main {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, IOException {
    	//还记得 @SpringBootApplication 其实这个注解就可以标志这个是启动程序,springBoot主程序只需要扫描一下就知道哪个是主程序的入口了
    	//也就获得以下的主程序 Class,这里为了方便并没有演示出来,如果这段话看不懂的同学,可以在评论区进行评论,我再丰富内容
        Class<?> clazz = Main.class;
        //如果这个没有指定扫描包,则直接返回。(理应有默认值其实)
        Annotation annotation = clazz.getDeclaredAnnotation(ComponentScan.class);
        if (null == annotation){
            return;
        }
         // 通过反射获取 指定包的扫描值,本文中 classPath = "springCopy.classes" ,由Ⅰ号代码 处获取
        String aimPath = ((ComponentScan)annotation).value();
        // 获取 classpath,或者理解成编译后的 class文件存在的地方
        String url =ClassLoader.getSystemClassLoader().getResource("")+aimPath;
       	// 要将 aimPath 的 . 替换成 / ,才能拼凑成编译后class的路径
        url = url.replace(".","/");
        url = url.replace("file:/",""); // 去掉classpath 中的 file:/
        File file = new File(url);
        File[] subFiles = file.listFiles();
        //遍历这个文件下的所有 class 文件,并将符合条件的类加载到对象池里
        for (File subFile : subFiles) {
        	// 提取 className , 例如 springCopy.classes.Animal
            String className =  aimPath+"."+subFile.getName().substring(0,subFile.getName().indexOf("."));
            ObjectPoolFactory.createObject(className);
        }
        //获取相关的加载类,如果对象池没有这个类的话,则会有 classNotFound 的错
        for (File subFile : subFiles) {        	
            String path =  aimPath+"."+subFile.getName().substring(0,subFile.getName().indexOf("."));
            Object object = ObjectPoolFactory.getObject(path);
            System.out.println(object);
             for (Field declaredField : object.getClass().getDeclaredFields()) {
                declaredField.setAccessible(true); //关闭 私有 Field 的权限检查,即所有的Field 无论权限控制符是啥,都可以访问
                System.out.println(declaredField.get(object));
            }          
        }
    }
}
  • 输出结果 :因为 Person 类没有 @Component的注解,所以没有加载到容器中,因此报错
springbootCopy.classes.Animal@266474c2
我是 Animal
10
Exception in thread "main" java.lang.ClassNotFoundException
	at springbootCopy.ObjectPoolFactory.getObject(ObjectPoolFactory.java:26)
	at springbootCopy.Main.main(Main.java:34)

Process finished with exit code 1

如果再加上 AOP 则可以实现很多功能。
以上则是这个demo的全部内容,欢迎各位斧正!

END

猜你喜欢

转载自blog.csdn.net/klli15/article/details/98450406
今日推荐