文章目录
前言
学习了很久的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. 反射
- 既然不能手动new对象,那么我们的第一反应就是通过反射来做
- 假设我们有如下两个类:
@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);
}
}
- 如果我们要通过反射来实例化一个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);
}
}
- 那么很自然的,我们会想到继续通过反射来进行属性设置
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. 思考
我们可以这样写的前提是什么?
- 我们提前知道了需要实例化哪个类(Node)
- 我们提前知道了这个类里面有哪些属性需要通过反射来设置(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需要一定要做的三个主体工作:
- 确定需要实例化哪些类和需要设置的属性
- 实例化这些类
- 对这些被实例化的类进行属性设置
- 进行代理
当然Spring作为一个开源且鲁棒性极佳的框架,在主体功能的实现上有很多细节处理和具体实现方式。
- 譬如第一步,不可能像我们这样通过注册来实现,Spring是通过用户配置的path,扫描path下面的class文件,根据文件上的注解以及校验(是不是合成类,是不是匿名内部类,是不是抽象类)
- 实例化类的时候,需要推断类中最合理的构造方法
- 通过扫描类里的注解来确定每个实例哪些地方需要进行属性设置(field and method)
- 属性设置可能拥有循环依赖
- AOP的设置除了jdk动态代理还有CGLIB的,同时还要考虑aspect的实现
- 钩子函数:init
这样就有了一个最简单的Spring实现,当然Spring里也有一个类似我们此处定义的MetaNode的类,叫BeanDefinition。
而我们的MyContainer可以算是一个最简单的BeanFactory了。
参考这个类上面的document:
示例代码
代码地址:我的GitHub