标签:number 它的 cannot beans ons 如何 实现 qualifier error
jsoncat: 仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架
国庆节的时候,我就已经把 jsoncat 的 IoC 功能给写了,具体可以看这篇文章《手写“SpringBoot”近况:IoC模块已经完成》 。
今天这篇文章就来简单分享一下自己写 IoC 的思路与具体的代码实现。
IoC (Inverse of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程) 可以说是 Spring 框架提供的最核心的两个功能。但凡是了解过 Spring 的小伙伴,那肯定对这个两个概念非常非常了解。不了解的小伙伴,可以查看《面试被问了几百遍的 IoC 和 AOP ,还在傻傻搞不清楚?》这篇通俗易懂的文章。
考虑到这篇文章要手写 Spring 框架的 IoC 功能,所以,我这里还是简单介绍一下 IoC 。如果你不太清楚 IoC 这个概念,一定要搞懂之后再看后面具体的代码实现环节。
IoC 介绍
IoC(Inverse of Control:控制反转)是一种设计思想,也就是 将原本在程序中手动创建对象的控制权交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。
IoC 容器
IoC 容器是用来实现 IoC 的载体,被管理的对象就被存放在IoC容器中。IoC 容器在 Spring 中实际上就是个Map(key,value),Map 中存放了各种被管理的对象。
IoC 解决了什么问题
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
IoC 和 DI 别再傻傻分不清楚
IoC(Inverse of Control:控制反转)是一种设计思想 或者说是某种模式。这个设计思想就是 将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种被管理的对象。
IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。
并且,老马(Martin Fowler)在一篇文章中提到将 IoC 改名为 DI,原文如下,原文地址:https://martinfowler.com/articles/injection.html 。
@Slf4j
public class ReflectionUtil {
/**
* scan the classes marked by the specified annotation in the specified package
*
* @param packageName specified package name
* @param annotation specified annotation
* @return the classes marked by the specified annotation in the specified package
*/
public static Set> scanAnnotatedClass(String packageName, Class extends Annotation> annotation) {
Reflections reflections = new Reflections(packageName, new TypeAnnotationsScanner());
Set> annotatedClass = reflections.getTypesAnnotatedWith(annotation, true);
log.info("The number of class Annotated with @RestController :[{}]", annotatedClass.size());
return annotatedClass;
}
/**
* create object instance through class
*
* @param cls target class
* @return object created by the target class
*/
public static Object newInstance(Class> cls) {
Object instance = null;
try {
instance = cls.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
log.error("new instance failed", e);
}
return instance;
}
/**
* set the value of a field in the object
*
* @param obj target object
* @param field target field
* @param value the value assigned to the field
*/
public static void setField(Object obj, Field field, Object value) {
field.setAccessible(true);
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
log.error("set field failed", e);
e.printStackTrace();
}
}
}
根据实现思路写代码
??注意 :以下代码未涉及解决循环依赖的问题!以下是 IoC 实现的核心代码,完整代码地址:https://github.com/Snailclimb/jsoncat 。
1.扫描指定包下的特定注解比如@Component标记的类,并将这些类保存起来。
扫描指定注解@RestController和@Component并保存起来:
public class ClassFactory {
public static final Map, Set>> CLASSES = new ConcurrentHashMap();
//1.扫描指定包下的特定注解比如`@Component`标记的类,并将这些类保存起来
public static void loadClass(String packageName) {
Set> restControllerSets = ReflectionUtil.scanAnnotatedClass(packageName, RestController.class);
Set> componentSets = ReflectionUtil.scanAnnotatedClass(packageName, Component.class);
CLASSES.put(RestController.class, restControllerSets);
CLASSES.put(Component.class, componentSets);
}
}