首页 > 其他分享 >Solon Ioc 的魔法之注解注入器(也可叫虚空注入器)

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

时间:2024-10-25 17:11:52浏览次数:1  
标签:mapper Solon vh anno Inject context 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;
}

标签:mapper,Solon,vh,anno,Inject,context,Ioc,注入
From: https://www.cnblogs.com/noear/p/18502935

相关文章

  • 08-宽字节注入、GetShell、SQLMap、XSS存储型练习
    1、利用宽字节注入实现“库名-表名”的注入过程,写清楚注入步骤;​ 由于网站的过滤,调用其addslashes()函数在单引号之前添加反斜线\进行转义,我们需要让\无效实现单引号的逃逸。​ 解决方法:因为addslashes()函数使用时会对输入内容进行URL编码(即添加的\也会编码成%5c)在......
  • IOC 启动流程
    初始化12步骤容器创建会进入refresh方法,总共12个步骤//org.springframework.context.support.AbstractApplicationContext#refresh@Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){......
  • 【漏洞复现】灵当CRM getOrderList Sql注入漏洞
    免责声明:        本文旨在提供有关特定漏洞的信息,以帮助用户了解潜在风险。发布此信息旨在促进网络安全意识和技术进步,并非出于恶意。读者应理解,利用本文提到的漏洞或进行相关测试可能违反法律或服务协议。未经授权访问系统、网络或应用程序可能导致法律责任或严......
  • 【漏洞复现】华望云 会议管理平台 confmanger.inc 后台SQL注入漏洞
    免责声明:        本文旨在提供有关特定漏洞的信息,以帮助用户了解潜在风险。发布此信息旨在促进网络安全意识和技术进步,并非出于恶意。读者应理解,利用本文提到的漏洞或进行相关测试可能违反法律或服务协议。未经授权访问系统、网络或应用程序可能导致法律责任或严......
  • Solon 之 STOMP
    一、STOMP简介如果直接使用WebSocket会非常累,就像用Socket编写Web应用。没有高层级的交互协议,就需要我们定义应用间所发消息的语义,还需要确保连接的两端都能遵循这些语义。如HTTP在TCP套接字之上添加了请求-响应模型层一样,STOMP是在WebSocket之上提供了基于帧的线......
  • 对于@Bean注入的新理解
    最近在项目中看到别人的代码是莫名奇妙就有值了,不理解原理,现在已经查明了示例:@ServicepublicclassDefaultChainFactory{privatefinalMap<String,ILogicChain>logicChainGroup;protectedIStrategyRepositoryrepository;publicDefaultChainFactory(......
  • Spring Boot 依赖注入为 null 问题
    目录问题省流代码复现TestServiceTestAspectTestController源码分析AbstractAutoProxyCreatorCglibAopProxyEnhancer问题工作中,在负责的模块里使用@DubboService注解注册了一个dubbo接口,给定时任务模块去调用。在自我调试阶段,需要在本地自己验证一下接口的功......
  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
    文章目录Spring静态注入实际案例Demo为什么这样写有时候RemoteEBRpcInvoker.getEbFormIdUtil是一个NULL???原因1:静态变量初始化顺序问题原因2:Spring生命周期与静态字段解决方案:方法1:移除静态字段(违背了我的初衷)方法2:使用@PostConstruct方法3:使用@Autowire......
  • 众智OA办公系统 Login SQL注入漏洞复现
    0x01产品描述:   ‌众智OA办公系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台。‌它凭借先进的技术和人性化的设计理念,实现了信息的快速传递和自动化处理,帮助企业和机构实现信息化、自动化、智能化和标准化的办公管理‌0x02漏洞描述:   众......
  • MySQL注入load_file常用路径
            在MySQL注入攻击中,攻击者可能会尝试利用LOAD_FILE()函数来读取服务器上的敏感文件。LOAD_FILE()函数允许从服务器的文件系统中读取文件,并将其内容作为字符串返回。然而,这个函数需要满足一定的权限条件,并且文件路径必须是服务器能够访问的。WINDOWS下:c:/boo......