首页 > 极客资料 博客日记
Solon Ioc 的魔法之注解注入器(也可叫虚空注入器)
2024-10-25 17:30:04极客资料围观15次
这篇文章介绍了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{
@Inject
private 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{
@Inject
DocumentMapper documentMapper;
@Inject("es2")
DocumentMapper documentMapper2;
}
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- Nuxt.js 应用中的 prerender:routes 事件钩子详解
- 【问题解决】Tomcat由低于8版本升级到高版本使用Tomcat自带连接池报错无法找到表空间的问题
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Vision Kit
- 六、Spring Boot集成Spring Security之前后分离认证流程最佳方案
- 《JVM第7课》堆区
- .NET 8 高性能跨平台图像处理库 ImageSharp
- 还在为慢速数据传输苦恼?Linux 零拷贝技术来帮你!
- 刚毕业,去做边缘业务,还有救吗?
- 如何避免 HttpClient 丢失请求头:通过 HttpRequestMessage 解决并优化
- 让性能提升56%的Vue3.5响应式重构之“版本计数”