从零实现一个 Java 微框架 - IoC
前言
IoC 容器在之前的文章中就有说明。
之前的文章其实是基于 PHP 的,虽然思想是类似的,不过还是再次说明一下吧。
IoC 是什么?
IoC(Inversion of control,控制反转),它是一种思想而不是一个技术实现(组件),通常也和 DI(Dependency Injection,依赖注入)一同出现,这两者其实可以看成一个东西。不过 DI 更多的是指注入的过程或方式(B 对象注入到了 A),IoC 更多的是指这种反转思想(B 对象交给了外部管理)。
为了更好的描述 IoC,这里我们 就引入一个样例吧,就拿我前几天购买的一个阅读器来说吧。既然是阅读器,那么我们肯定是要有个阅读器的类:
_16public class BookReader {_16_16 private final BookStorage storage;_16_16 public BookReader() {_16 this.storage = new FileBookStorage();_16 }_16_16 public String read(final String name) {_16 return this.storage.getBook(name).getContent();_16 }_16_16 public void put(final Book book) {_16 this.storage.registerBook(book);_16 }_16}
其中,我们需要一个 BookStorage
来存储阅读器里存放的书,然后阅读器拥有 read
阅读和 put
存新书的功能。
通常情况下我们会将所依赖的 BookStorage
的对象直接在构造器中 new
出来,这是最简单且直接的使用方式。但是这种简单的方式也导致了一种问题,如果哪天需要开发一个基于网络的阅读器,那么我们的存储不再是 FileBookStorage
,而应该是 NetworkBookStorage
,此时为了能制作出网络阅读器我们就不得不重新写一个 BookReader
类,然后重新实现内部的逻辑。
这时候肯定有人会提出应该把 BookStorage
从外面通过构造器传入不就可以了?其实当你提出这个疑问的时候你已经可以说了解 IoC 了,这种通过外部传入依赖的方式就称为依赖注入,也就是控制反转的思想。
控制反转中的控制指的是对对象管理、创建的权力;反转指的是将这个控制权交给外部环境,至于外部环境可以是几行代码、IoC 容器。使用者只负责使用依赖,至于依赖是如何构造、管理的这就不关使用者的事了。
利用 IoC 思想改造后的构造器如下:
_3public BookReader(final BookStorage bookStorage) {_3 this.storage = bookStorage;_3}
改造后虽然我们丢失了创建 BookStorage
的功能,不过相对的这种方式解决了各部件间强耦合的问题,我们可以通过给 BookReader
传入不同的 BookStorage
来灵活的实现及复用。
IoC 容器
**IoC 容器(IoC Container)**一般也称为 IoC 服务提供者(IoC Service Provider),简单的说就是用来自动化创建依赖以及管理依赖的工厂。由于经常被简称为 IoC 所以也很多人会认为 IoC 就是 IoC 容器,其实 IoC 容器 只是用来方便实现 IoC 思想的一种工具。
最简单的 IoC 容器包括了以下几种功能:
- 对象的构建管理:当我们需要某个对象的时候无需关心它是如何被创建出来的、需要什么依赖关系,这个过程就是由 IoC 负责的。
- 对象的依赖绑定:为了对对象进行构建,IoC 容器需要知道对象的依赖关系。
- 对象的存储管理:既然是容器那就需要有存储的功能,IoC 容器可以依照需求存储单例对象或依赖(需要存储的依赖不单单是 Bean 对象)。
对于现在的 IoC 容器来说注册对象管理信息一般有以下 3 种:
- 直接编码:即调用注册方法
regsiter
将对象注册到 IoC 容器中。 - 配置文件:在 Spring IoC 等容器一般都存在这种配置方式,通过配置文件配置 IoC 容器的对象及依赖关系。
- 元数据:元数据的方式则较为广泛,注解、类型、变量名等等都可以作为元数据来指引 IoC 容器注册和使用对象。
通常情况 IoC 容器有以下几种注入方式:
- 构造器注入
- Setter 方式注入
- 字段注入:字段注入可以归入 Setter 注入,有一定侵入性,是利用反射直接设置字段值的方式。
- 接口注入:接口注入是比较特殊的,带有侵入性,不一定所有 IoC 容器都支持,是通过实现接口方法来取得注入的依赖。
设计 IoC 容器
既然已经知道了 IoC 容器需要的功能,那么就可以开始设计我们自己的 IoC 容器了。文章可能会结合一些 Spring 的东西。不过本篇文章主要是写我自己的 Java 框架,所以 Spring 就点到为止了,如需深入的话可以看别的源码解析的文章或者书籍。比如这篇大佬写的文章就还不错。
XK-Java IoC 容器的设计较为简单,其设计最初的参考是来自 Laravel,不过经过后续不断的重构已经比较类似 Spring IoC 了。
XK-Java IoC 容器所需要存储的数据:
- 实例元信息(Binding, BeanDefinition):保存实例的一些信息,如作用域、名称、注解等一系列容器需要使用的信息。
- 实例(Instance, Singleton):由于有些实例是以单例的状态存储的,所以容器还需要为这些实例提供存储。
- 别名(Alias):实例可以有别的名称。
- 类型索引(BeanNameByType):通常情况下我们都不会对每个 Bean 都进行配置,所以 IoC 容器一般是使用类型来进行自动注入的,为了能快速的查询到指定类型的依赖,我们需要对每个绑定到 IoC 容器的依赖都进行类型遍历,然后建立索引。
- 注入器 & Bean 处理器(Injector & BeanProcessor):为了方便扩展和实现额外的功能就不能把构建的流程封闭到 IoC 容器,所以需要通过注入器或者 Bean 处理器来处理实例或依赖。
- 作用域(Context, Scope):IoC 容器不可能只存储某个作用域的实例,通常有多种作用域,比如单例域、非单例、请求域等多种作用域来存储实例。
- 临时依赖(DataBinder):由于部分情况需要临时注入一些依赖,比如 HTTP 的请求参数,这就需要有一个数据容器来临时存储这些参数依赖。
XK-Java IoC 容器所需要的功能:
- 绑定:用于将依赖绑定到容器中,依赖可以是已经构建完成的实例、立即值、工厂类等等。对应
bind
、doBind
方法。 - 构建:当某个依赖被依赖的时候,而且依赖没有构建的时候就需要对依赖进行构建。对应
doBuild
方法。 - 获取:当我们需要某个实例的时候,就需要从 IoC 容器获取。对应
make
、doMake
方法。 - 销毁:当依赖被从容器删除,或者容器关闭的时候就需要对依赖进行销毁操作,如关闭连接池等等的操作。对应
remove
、doRemove
方法。
实现
有了大致的设计我们就可以开始动工了。
首先需要准备一些周边的类和接口,以下这些周边类是属于 IoC 的一部分,有些其他的类,如 MergedAnnotation,就不在这里说明了。
- TypeProvider:为实现集合、Map 等复合类型注入的类型提供器。因为 Java 有泛型擦除的问题,无法简单的保留泛型,需要从
Field
等类中读取然后保存传递到容器中。 - TypeWrapper:
TypeProvider
的实现类。 - FactoryBean:工厂 Bean,作用和 Spring 的类似,用于创建 Bean 的工厂。
- ObjectFactory:作用和 Spring 类似,用于延迟获取 Bean,不过在本框架也用于 Cglib 代理。
- ObjectProvider:作用和 Spring 类似,相当于高级的
ObjectFactory
。 - AnnotatedEntry、ClassProperty、ConstructorContext、InjectContext、ParameterContext:一些包装类。
- ScopeType:就一个静态类,存放内置作用域名称的常量。
有了上面这些周边类,就可以进入下一部分了。
DataBinder
由于 XK-Java 的设计与 Spring 有所不同。在 XK-Java 的设计里,所有需要注入的(如注入单例,注入请求参数) Java 实例都应该由 IoC 容器负责构建。通常情况下我们有可能会临时设置一些依赖,而又不希望这些临时的依赖托管到容器里,这时候就需要 DataBinder
来负责存储。
_19// see: https://github.com/syfxlin/xkjava/blob/36b1ca22c86790b93e79a00c5b6c3e031ad6139b/xkjava-framework/src/main/java/me/ixk/framework/ioc/binder/DataBinder.java_19public interface DataBinder {_19 /**_19 * 获取实例_19 *_19 * @param name 实例名_19 * @param type 实例类型_19 * @param annotation 注解_19 * @param <T> 实例类型_19 * @param container 容器_19 * @return 实例_19 */_19 <T> T getObject(_19 String name,_19 TypeWrapper<T> type,_19 MergedAnnotation annotation,_19 Container container_19 );_19}
DataBinder
被设计为简单的依赖存储容器,所以无需非常多的元信息,通过实例的名称、类型、注解即可取得其存储的实 例。可以认为是缩小版的 IoC 容器。
DefaultDataBinder
是默认的实现类:
_57// see: https://github.com/syfxlin/xkjava/blob/36b1ca22c86790b93e79a00c5b6c3e031ad6139b/xkjava-framework/src/main/java/me/ixk/framework/ioc/binder/DefaultDataBinder.java_57public class DefaultDataBinder implements DataBinder {_57 // 实例容器 <名称,实例>_57 private final Map<String, Object> objects = new HashMap<>();_57 // 类型对应的实例名称 <类型,<名称>>_57 private final Map<Class<?>, List<String>> objectTypes = new HashMap<>();_57_57 @Override_57 public <T> T getObject(_57 String name,_57 final TypeWrapper<T> type,_57 final MergedAnnotation annotation,_57 final Container container_57 ) {_57 // 取得 @DataBind 注解,@DataBind 注解可以控制注入的实例_57 final DataBind dataBind = annotation == null_57 ? null_57 : annotation.getAnnotation(DataBind.class);_57 if (dataBind != null && dataBind.name().length() != 0) {_57 // 如果 DataBind 设置要取得的实例的名称就以 DataBind 为准_57 name = dataBind.name();_57 }_57 final Class<T> clazz = type.getClazz();_57 // 取得对应名称的实例_57 Object object = this.objects.get(name);_57 // 如果取得的实例类型不符,那就放弃这个实例(需要注意,DataBind 被设计为不允许类型转换)_57 if (object != null && !clazz.isInstance(object)) {_57 object = null;_57 }_57 if (object == null) {_57 // 如果通过名称找不到就尝试通过类型查找_57 final List<String> list = this.objectTypes.get(clazz);_57 final String objectName;_57 if (list == null || list.isEmpty()) {_57 // 如果没找到就使用默认的名称,即类名首字母小写后的名称_57 objectName = container.typeToBeanName(clazz);_57 } else {_57 objectName = list.get(0);_57 }_57 object = this.objects.get(objectName);_57 }_57 if (object == null) {_57 // 如果还是没取得,就尝试使用 IoC 容器构建(递归构建)_57 object = container.make(name, type, this);_57 }_57 if (_57 object == null &&_57 dataBind != null &&_57 DataBind.EMPTY.equals(dataBind.defaultValue())_57 ) {_57 // 构建还是失败了(真惨),那就使用 DataBind 设置的默认值_57 object = dataBind.defaultValue();_57 }_57 // 类型转换(需要注意,这只是简单的转换)_57 return Convert.convert(clazz, object);_57 }_57}
Context
Context
类似于 Spring 的 Scope
,用于作用域隔离,比如线程私有实例,请求私有实例等等。具体的可以参考 Spring 的 Scope
的作用。
_75// see: https://github.com/syfxlin/xkjava/blob/36b1ca22c86790b93e79a00c5b6c3e031ad6139b/xkjava-framework/src/main/java/me/ixk/framework/ioc/context/Context.java_75public interface Context {_75 /**_75 * 是否是共享的,即单 例_75 *_75 * @return 是否_75 */_75 default boolean isShared() {_75 return true;_75 }_75_75 /**_75 * 该 Context 是否启动,一般的 Context 只要 new 后就会启动 但是如果是 ThreadLocal 则需要另行启动_75 *_75 * @return 是否启动_75 */_75 default boolean isCreated() {_75 return true;_75 }_75_75 /**_75 * 是否需要代理_75 *_75 * @return 是否需要代理_75 */_75 default boolean useProxy() {_75 return false;_75 }_75_75 /**_75 * 获取所有实例_75 *_75 * @return 所有实例_75 */_75 ConcurrentMap<String, Object> getInstances();_75_75 /**_75 * 获取实例_75 *_75 * @param name 实例名称_75 * @return 实例_75 */_75 default Object get(final String name) {_75 return this.getInstances().get(name);_75 }_75_75 /**_75 * 删除实例_75 *_75 * @param name 实例名称_75 */_75 default void remove(final String name) {_75 this.getInstances().remove(name);_75 }_75_75 /**_75 * 设置实例_75 *_75 * @param name 名称_75 * @param instance 实例_75 */_75 default void set(final String name, final Object instance) {_75 this.getInstances().put(name, instance);_75 }_75_75 /**_75 * 是否存在实例_75 *_75 * @param name 实例名称_75 * @return 是否存在_75 */_75 default boolean has(final String name) {_75 return this.getInstances().containsKey(name);_75 }_75}
可以看到 Context
其实就是一个类似 Map
的容器,只不过有些其他的方法:
isShared
方法用于确定是否是单例,如果是单例 IoC 容器会在构建实例完后将单例存入Context
。isCreated
方法用于确定实例是否启动,避免在未启动的时候错误使用。useProxy
方法用于确定实例是否需要 Cglib 代理来实时获取最新的值,避免发生使用旧对象情况,或者将 Request 作用域对象注入到 Singleton 作用域导致线程不安全。 有了接口自然有实现类,以下是几个不同场景的实现类,这几个实现类由于代码简单就不细说了:- SingletonContext:单例作用域,里面就是一个简单的
ConcurrentHashMap
。 - PrototypeContext:原型作用域,不存储实例,是非共享的。
- RequestContext:请求作用域,这个作用域和 SessionContext 一样比较特殊,是存储于对应作用域的对象里,比如 Request 是存储于
HttpServletRequest
的 Attribute 里,Session 则存储于HttpSession
里。
Binding
Binding
是实例元信息的实现类,与 Spring 中的 BeanDefinition
类似,不过由于不需要太多的功能就只保存了几种元信息:
- 作用域名称(scope):实例对应的作用域名称。
- 名称(name):实 例名称,全局唯一。
- 类型及类注解(instanceTypeEntry):实例的类型及标记在该类上的组合注解。
- 是否是主要的实例(primary):如果是主要注解,当通过类型获取实例,同时该类型下有多个不同的实例,则优先使用
primary
为true
的实例。 - 额外信息(bindingInfos):带软引用缓存的一些信息,有 init-destory 对应的方法反射和 autowired 需要注入的方法,以及字段和方法的反射以及注解。同类型并且有缓存的情况下就不需要再扫描。
除了元信息外 Binding
还保存了一些其他的数据:
- Context:作用域,为了
Binding
内部方法方便操作,避免要使用的时候从 IoC 容器中获取。 - FactoryBean:创建实例的工厂方法,如果未设置 IoC 容器会默认使用 doBuild 方法构建实例。
- Mutex:
Binding
的互斥量(锁)用于避免多次初始化单例使用。将互斥量分散到不同的Binding
中,避免使用唯一互斥量导致大量阻塞的发生。同时单例也采用双重检查模式,避免每次获取的时候都锁住互斥量导致阻塞。
数据部分说完了就开始看方法吧,首先是初始化,初始化就是对 Binding
内的字段进行赋值,扫描对应类型的方法、注解等等的信息,对于消耗性能的扫描部分则使用软引用,空间换时间,避免重复扫描,同时在内存不足的时候可以时间换空间,一定程度避免 OOM 发生。
然后 Binding
里剩下的重要操作就是对实例的操作了:
_45// see: https://github.com/syfxlin/xkjava/blob/36b1ca22c86790b93e79a00c5b6c3e031ad6139b/xkjava-framework/src/main/java/me/ixk/framework/ioc/entity/Binding.java_45public class Binding {_45 public Object getSource() {_45 // 双重检查获取,因为此时实例可能在构建_45 final Object source = this.getSourceUnsafe();_45 if (source == null) {_45 synchronized (this.getMutex()) {_45 return this.getSourceUnsafe();_45 }_45 }_45 return source;_45 }_45_45 public Object getSource(final boolean proxy) {_45 // 是否使用代理,如果使用代理则利用 Cglib 进行代理,避免引用旧实例,否则就直接取得未代理的实例_45 // 因为执行方法的时候,实际上是每次都使用 getSource 方法取出最新的实例,然后执行_45 // 代理需要满足所有条件才会生效:_45 // 1. 是单例_45 // 2. Context 的作用域配置了需要代理_45 // 3. 注入的类型需要代理,在 TypeWrapper 配置(典型的就是 Field)_45 if (proxy && this.useProxy() && this.isShared()) {_45 return ReflectUtils.proxyObjectFactory(_45 (ObjectFactory<Object>) this::getSource,_45 this.getType()_45 );_45 } else {_45 return this.getSource();_45 }_45 }_45_45 private Object getSourceUnsafe() {_45 // 获取实例前需要判断 Context 是否已经启动,如果未启动就直接返回 null,避免 NPE。_45 return this.isCreated() ? this.context.get(name) : null;_45 }_45_45 public void setSource(final Object instance) {_45 // 设置实例的时候锁住互斥量_45 synchronized (this.getMutex()) {_45 // 要确定是单例才可以存入 Context,否则就不能存入_45 if (this.context.isShared()) {_45 this.context.set(name, instance);_45 }_45 }_45 }_45}
Injector
与 Spring 不同的是,XK-Java 为了更好的扩展性添加了**注入器(Injector)**的设计,其作用仅作为对实例或参数进行注入。目前共有两种类型的 Injector
:
- ParameterInjector:用于参数注入的注入器。
- InstanceInjector:用于实例注入的注入器。
添加注入器的方式非常简单,只需要给注入器的类添加 @Injector
注解,注解扫描器会自动识别注入器并添加到 IoC 容器中。同时可以使用 @Order
注解来对注入器进行排序。
DefaultParameterInjector
是默认的参数注入器,其负责通过参数的元信息构建或获取参数,然后让 IoC 容器可以构建实例或者调用方法:
注入规则:
- 标记了
@DataBind
方法。利用@DataBind
的一些限制查找依赖注入。 - 标记了
@Value
方法。使用@Value
的表达式进行查找注入。 - 未标记任何注解。使用
DataBinder
进行注入。
_86// see: https://github.com/syfxlin/xkjava/blob/36b1ca22c86790b93e79a00c5b6c3e031ad6139b/xkjava-framework/src/main/java/me/ixk/framework/ioc/injector/DefaultParameterInjector.java_86public class DefaultParameterInjector implements ParameterInjector {_86 @Override_86 public Object[] inject(_86 Container container,_86 Object[] dependencies,_86 ParameterContext context_86 ) {_86 // 通过 Parameter 的上下文取得参数反射对象、名称、注解等信息_86 final ParameterEntry[] entries = context.getParameterEntries();_86 for (int i = 0; i < entries.length; i++) {_86 // ParameterEntry 中有个 changed 的标记用于标记是否已经设置_86 // 如果已经设置则不需要使用 DefaultParameterInjector 再次设置_86 // 当然这个标记要靠 ParameterInjector 是否遵守_86 if (entries[i].isChanged()) {_86 continue;_86 }_86 Parameter parameter = entries[i].getElement();_86 String parameterName = entries[i].getName();_86 MergedAnnotation annotation = entries[i].getAnnotation();_86 // 获取 @DataBind 注解,由于 DefaultParameterInjector 并不只用于构造器,所以这个注解还是需要的_86 DataBind dataBind = annotation.getAnnotation(DataBind.class);_86 // 获取 @Value 注解_86 final Value value = annotation.getAnnotation(Value.class);_86 if (value != null) {_86 // 如果设置了 @Value 注解则优先使用 @Value 注解_86 final InjectContext injectContext = context.getContext();_86 // 利用 SpEL 解析 @Value 里的表达式,具体看源码,就是委托给 BeanExpressionResolver 解析_86 dependencies[i] =_86 this.resolveExpression(_86 value,_86 injectContext.getType(),_86 // 获取从 PropertiesProcessor 里设置的 properties 和 prefix_86 // PropertiesProcessor 是 BeforeInjectProcessor,会在 Injector 之前执行_86 injectContext.getData(_86 PropertiesProcessor.PROPERTIES_86 ),_86 injectContext.getData(_86 PropertiesProcessor.PROPERTIES_PREFIX_86 ),_86 container_86 );_86 } else {_86 // 否则就使用当前的 DataBinder 来取得依赖_86 // 默认是 DefaultDataBinder_86 dependencies[i] =_86 context_86 .getBinder()_86 .getObject(_86 parameterName,_86 // 将 Parameter 封装起来是为了传递泛型信息_86 TypeWrapper.forParameter(parameter),_86 annotation,_86 container_86 );_86 }_86 if (_86 dependencies[i] == null &&_86 dataBind != null &&_86 dataBind.required()_86 ) {_86 // 如果这个参数是必须要注入的,但是未查找到依赖则抛出 NPE_86 final NullPointerException exception = new NullPointerException(_86 "Target [" +_86 context.getExecutable().getDeclaringClass().getName() +_86 "@" +_86 context.getExecutable().getName() +_86 "(" +_86 parameterName +_86 ")] is required, but inject value is null"_86 );_86 log.error(_86 "Target [{}@{}({})] is required, but inject value is null",_86 context.getExecutable().getDeclaringClass().getName(),_86 context.getExecutable().getName(),_86 parameterName_86 );_86 throw exception;_86 }_86 // 不管有没有注入完成都设置 changed 标记,表示已经处理过了_86 // DefaultParameterInjector 是优先级最低的注入器,所以设不设置都一样,不过还是遵守标准吧_86 entries[i].setChanged(true);_86 }_86 return dependencies;_86 }_86}
DefaultPropertyInjector
是默认的字段(成员)注入器,与 PropertiesValueInjector
一同作用,用于对实例字段进行注入:
注入规则:
- 字段存在 Setter 方法。使用 Setter 方法注入。
- 字段标记了
@Autowired
注解,但是没有 Setter 方法。直接反射设置。 - 字段标记了
@Autowired
注解,同时有 Setter 方法。使用 Setter 方法注入。
_111public class DefaultPropertyInjector implements InstanceInjector {_111 @Override_111 public Object inject(_111 Container container,_111 Object instance,_111 InjectContext context_111 ) {_111 // 获取所有字段_111 for (ChangeableEntry<Field> entry : context.getFieldEntries()) {_111 // 如果已经修改过就跳过_111 if (entry.isChanged()) {_111 continue;_111 }_111 final Field field = entry.getElement();_111 final MergedAnnotation annotation = entry.getAnnotation();_111 // 获取 @Autowired 注解_111 Autowired autowired = annotation.getAnnotation(Autowired.class);_111 // 获取字段的描述信息,主要是用于获取 WriteMethod 也就是 Setter_111 PropertyDescriptor propertyDescriptor = BeanUtil.getPropertyDescriptor(_111 context.getType(),_111 field.getName()_111 );_111 // 看看有没有 Setter 方法_111 Method writeMethod = propertyDescriptor == null_111 ? null_111 : propertyDescriptor.getWriteMethod();_111 if (autowired == null) {_111 // 没有 @Autowired 同时也没有 Setter 方法那还注入个鬼,直接跳过_111 if (writeMethod == null) {_111 continue;_111 }_111 // 利用 DataBinder 获取依赖_111 Object dependency = context_111 .getBinder()_111 .getObject(_111 field.getName(),_111 TypeWrapper.forField(field),_111 annotation,_111 container_111 );_111 // 如果获取不到则看看字段是不是设置了值,如果设置了则取出_111 if (dependency == null) {_111 dependency = ReflectUtil.getFieldValue(instance, field);_111 }_111 // 将值通过 Setter 方法注入_111 ReflectUtil.invoke(instance, writeMethod, dependency);_111 } else {_111 // 有 @Autowired 注解_111 Object dependency;_111 String name = autowired.name();_111 Class<?> type = autowired.type();_111 if (!"".equals(name)) {_111 // @Autowired 注解设置了要注入的依赖名称,则直接使用这个名称的实例注入_111 dependency = container.make(name, field.getType());_111 } else {_111 TypeWrapper<?> typeWrapper;_111 // 取得要注入的依赖类型,如果 @Autowired 里没设置则默认使用字段的类型_111 // 同时也查看 @Autowired 的 proxyType,如果为 UNSET 则遵循 useProxy 设置_111 // 否则就按照 @Autowired 的设置_111 if (type == Class.class) {_111 typeWrapper =_111 TypeWrapper.forField(field, autowired.proxyType());_111 } else {_111 typeWrapper =_111 TypeWrapper.forClass(type, autowired.proxyType());_111 }_111 // 利用 DataBinder 获取依赖_111 dependency =_111 context_111 .getBinder()_111 .getObject(_111 field.getName(),_111 typeWrapper,_111 annotation,_111 container_111 );_111 }_111 // 如果获取不到则看看字段是不是设置了值,如果设置了则取出_111 if (dependency == null) {_111 dependency = ReflectUtil.getFieldValue(instance, field);_111 }_111 // 如果必须注入,但是为 null,则抛出错误_111 if (dependency == null && autowired.required()) {_111 final NullPointerException exception = new NullPointerException(_111 "Target [" +_111 context.getType().getName() +_111 "::" +_111 field.getName() +_111 "] is required, but inject value is null"_111 );_111 log.error(_111 "Target [{}::{}] is required, but inject value is null",_111 context.getType().getName(),_111 field.getName()_111 );_111 throw exception;_111 }_111 if (writeMethod == null) {_111 // 如果没有 Setter 方法则直接用反射写入_111 // 需要注意,只有标记了 @Autowired 的字段才可以使用这种注入方式_111 ReflectUtil.setFieldValue(instance, field, dependency);_111 } else {_111 // 如果有 Setter 则用 Setter 方法进行注入_111 ReflectUtil.invoke(instance, writeMethod, dependency);_111 }_111 }_111 entry.setChanged(true);_111 }_111 return instance;_111 }_111}
PropertiesValueInjector
是用于注入配置文件的注入器:
注入规则:
- 字段标记了
@Value
注解。使用@Value
注解注入,需要注意注入的 Properties 来源是@ConfigurationProperties
和@PropertySource
的设置,如果没这两个注入则是Environment
,也就是根配置。 - 类上有
@ConfigurationProperties
注解,此时就按字段上的注解或者字段名称来注入。
_156public class PropertiesValueInjector implements InstanceInjector {_156 @Override_156 public Object inject(_156 final Container container,_156 final Object instance,_156 final InjectContext context_156 ) {_156 for (final ChangeableEntry<Field> entry : context.getFieldEntries()) {_156 if (entry.isChanged()) {_156 continue;_156 }_156 final Field field = entry.getElement();_156 final MergedAnnotation fieldAnnotation = entry.getAnnotation();_156 // 看看类上有没有 @ConfigurationProperties 注解_156 final boolean hasConfig = context_156 .getAnnotation()_156 .hasAnnotation(ConfigurationProperties.class);_156 // 看看字段上有没有标记 @Value 注解_156 final boolean hasValue = fieldAnnotation.hasAnnotation(Value.class);_156 // 不存在 @Value 或者 @Configuration 注解的时候则无需注入_156 if (!hasConfig && !hasValue) {_156 continue;_156 }_156 // 获取 @PropertyValue 注解_156 final PropertyValue propertyValue = fieldAnnotation.getAnnotation(_156 PropertyValue.class_156 );_156 // 手动配置跳过_156 if (propertyValue != null && propertyValue.skip()) {_156 continue;_156 }_156 // 同样获取 Setter 方法_156 final PropertyDescriptor propertyDescriptor = BeanUtil.getPropertyDescriptor(_156 context.getType(),_156 field.getName()_156 );_156 final Method writeMethod = propertyDescriptor == null_156 ? null_156 : propertyDescriptor.getWriteMethod();_156 final ClassProperty property = new ClassProperty(_156 instance,_156 context.getType(),_156 field,_156 field.getName(),_156 context.getAnnotation(),_156 fieldAnnotation_156 );_156 // 获取依赖_156 final Object value =_156 this.resolveValue(_156 property,_156 context.getData(PropertiesProcessor.PROPERTIES),_156 context.getData(PropertiesProcessor.PROPERTIES_PREFIX),_156 container_156 );_156 // 有 Write 方法就使用 Write 方法_156 if (writeMethod != null) {_156 ReflectUtil.invoke(instance, writeMethod, value);_156 } else {_156 ReflectUtil.setFieldValue(instance, field, value);_156 }_156 entry.setChanged(true);_156 }_156 return instance;_156 }_156_156 private Object resolveValue(_156 final ClassProperty property,_156 CompositePropertySource compositePropertySource,_156 String prefix,_156 final Container container_156 ) {_156 final MergedAnnotation classAnnotation = property.getClassAnnotation();_156 final ConfigurationProperties configurationProperties = classAnnotation.getAnnotation(_156 ConfigurationProperties.class_156 );_156 final String propertyName = property.getPropertyName();_156 Object value =_156 this.getValue(property, compositePropertySource, prefix, container);_156 if (_156 value == null &&_156 !(_156 configurationProperties == null ||_156 configurationProperties.ignoreUnknownFields()_156 )_156 ) {_156 final NullPointerException exception = new NullPointerException(_156 "Unknown property [" + prefix + "." + propertyName + "]"_156 );_156 log.error("Unknown property [{}.{}]", prefix, propertyName);_156 throw exception;_156 }_156 try {_156 value = Convert.convert(property.getPropertyType(), value);_156 } catch (final UtilException e) {_156 if (_156 !(_156 configurationProperties == null ||_156 configurationProperties.ignoreInvalidFields()_156 )_156 ) {_156 final RuntimeException exception = new RuntimeException(_156 "Invalid property [" + prefix + "." + propertyName + "]",_156 e_156 );_156 log.error("Invalid property [{}.{}]", prefix, propertyName);_156 throw exception;_156 }_156 value = ClassUtil.getDefaultValue(property.getPropertyType());_156 }_156 return value;_156 }_156_156 private Object getValue(_156 final ClassProperty property,_156 final CompositePropertySource properties,_156 final String prefix,_156 final Container container_156 ) {_156 final MergedAnnotation propertyAnnotation = property.getPropertyAnnotation();_156 // 有 @Value 就优先使用_156 final Value value = propertyAnnotation.getAnnotation(Value.class);_156 if (value != null) {_156 // 解析表达式_156 return this.resolveExpression(_156 value,_156 property.getPropertyType(),_156 properties,_156 prefix,_156 container_156 );_156 }_156 final PropertyValue propertyValue = propertyAnnotation.getAnnotation(_156 PropertyValue.class_156 );_156 // 有 @PropertyValue 则用 @PropertyValue 里的设置_156 if (propertyValue != null) {_156 // 用 @PropertyValue 里的设置取得注解_156 return this.resolvePropertyValue(_156 propertyValue,_156 properties,_156 prefix,_156 container,_156 property_156 );_156 }_156 // 如果没有这些注解就默认使用字段名进行注入_156 // 字段名会自动进行格式匹配,如大驼峰小驼峰的转换等等_156 Object result = caseGet(property.getPropertyName(), properties::get);_156 if (result == null && prefix != null && !prefix.isEmpty()) {_156 result =_156 caseGet(prefix + property.getPropertyName(), properties::get);_156 }_156 return result;_156 }_156}
然后就是 DefaultMethodInjector 了,这个是用于注入标记了 @Autowired
注解的方法:
_15public class DefaultMethodInjector implements InstanceInjector {_15 @Override_15 public Object inject(_15 final Container container,_15 final Object instance,_15 final InjectContext context_15 ) {_15 final List<Method> methods = context.getBinding().getAutowiredMethods();_15 for (final Method method : methods) {_15 // Set 注入_15 container.call(instance, method, Object.class, context.getBinder());_15 }_15 return instance;_15 }_15}
BeanProcessor
BeanProcessor
是在实例在构建前、构建后、销毁时进行一些额外操作的处理器,有以下 3 种处理器:
- BeforeInjectProcessor:在实例进行构建和注入前进行一些操作,比如
PropertiesProcessor
提前进行一些数据收集。 - BeanAfterCreateProcessor:在实例构建后进行一些操作,如创建 Aop 代理,调用 PostConstruct 方法等。
- BeanDestroyProcessor:在实例销毁时进行一些操作,如调用 PreDestroy 方法。
这部分因为功能需求不高就几个实现类,这里就拿 AopBeanProcessor
来举个例子吧:
_48public class AopBeanProcessor implements BeanAfterCreateProcessor {_48_48 @Override_48 public Object process(_48 final Container container,_48 final Object instance,_48 final InjectContext context,_48 final ConstructorContext constructor_48 ) {_48 final Class<?> instanceType = context.getType();_48 // 如果实例符合 Aop 代理需求_48 if (this.aspectMatches(instanceType, container)) {_48 // 则返回代理过的实例_48 return ProxyCreator.createAop(_48 container.make(AspectManager.class),_48 instance,_48 instanceType,_48 instanceType.getInterfaces(),_48 constructor.getConstructor().getParameterTypes(),_48 constructor.getArgs()_48 );_48 } else {_48 // 否则就原路返回_48 return instance;_48 }_48 }_48_48 protected boolean aspectMatches(_48 final Class<?> type,_48 final Container container_48 ) {_48 // Disable proxy Advice and AspectManager_48 if (_48 Advice.class.isAssignableFrom(type) || type == AspectManager.class_48 ) {_48 return false;_48 }_48 // Disable some bootstrap_48 if (ClassUtils.isSkipBuildType(type)) {_48 return false;_48 }_48 final AspectManager aspectManager = container.make(AspectManager.class);_48 if (aspectManager == null) {_48 return false;_48 }_48 return aspectManager.matches(type);_48 }_48}
Container
接下来就到了最重要的 IoC 容器部分了,有了上面的准备,容器就可以很方便的进行编写了:
_712public class Container {_712 public Container() {_712 // 构造时设置默认的 DataBinder_712 this.dataBinder.set(new DefaultDataBinder(new ConcurrentHashMap<>()));_712 log.info("Container created");_712 }_712_712 /**_712 * 销毁方法_712 */_712 public void destroy() {_712 synchronized (this.contexts) {_712 // 销毁时就取出所有的 Context,然后依次销毁_712 for (String scopeType : new ArrayList<>(this.contexts.keySet())) {_712 this.removeContext(scopeType);_712 }_712 log.info("Container destroyed");_712 }_712 }_712_712 /* ===================== Context ===================== */_712_712 public void registerContext(String scopeType, final Context context) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container registered context: {}", scopeType);_712 }_712 synchronized (this.contexts) {_712 // 注册 Context 就直接放到 contexts 就可以了_712 this.contexts.put(scopeType, context);_712 }_712 }_712_712 public void removeContext(final String scopeType) {_712 synchronized (this.contexts) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container remove context: {}", scopeType);_712 }_712 final Context context = this.contexts.get(scopeType);_712 // 删除前检查 Context 是否启动,如果未启动就直接删掉_712 if (context.isCreated()) {_712 // 如果已经启动则清除对应作用域的 Binding,同时调用 BeanDestroyProcessor_712 for (final Entry<String, Binding> entry : this.bindings.entrySet()) {_712 if (entry.getValue().getScope().equals(scopeType)) {_712 this.doRemove(entry.getKey());_712 }_712 }_712 }_712 this.contexts.remove(scopeType);_712 }_712 }_712_712 public Context getContextByScope(final String scopeType) {_712 synchronized (this.contexts) {_712 // 获取对应作用域名称的 Context_712 return this.contexts.get(scopeType);_712 }_712 }_712_712 /* ===================== Binding ===================== */_712_712 protected Binding newBinding(_712 final String name,_712 final Class<?> instanceType,_712 final String scopeType_712 ) {_712 return new Binding(_712 this.getContextByScope(scopeType),_712 name,_712 instanceType,_712 scopeType_712 );_712 }_712_712 protected Binding newBinding(_712 final String name,_712 final Object instance,_712 final String scopeType_712 ) {_712 return new Binding(_712 this.getContextByScope(scopeType),_712 name,_712 instance,_712 scopeType_712 );_712 }_712_712 protected Binding newBinding(_712 final String name,_712 final FactoryBean<?> factoryBean,_712 final String scopeType_712 ) {_712 return new Binding(_712 this.getContextByScope(scopeType),_712 name,_712 factoryBean,_712 scopeType_712 );_712 }_712_712 public Binding getBinding(final Class<?> type) {_712 // 如果是通过类型的,则需要通过类型找到最符合的名称,然后通过名称查找_712 return this.getBinding(this.getBeanNameByType(type));_712 }_712_712 public Binding getBinding(String name) {_712 // 如果时通过名称取得 Binding 只需要通过取得最终的名称(通过别名或最终名称寻找)_712 // 然后从 bindings 取出就可以了_712 return this.bindings.get(this.getCanonicalName(name));_712 }_712_712 public void setBinding(String name, final Binding binding) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container set binding: {}", name);_712 }_712 synchronized (this.bindings) {_712 // 设置的时候由于有可能是重复设置,所以也要取得最终名称_712 name = this.getCanonicalName(name);_712 // 设置到 bindings_712 this.bindings.put(name, binding);_712 Class<?> clazz = binding.getType();_712 // 然后遍历类型,将类型设置到 bindingNamesByType_712 while (clazz != null && !ClassUtils.isSkipBuildType(clazz)) {_712 this.addType(name, clazz, binding.isPrimary());_712 for (final Class<?> in : clazz.getInterfaces()) {_712 this.addType(name, in, binding.isPrimary());_712 }_712 clazz = clazz.getSuperclass();_712 }_712 }_712 }_712_712 protected void validHas(final String name, final String message) {_712 synchronized (this.bindings) {_712 // 如果名称冲突了,那就抛出异常_712 if (this.has(name)) {_712 throw new IllegalStateException(String.format(message, name));_712 }_712 }_712 }_712_712 public void removeBinding(String name) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container remove binding: {}", name);_712 }_712 synchronized (this.bindings) {_712 name = this.getCanonicalName(name);_712 final Binding binding = this.bindings.get(name);_712 if (binding == null) {_712 return;_712 }_712 // 删除的时候也要递归的删除 bindingNamesByType 里对应的名称_712 Class<?> clazz = binding.getType();_712 while (clazz != null && !ClassUtils.isSkipBuildType(clazz)) {_712 this.removeType(name, clazz);_712 for (final Class<?> in : clazz.getInterfaces()) {_712 this.removeType(name, in);_712 }_712 clazz = clazz.getSuperclass();_712 }_712 this.removeAlias(name);_712 this.bindings.remove(name);_712 }_712 }_712_712 private void addType(_712 final String name,_712 final Class<?> type,_712 final boolean isPrimary_712 ) {_712 this.bindingNamesByType.compute(_712 type,_712 (t, o) -> {_712 if (o != null) {_712 if (isPrimary) {_712 o.add(0, name);_712 } else {_712 o.add(name);_712 }_712 return o;_712 } else {_712 final List<String> list = new CopyOnWriteArrayList<>();_712 list.add(name);_712 return list;_712 }_712 }_712 );_712 }_712_712 private void removeType(final String name, final Class<?> type) {_712 this.bindingNamesByType.computeIfPresent(_712 type,_712 (k, v) -> {_712 v.remove(name);_712 return v;_712 }_712 );_712 }_712_712 public String getBeanNameByType(final Class<?> type) {_712 // 取得对应类型的名称列表_712 List<String> list = this.bindingNamesByType.get(type);_712 if (list == null || list.isEmpty()) {_712 // 未找到或空则使用短类名作为名称_712 return this.typeToBeanName(type);_712 }_712 // 否则取第一个返回_712 return list.get(0);_712 }_712_712 public String typeToBeanName(final Class<?> type) {_712 // 简单来说就是取类名,如果不是前两个字母都大写,则将类名的首字母变成小写_712 final String name = type.getSimpleName();_712 if (name.length() == 0) {_712 return name;_712 }_712 if (_712 name.length() > 1 &&_712 Character.isUpperCase(name.charAt(1)) &&_712 Character.isUpperCase(name.charAt(0))_712 ) {_712 return name;_712 }_712 final char[] chars = name.toCharArray();_712 chars[0] = Character.toLowerCase(chars[0]);_712 return new String(chars);_712 }_712_712 /* ======================= Bean ======================= */_712_712 public List<String> getBeanNamesForType(final Class<?> type) {_712 // 通过类型取得名称列表_712 return this.bindingNamesByType.get(type);_712 }_712_712 public <T> Map<String, T> getBeanOfType(final Class<T> type) {_712 // 通过类型取得名称和实例的 Map_712 final List<String> list = this.getBeanNamesForType(type);_712 if (list == null || list.isEmpty()) {_712 return Collections.emptyMap();_712 }_712 return list_712 .stream()_712 .collect(_712 Collectors.toMap(name -> name, name -> this.make(name, type))_712 );_712 }_712_712 public List<String> getBeanNamesForAnnotation(_712 final Class<? extends Annotation> annotationType_712 ) {_712 // 通过注解取得名称_712 final List<String> list = new ArrayList<>();_712 for (final Entry<String, Binding> entry : this.bindings.entrySet()) {_712 final Class<?> type = entry.getValue().getType();_712 if (_712 type.isInterface() ||_712 type.isEnum() ||_712 type.isAnnotation() ||_712 type.isPrimitive() ||_712 type.isArray() ||_712 entry.getValue().getAnnotation().notAnnotation(annotationType)_712 ) {_712 continue;_712 }_712 list.add(entry.getKey());_712 }_712 return list;_712 }_712_712 public Map<String, Object> getBeansWithAnnotation(_712 final Class<? extends Annotation> annotationType_712 ) {_712 // 通过注解取得名称和实例的 Map_712 final List<String> list =_712 this.getBeanNamesForAnnotation(annotationType);_712 if (list.isEmpty()) {_712 return Collections.emptyMap();_712 }_712 final Map<String, Object> beans = new HashMap<>(list.size());_712 for (final String name : list) {_712 beans.put(name, this.make(name, Object.class));_712 }_712 return beans;_712 }_712_712 /* ===================== Alias ===================== */_712_712 private String getCanonicalName(final String name) {_712 // 取得实际名称_712 // 别名只支持一层_712 final String resolve = this.getAlias(name);_712 if (resolve == null) {_712 return name;_712 }_712 return resolve;_712 }_712_712 public void setAlias(final String alias, final String name) {_712 if (alias == null || alias.equals(name)) {_712 return;_712 }_712 if (log.isDebugEnabled()) {_712 log.debug("Container add alias: {} => {}", alias, name);_712 }_712 // 二元操作,由于验证包含 alias 和 bindings,并发工具只能保护一个,所以要加锁_712 synchronized (this.bindings) {_712 this.validHas(alias, "Alias [%s] has contains");_712 this.aliases.put(alias, name);_712 }_712 }_712_712 public void removeAlias(final String alias) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container remove alias: {}", alias);_712 }_712 synchronized (this.bindings) {_712 this.aliases.remove(alias);_712 }_712 }_712_712 public boolean hasAlias(final String alias) {_712 return this.getAlias(alias) != null;_712 }_712_712 public String getAlias(final String alias) {_712 return this.aliases.get(alias);_712 }_712_712 /* ===================== Process ===================== */_712_712 protected InjectContext processBeforeInject(final Binding binding) {_712 // 调用 BeforeInjectProcessor 进行前置处理_712 final InjectContext context = new InjectContext(_712 binding,_712 this.dataBinder.get()_712 );_712 for (final BeforeInjectProcessor processor : this.beforeInjectProcessors) {_712 processor.process(this, context);_712 }_712 return context;_712 }_712_712 protected Object processInstanceInjector(_712 final InjectContext context,_712 Object instance_712 ) {_712 // 调用 InstanceInjector 进行实例注入_712 for (final InstanceInjector injector : this.instanceInjectors) {_712 instance = injector.process(this, instance, context);_712 }_712 return instance;_712 }_712_712 protected Object[] processParameterInjector(_712 final InjectContext context,_712 Executable method_712 ) {_712 // 调用 ParameterInjector 进行参数注入_712 Object[] dependencies = new Object[method.getParameterCount()];_712 method = ClassUtils.getUserMethod(method);_712 final ParameterContext parameterContext = new ParameterContext(_712 context,_712 method_712 );_712 for (final ParameterInjector injector : this.parameterInjectors) {_712 dependencies =_712 injector.process(this, dependencies, parameterContext);_712 }_712 return dependencies;_712 }_712_712 protected Object processBeanAfterCreate(_712 final InjectContext context,_712 Object instance,_712 final Constructor<?> constructor,_712 final Object[] args_712 ) {_712 // 调用 BeanAfterCreateProcessor 进行构建后处理_712 final ConstructorContext constructorContext = new ConstructorContext(_712 constructor,_712 args_712 );_712 for (final BeanAfterCreateProcessor processor : this.beanAfterCreateProcessors) {_712 instance =_712 processor.process(this, instance, context, constructorContext);_712 }_712 return instance;_712 }_712_712 protected void processBeanDestroy(_712 final Binding binding,_712 final Object instance_712 ) {_712 // 调用 BeanDestroyProcessor 进行销毁时处理_712 final InjectContext context = new InjectContext(_712 binding,_712 this.dataBinder.get()_712 );_712 for (final BeanDestroyProcessor processor : this.beanDestroyProcessors) {_712 processor.process(this, instance, context);_712 }_712 }_712_712 /* ===================== doBind ===================== */_712_712 protected Binding doBind(final String name, final Binding binding) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container bind: {} - {}", binding.getScope(), name);_712 }_712 // doBind 其实是个空壳方法,具体的逻辑在 setBinding_712 this.setBinding(name, binding);_712 return binding;_712 }_712_712 protected Binding doBind(_712 final String name,_712 final FactoryBean<?> factoryBean,_712 final String scopeType_712 ) {_712 synchronized (this.bindings) {_712 this.validHas(name, "Target [%s] has been bind");_712 final Binding binding =_712 this.newBinding(name, factoryBean, scopeType);_712 return this.doBind(name, binding);_712 }_712 }_712_712 protected Binding doBind(_712 final String name,_712 final Class<?> instanceType,_712 final String scopeType_712 ) {_712 synchronized (this.bindings) {_712 this.validHas(name, "Target [%s] has been bind");_712 final Binding binding =_712 this.newBinding(name, instanceType, scopeType);_712 return this.doBind(name, binding);_712 }_712 }_712_712 protected Binding doBind(_712 final String name,_712 final Object instance,_712 final String scopeType_712 ) {_712 synchronized (this.bindings) {_712 this.validHas(name, "Target [%s] has been bind");_712 final Binding binding = this.newBinding(name, instance, scopeType);_712 return this.doBind(name, binding);_712 }_712 }_712_712 /* ===================== doBuild ===================== */_712_712 protected Object doBuild(final Binding binding) {_712 // doBuild 负责构建实例,并不参与容器的管理,所以如果调用 doBuild 创建两次单例,则这两次创建的实例不会是一样的_712 final Class<?> instanceType = binding.getType();_712 // 没有类型就没法构建_712 if (instanceType == null) {_712 return null;_712 }_712 if (log.isDebugEnabled()) {_712 log.debug("Container build: {}", instanceType);_712 }_712 // 取得早期引用,用于解决循环依赖的问题_712 Map<String, Object> earlyBeans = this.earlyBeans.get();_712 // 如果早期引用里存在需要的实例说明发生了循环依赖的问题,此时就取出返回_712 if (earlyBeans != null && earlyBeans.containsKey(binding.getName())) {_712 return earlyBeans.get(binding.getName());_712 }_712 // 取出构造器,并进行排序,使最优的构造器能优先构造,失败了才会用其他的构造器_712 final Constructor<?>[] constructors = ReflectUtils.sortConstructors(_712 instanceType.getDeclaredConstructors()_712 );_712 Object instance;_712 // 构造过程中发生的错误_712 final List<Exception> errors = new ArrayList<>();_712 for (final Constructor<?> constructor : constructors) {_712 // 构造器有可能是私有的,要先改权限_712 constructor.setAccessible(true);_712 // 前置处理_712 final InjectContext context = this.processBeforeInject(binding);_712 // 注入参数_712 final Object[] dependencies =_712 this.processParameterInjector(context, constructor);_712 try {_712 // 实例化_712 instance = constructor.newInstance(dependencies);_712 } catch (final Exception e) {_712 errors.add(e);_712 // 如果失败了就尝试使用下一个构造器_712 continue;_712 }_712 // 在进行下一步处理的时候先将自己存入早期引用,避免循环依赖问题_712 boolean createEarlyMap = false;_712 earlyBeans = this.earlyBeans.get();_712 if (earlyBeans == null) {_712 earlyBeans = new HashMap<>();_712 earlyBeans.put(binding.getName(), instance);_712 this.earlyBeans.set(earlyBeans);_712 createEarlyMap = true;_712 }_712 try {_712 // 实例注入_712 instance = this.processInstanceInjector(context, instance);_712 // 后置处理_712 instance =_712 this.processBeanAfterCreate(_712 context,_712 instance,_712 constructor,_712 dependencies_712 );_712 } finally {_712 // 最终都要清理早期引用_712 if (createEarlyMap) {_712 this.earlyBeans.remove();_712 }_712 }_712 // 如果构建成功了就不是 null,此时就可以返回了_712 if (instance != null) {_712 return instance;_712 }_712 }_712 // 当所有的构造器都尝试了,还是无法构建成功,则打印所有的错误_712 log.error(_712 "Build instance failed, use default value, Type: {}",_712 instanceType_712 );_712 for (final Exception error : errors) {_712 log.error("Build instance failed error", error);_712 }_712 // 同时返回对应类型的默认值_712 return ClassUtil.getDefaultValue(instanceType);_712 }_712_712 /* ===================== doMake ===================== */_712_712 protected <T> T doResolveType(_712 String name,_712 Class<T> returnType,_712 TypeWrapper<T> typeWrapper_712 ) {_712 if (returnType.isArray()) {_712 // 注入类型为数组,则只需要使用 ComponentType 取出对应类型的所有实例就可以了_712 return Convert.convert(_712 returnType,_712 this.getBeanOfType(returnType.getComponentType()).values()_712 );_712 } else if (_712 Collection.class.isAssignableFrom(returnType) &&_712 returnType.isInterface()_712 ) {_712 // 注入集合,此时就要依靠 TypeWrapper 传入的泛型 信息_712 final Class<?> componentType = typeWrapper.getGeneric(0);_712 // 如果泛型类没有传进来,则无法注入,直接返回 null_712 if (componentType == null) {_712 return null;_712 }_712 // 否则就按照 ComponentType 取出对应类型的所有实例就可以了_712 // 比如 List<User> 那么 getGeneric(0) 就是 User,也就是 ComponentType_712 return Convert.convert(_712 returnType,_712 this.getBeanOfType(componentType).values()_712 );_712 } else if (Map.class == returnType) {_712 // Map 类型也是类似的,不过只支持 Map<String, T> 这样的类型_712 Class<?> keyType = typeWrapper.getGeneric(0);_712 if (String.class != keyType) {_712 return null;_712 }_712 Class<?> valueType = typeWrapper.getGeneric(1);_712 if (valueType == null) {_712 return null;_712 }_712 return Convert.convert(_712 returnType,_712 this.getBeanOfType(valueType).values()_712 );_712 } else if (ObjectFactory.class == returnType) {_712 // 还有 ObjectFactory,需要注意 ObjectFactory 带有 LazyLoad 效果_712 final Class<?> componentType = typeWrapper.getGeneric(0);_712 if (componentType == null) {_712 return null;_712 }_712 return Convert.convert(_712 returnType,_712 (ObjectFactory<Object>) () -> make(name, componentType)_712 );_712 } else if (ObjectProvider.class == returnType) {_712 // ObjectFactory 的高级版一样的操作_712 final Class<?> componentType = typeWrapper.getGeneric(0);_712 if (componentType == null) {_712 return null;_712 }_712 return Convert.convert(_712 returnType,_712 new ObjectProvider<>() {_712 @Override_712 @SuppressWarnings("unchecked")_712 public Collection<Object> getObjects() {_712 return (Collection<Object>) getBeanOfType(componentType)_712 .values();_712 }_712_712 @Override_712 public Object getObject() {_712 return make(name, componentType);_712 }_712 }_712 );_712 }_712 return null;_712 }_712_712 protected <T> T doMake(final String name, final Class<T> returnType) {_712 return this.doMake(name, TypeWrapper.forClass(returnType));_712 }_712_712 @SuppressWarnings("unchecked")_712 protected <T> T doMake(_712 final String name,_712 final TypeWrapper<T> typeWrapper_712 ) {_712 // 获取依赖(依赖查找)_712 Class<T> returnType = typeWrapper.getClazz();_712 if (log.isDebugEnabled()) {_712 log.debug("Container make: {} - {}", name, returnType);_712 }_712 // 首先取得 Binding_712 Binding binding = name == null ? null : this.getBinding(name);_712 // Binding 未找到_712 if (binding == null) {_712 // 有可能是复合类型,则尝试获取_712 final T resolved =_712 this.doResolveType(name, returnType, typeWrapper);_712 if (resolved != null) {_712 return resolved;_712 }_712 // 如果没有就尝试通过类型取得 Binding_712 if (ClassUtils.isSkipBuildType(returnType)) {_712 return (T) ClassUtil.getDefaultValue(returnType);_712 } else {_712 binding = this.getBinding(this.getBeanNameByType(returnType));_712 }_712 }_712 if (binding == null) {_712 // 如果都没找到就新建 Binding, 不过这个 Binding 不会存入 IoC 容器,是临时的_712 binding = this.newBinding(name, returnType, ScopeType.PROTOTYPE);_712 }_712 // 是否需要代理,比如 Field 是需要代理的_712 boolean proxy = typeWrapper.useProxy();_712 // 取得对应的实例_712 Object instance = binding.getSource(proxy);_712 if (instance != null) {_712 return Convert.convert(returnType, instance);_712 }_712 // 加锁,双重检查,防止二次初始化_712 synchronized (binding.getMutex()) {_712 instance = binding.getSource(proxy);_712 if (instance != null) {_712 return Convert.convert(returnType, instance);_712 }_712 // 如果还是没取得实例,说明实例并未构建,此时就进入构建流程_712 Binding finalBinding = binding;_712 try {_712 // 取出 FactoryBean,如果没有就使用默认的 FactoryBean,也就是 doBuild_712 FactoryBean<?> factoryBean = binding.getFactoryBean();_712 if (factoryBean == null) {_712 factoryBean =_712 new FactoryBean<>() {_712 @Override_712 public Object getObject() {_712 return doBuild(finalBinding);_712 }_712_712 @Override_712 public Class<?> getObjectType() {_712 return finalBinding.getType();_712 }_712 };_712 }_712 instance = factoryBean.getObject();_712 } catch (final Throwable e) {_712 throw new ContainerException("Instance make failed", e);_712 }_712 T returnInstance = Convert.convert(returnType, instance);_712 // 如果是共享的,也就是单例,则将单例设置到 Context 里_712 if (binding.isShared()) {_712 binding.setSource(returnInstance);_712 }_712 return returnInstance;_712 }_712 }_712_712 /* ===================== doRemove ===================== */_712_712 protected void doRemove(final String name) {_712 if (log.isDebugEnabled()) {_712 log.debug("Container remove: {}", name);_712 }_712 synchronized (this.bindings) {_712 final Binding binding = this.getBinding(name);_712 // 删除就看看实例构建了吗,如果构建了就调用 BeanDestroyProcessor 进行销毁时处理_712 if (binding.isCreated()) {_712 this.processBeanDestroy(binding, binding.getSource());_712 }_712 // 然后删除 Binding_712 this.removeBinding(name);_712 }_712 }_712}
Container
里较为重要的方法都已经通过注解说清楚了。不过有些不重要的部分这里就不贴了,主要是代码太长了 2333。
结语
到这里 XK-Java 的 IoC 容器部分就写完了。
文章十几天了终于肝完了,主要也是内容比较多,也相对复杂,和上次的 XK-PHP 相比简直是小巫见大巫。所以文中可能会有错误,同时毕竟我也不是什么业界大佬,没有丰富的经验,代码里可能有挺多错误,如果你发现了错误可以在底下评论。溜了溜了 🤣。
从零实现一个 Java 微框架 - IoC
https://blog.ixk.me/post/implement-a-java-microframework-from-zero-2许可协议
发布于
2021-04-11
本文作者
Otstar Lin
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!