利用反射模拟创建一个Spring容器

14 篇文章 1 订阅
  • 定义两个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AutoWired {
}
  • 定义几个测试类
@Component
public class UserMapper {
    

}
@Component
@Setter
@Getter
public class UserServiceV2 {

    @AutoWired
    private OrderService orderService;

    private String name;
    private Integer age;
    public String address;

    private void helloUser(){
        System.out.println("helloUser...");
    }

    private void helloUser(String str){
        System.out.println("helloUser..." + str);
    }

}
@Setter
@Getter
@Component
public class OrderService {

    private String orderNo = "123";

    @AutoWired
    private UserServiceV2 userServiceV2;

}

@Data
@Component
public class UserController {

    @AutoWired
    private UserServiceV2 userService;

}

  • 容器代码
public class ApplicationContext {

    private static Map<Class, Object> context = new ConcurrentHashMap<>();

    public static void init(String basePackages) throws Exception{
        String basePackageSperator = basePackages.replaceAll("\\.", Matcher.quoteReplacement(File.separator));
        //获取到classpath
        URL resource = Thread.currentThread().getContextClassLoader().getResource("");
        File file = new File(resource.getFile());
        String basePath = file.getAbsolutePath() + File.separator + basePackageSperator;
        //从basePath下开始遍历class文件
        File classFilePath = new File(basePath);
        List<String> filePaths = new ArrayList<>();
        getPath(classFilePath.getAbsolutePath(), filePaths, ".class");
        //遍历这些class文件,创建标有@Component注解的对象
        filePaths = filePaths.stream().map(item -> {
            item = item = item.replace(classFilePath.getAbsolutePath() + File.separator, "");
            item = item.replace(".class","");
            return item;
        }).collect(Collectors.toList());

        doInitContext(basePackages,filePaths);

    }

    private static void doInitContext(String basePackages, List<String> filePaths) throws Exception {
        for (String filePath : filePaths) {
            Class<?> clazz = Class.forName(basePackages + "." + filePath);
            if (clazz.isAnnotationPresent(Component.class)){
                Object newInstance = clazz.newInstance();
                context.put(clazz,newInstance);
            }
        }
        context.keySet().stream().forEach(k -> {
            Field[] declaredFields = k.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                boolean present = declaredField.isAnnotationPresent(AutoWired.class);
                if (present){
                    Class<?> type = declaredField.getType();
                    //从容器中找出该属性类型的实例
                    Object bean = getBean(type);
                    //将这个bean赋值给该对象的属性
                    Object instance = context.get(k);
                    declaredField.setAccessible(true);
                    try {
                        declaredField.set(instance,bean);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

    }

    public static  <T> T getBean(Class<T> clazz){
        return (T) context.get(clazz);
    }

    private static void getPath(String rootPath, List<String> filePaths, String suffix) {
        File file = new File(rootPath);
        Optional<File[]> files = Optional.ofNullable(file.listFiles(
                (f) -> f.isDirectory() || f.getName().endsWith(suffix)
        ));
        //找出该目录下所有符合后缀名的文件名以及目录,目录需要递归遍历
        files.ifPresent(fs -> {
            for (File f : fs) {
                if (f.isDirectory()) {
                    getPath(f.getAbsolutePath(), filePaths, suffix);
                } else {
                    filePaths.add(f.getAbsolutePath());
                }
            }
        });
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext.init("com.example.demo.reflect.app");
        ApplicationContext.context.keySet().stream().forEach(k -> {
            System.out.println(context.get(k));
        });

        UserServiceV2 bean = ApplicationContext.getBean(UserServiceV2.class);
        OrderService orderService = ApplicationContext.getBean(OrderService.class);
        System.out.println("bean.getOrderService() == orderService = " + (bean.getOrderService() == orderService) );

    }

}

核心思想就是从classpath目录下,拼接上给定的包名,整理成一个目录,然后遍历这个目录下的class文件,将文件路径格式替换为全类名格式,然后通过给定全限定类名,创建class实例对象。判断该class对象有没有被@Component注解修饰,有的话创建一个对象,存入容器,创建完成以后再继续遍历每个class对象的成员变量是否被@AutoWried修饰,如果有,则找到该成员变量类型的对象,为该class对象的该成员变量赋值。这整个过程中其实就是对象引用的来回传递。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值