手写简单的spring(1):了解Spring的原理


前言

学习了很久的Spring之后,我觉得可以写一篇文章,简单解析下Spring的原理


一、没有Spring

1. 代码块

public class Application {
	
	private MyService myService;

	public void setMyService(MyService myService) {
		this.myService = myService;
	}

	public static void main(String[] args) {
		Application application = new Application();
		application.setMyService(new MyService());
	}
	
}

2. 简单的原理

在这里插入图片描述
可以参考这篇博客:https://www.jianshu.com/p/3ca14ec823d7

二、有了Spring

1.代码块

代码如下(示例):

@Component
public class Application {

	@Autowired
	private MyService myService;

}

so gentle, so simple

三、How do spring do it ?

1. Spring是怎么实现以上功能的

如果由我们来写spring,思路是什么?答案不重要,重要的永远是思考的方向和过程。

2. 反射

  1. 既然不能手动new对象,那么我们的第一反应就是通过反射来做
  2. 假设我们有如下两个类:
@NoArgsConstructor
@ToString
@Slf4j
public class Item {
  private int mark;
}

public interface MyInterface {
    void doSomething();
}

@Slf4j
@NoArgsConstructor
@ToString
public class Node implements MyInterface{

    private Item item;

	@Override
    public void doSomething() {
        System.out.println("node is doing something with item:" + item);
    }

}

  1. 如果我们要通过反射来实例化一个Node,我们一般如下做法:
	public static void main(String[] args) {
        try {
            Node node = Node.class.newInstance();
            System.out.println(node);
        } catch (Exception e) {
            log.error("oops, there is an error", e);
        }

    }

在这里插入图片描述

  1. 那么很自然的,我们会想到继续通过反射来进行属性设置
public static void main(String[] args) {
        try {
            Node node = Node.class.newInstance();
            Item item = Item.class.newInstance();
            Field[] declaredFields = Node.class.getDeclaredFields();
            for (Field field : declaredFields) {
                if (field.getType().equals(Item.class)) {
                    field.setAccessible(true);
                    field.set(node, item);
                }
            }
            System.out.println(node);
        } catch (Exception e) {
            log.error("oops, there is an error", e);
        }

    }

在这里插入图片描述

3. 思考

我们可以这样写的前提是什么?

  1. 我们提前知道了需要实例化哪个类(Node)
  2. 我们提前知道了这个类里面有哪些属性需要通过反射来设置(Item)

那么是不是我们解决掉这两个问题,我们相当于就实现了一个简易版本spring的IOC?说干就干!

3.1 代码实现

MetaNode:用来保存需要实例化的class,以及该class需要设置的属性

@NoArgsConstructor
@Slf4j
@ToString
@Data
public class MetaNode {

    private Class clazz;

    private Map<String, Field> fieldMap;

}

MyContainer:用来进行主体功能方法

@Slf4j
public class MyContainer {

    /**
     * 保存所有需要处理的类信息:包括类以及他们需要设置的属性
     */
    private static Map<Class, MetaNode> META_NODE_MAP = new HashMap<>();

    /**
     * 保存最终生成的实例
     */
    private static Map<Class, Object> BEAN_MAP = new HashMap<>();

    public static void registerClass(Class clazz, List<Field> fieldList) {
        if (!META_NODE_MAP.containsKey(clazz)) {
            MetaNode metaNode = new MetaNode();
            metaNode.setClazz(clazz);
            Map<String, Field> fieldMap = CollectionUtils.emptyIfNull(fieldList).stream()
                    .collect(Collectors.toMap(Field::getName, Function.identity()));
            metaNode.setFieldMap(fieldMap);
            META_NODE_MAP.putIfAbsent(clazz, metaNode);
        }
    }

    public static void main(String[] args) {
        try {
            System.out.println(BEAN_MAP.values());
            System.out.println("init==========");
            // 1. 注册需要处理的class
            registerClass();

            // 2. 遍历所有需要处理的class,然后进行 instance 和 inject
            for (Class clazz : MapUtils.emptyIfNull(META_NODE_MAP).keySet()) {
                if (BEAN_MAP.containsKey(clazz)) {
                    continue;
                }
                Object instance = complete(clazz);
                BEAN_MAP.putIfAbsent(clazz, instance);
            }
			MyInterface o = (MyInterface)BEAN_MAP.get(Node.class);
            o.doSomething();

            System.out.println(BEAN_MAP.values());
            System.out.println("done==========");
        } catch (Exception e) {
            log.error("Oops, there is a error", e);
        }

    }

    private static Object complete(Class clazz) throws Exception {
        MetaNode metaNode = META_NODE_MAP.get(clazz);
        if (Objects.isNull(metaNode)) {
            return null;
        }
        // 1. 实例化
        Object instance = instance(clazz);
        // 2. 属性设置
        injectField(instance, metaNode.getFieldMap());
        // 3. aop
        instance = wrapIfNecessary(clazz, instance);
        return instance;
    }

    private static void registerClass() throws Exception{
        registerClass(Node.class, Collections.singletonList(Node.class.getDeclaredField("item")));
        registerClass(Item.class, null);
    }

    private static Object instance(Class clazz) throws Exception{
        return clazz.newInstance();
    }

    private static void injectField(Object instance, Map<String, Field> fieldMap) throws Exception {
        for (Map.Entry<String, Field> fieldEntry : MapUtils.emptyIfNull(fieldMap).entrySet()) {
            Field field = fieldEntry.getValue();
            Class<?> type = field.getType();
            Object toInject = BEAN_MAP.get(type);
            if (Objects.isNull(toInject)) {
                toInject = complete(type);
                BEAN_MAP.putIfAbsent(type, toInject);
            }
            field.setAccessible(true);
            field.set(instance, toInject);
        }

    }

    private static Object wrapIfNecessary(Class clazz, Object object) {
        Class[] interfaces = clazz.getInterfaces();
        if (Objects.isNull(interfaces) || interfaces.length == 0) {
            return object;
        }

        Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("it is a proxy doing its job:" + method.getName());
                Object invoke = method.invoke(object, args);
                return invoke;
            }
        });

        return proxy;

    }

}

在这里插入图片描述

基于以上可以看到我们的思路是正确的

总结

Spring的IOC需要一定要做的三个主体工作:

  1. 确定需要实例化哪些类和需要设置的属性
  2. 实例化这些类
  3. 对这些被实例化的类进行属性设置
  4. 进行代理

当然Spring作为一个开源且鲁棒性极佳的框架,在主体功能的实现上有很多细节处理和具体实现方式。

  1. 譬如第一步,不可能像我们这样通过注册来实现,Spring是通过用户配置的path,扫描path下面的class文件,根据文件上的注解以及校验(是不是合成类,是不是匿名内部类,是不是抽象类)
  2. 实例化类的时候,需要推断类中最合理的构造方法
  3. 通过扫描类里的注解来确定每个实例哪些地方需要进行属性设置(field and method)
  4. 属性设置可能拥有循环依赖
  5. AOP的设置除了jdk动态代理还有CGLIB的,同时还要考虑aspect的实现
  6. 钩子函数:init

这样就有了一个最简单的Spring实现,当然Spring里也有一个类似我们此处定义的MetaNode的类,叫BeanDefinition。
而我们的MyContainer可以算是一个最简单的BeanFactory了。
参考这个类上面的document:
在这里插入图片描述

示例代码

代码地址:我的GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值