当前位置: 首页 > news >正文

Solon Ioc 的魔法 - 注解注入器(也可叫虚空注入器)

很多人惊叹于 Solon 的注入能力,一个注解怎可注万物???

一、注解注入器

Solon Ioc 的四大魔法之一:注解注入器(BeanInjector<T extends Annotation>)。在扫描时,Solon 会检查相关组件的字段或者参数,上面有没有注解?如果有注解,有没有对应的注入器注册过?如果有,则执行注入器。

1、什么是注解?

注解一般也叫元数据,是一种代码级别的说明性内容。编译器在编译时,可以借助注解产生很多魔法效果;Solon Ioc 在运行时,也借助注解产生了很多魔法效果。

其中,注解注入器便是 Solon Ioc 的四大魔法之一。

2、注入器接口是怎么样的?
@FunctionalInterface
public interface BeanInjector<T extends Annotation> {void doInject(VarHolder vh, T anno);
}

其中:

  • vh,用于接收变量数据
  • anno,则是申明的注解
3、Solon Ioc 的注入器注册接口
void beanInjectorAdd(Class<T> annoClz, BeanInjector<T> injector);
void beanInjectorAdd(Class<T> annoClz, Class<?> targetClz, BeanInjector<T> injector);

二、为什么也可叫“虚空”注入器?

这个是因为,Solon 的注入是执行一个接口,而不是即定的内容。内容,可以是现成的,也可以是动态构建的。所以很“虚空”。

1、分解内置的的 @Inject 注解实现

@Inject 的简单使用示例

//主入配置
@Component
public class DemoService{@Inject("${track.url}")String trackUrl;@Inject("${track.db1}")HikariDataSource trackDs;
}//注入 bean
@Component
public class DemoService{@Injectprivate static TrackService trackService; @Inject("userService")private UserService userService;
}

注入器的能力实现剖析(简单的示意实现,框架的实现比这个复杂)

context.beanInjectorAdd(Inject.class, (vh, anno) -> {//申明:是否必须要注入?vh.required(anno.required());if (Utils.isEmpty(anno.value)) {//没有值,说明是 bean type 注入vh.content().getBeanAsync(vh.type(), bean->{ //vh.content() 即 context。在“热插拨”时可能会不同vh.setValue(bean);});} else {if(anno.value().startsWith("${")) {//说明是配置注入String val = vh.content().cfg().getByExpr(anno.value());vh.setValue(val);} else {//说明是 bean name 注入vh.content().getBeanAsync(anno.value(), bean->{vh.setValue(bean);});}}
});
2、“类型增强”注入器。魔法的升级!

Solon 内置的注入器,你不喜欢?

想换掉实现行不行?行!完全换掉代码太多,想为特定的类型增加注入行不行?也行!比如,我们设计了一个 EsMapper<T> 用于操作 Elasticsearch。然后可以自由的扩展:

public interface AuthorMapper extends EsMapper<Author> {
}
public interface CommentMapper extends EsMapper<Comment> {
}
public interface ContactMapper extends EsMapper<Contact> {
}
public interface DocumentMapper extends EsMapper<Document> {
}

估计还会想扩展更多的子类?“类型增强” 注入器在手,一切我有

EsMapperFactory  esMapperFactory;context.beanInjectorAdd(Inject.class, EsMapper.class, (vh, anno) -> {EsMapper mapper = esMapperFactory.create(vh.getType());vh.setValue(mapper);
});

可以再借用容器的“缓存”特性,同类型的注入性能就提高了:

EsMapperFactory  esMapperFactory;context.beanInjectorAdd(Inject.class, EsMapper.class, (vh, anno) -> {EsMapper mapper = vh.context().getBean(vh.getType());if (mapper == null) {mapper = esMapperFactory.create(vh.type());vh.context().wrapAndPut(mapper.getClass(), bean); //有可能被代理了,类型与 vh.getType() 不同vh.context().wrapAndPut(vh.getType(), bean);}vh.setValue(mapper);
});

如果有“多源”的概念,我们还可以支持 @Inject("name")

EsMapperFactory  esMapperFactory;context.beanInjectorAdd(Inject.class, EsMapper.class, (vh, anno) -> {EsMapper mapper = null;if (Utils.isEmpty(anno.value)) {//按类型取mapper = vh.context().getBean(vh.getType());} else {//按名字取mapper = vh.context().getBean(anno.value());}if (mapper == null) {mapper = esMapperFactory.create(anno.value(), vh.type());if (Utils.isEmpty(anno.value)) {//按类注型注入;就按类型缓存vh.context().wrapAndPut(mapper.getClass(), bean); //有可能被代理了,类型与 vh.getType() 不同vh.context().wrapAndPut(vh.getType(), bean);} else {//按类名字注入;就按名字缓存vh.context().wrapAndPut(anno.value(), bean);}}vh.setValue(mapper);
});

现在我们可以用了(吃饭喽,下班喽!):

//主入配置
@Component
public class DemoService{@InjectDocumentMapper documentMapper;@Inject("es2")DocumentMapper documentMapper2;
}

http://www.mrgr.cn/news/57930.html

相关文章:

  • 好用的AI工具
  • Bug:通过反射修改@Autowired注入Bean的字段,明确存在,报错 NoSuchFieldException
  • 手机空号过滤接口-在线手机空号检测-手机空号过滤API
  • 【无标题】测试
  • 基于单片机的 OLED 显示终端设计分析与研究
  • C++ set和map的模拟实现
  • 力扣之613.直线上的最近距离
  • 宠物空气净化器怎么买最划算?宠物空气净化器选购经验真实分享!
  • js逆向协议破解滑块验证
  • 【Blender】 学习笔记(一)
  • 笨蛋学习FreeMarker
  • Leecode热题100-416.分割等和子集
  • 6317A可调谐激光源
  • 草地杂草数据集野外草地数据集田间野草数据集YOLO格式VOC格式目标检测计算机视觉数据集
  • 【数据分享】全国各省份资源和环境-废气中主要污染物排放(2011-2021年)
  • AcWing 3534:矩阵幂 ← 矩阵快速幂
  • 中国建设银行广东省分行珠海市分行营业网点装修工程采购项目市场调研供应商征集公告
  • 1024程序员节
  • 二进制安全研究员的成长之路---栈溢出篇(一)
  • 【蓝桥杯选拔赛真题77】python计算小球 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析
  • 时间服务器 NTP协议
  • C++位操作实战:掩码、提取与组装
  • 073_基于springboot+Android的“川味游”app的设计与开发
  • c++学习DAY2
  • Java基于数据库的分布式可重入锁(带等待时间和过期时间)
  • 【Linux】进程调度 | 进程切换上下文数据