TheRouter 的跨模块依赖注入实现原理

简介: `TheRouter`用于跨模块通信设计的`ServiceProvider`,核心设计思想是参考了SOA(面向服务架构)的设计方式。

TheRouter用于跨模块通信设计的ServiceProvider,核心设计思想是参考了SOA(面向服务架构)的设计方式。

具体到 Android 侧就是 AIDL 类似的实现。

模块化能力支持项:

  • 支持跨模块依赖注入
  • 支持自定义注入项的创建规则,依赖注入可自定义参数
  • 支持自定义服务拦截,单模块mock调试
  • 支持注入对象缓存,多次注入 只会new一次对象

1.0 依赖注入

用于跨模块通信使用,核心设计思想是参考了SOA(面向服务架构) 的设计方式。
具体到 Android 侧就是 AIDL 类似的实现:
例如当前有两个模块:A订单模块、B登录模块,下单需要获取用户信息。
这个业务场景就是,A需要使用获取用户信息的服务,B需要向外提供一个获取用户信息的服务。

XrJc0f.jpg

1.1 声明接口服务

首先声明一个接口,放入公共依赖层

// 假设当前有一个用户信息获取服务
public interface IUserService {
    String getUserInfo();
}

1.2 服务使用方

也就是上面例子的 A订单模块,他需要使用获取用户信息的服务
A无需关心,IUserService这个接口服务是谁提供的,他只需要知道自己需要使用这样的一个服务就行了。
如果没有提供服务的提供方,TheRouter.get()可能返回null

TheRouter.get(IUserService::class.java)?.getUserInfo()

1.3 服务提供方

服务提供方需要声明一个提供服务的方法,用@ServiceProvider注解标记。

  • 如果是 java,必须是 public static 修饰
  • 如果是 kotlin,建议写成 top level 的函数
  • 方法名不限
/**
 * 方法名不限定,任意名字都行
 * 返回值必须是服务接口名,如果是实现了服务的子类,需要加上returnType限定(例如下面代码)
 * 方法必须加上 public static 修饰,否则编译期就会报错
 */
@ServiceProvider
public static IUserService test() {
    return new IUserService() {
        @Override
        public String getUserInfo() {
            return "返回用户信息";
        }
    };
}

// 也可以直接返回对象,然后标注这个方法的服名是什么
@ServiceProvider(returnType = IUserService.class)
public static UserServiceImpl test() {
    xxx
}

2.0 自定义服务拦截器

使用场景:单模块调试时,可能会有需要 mock 其他模块提供的服务,TheRouter 允许自定义其他模块的实现。

Interceptor interceptor = new Interceptor() {
    @Override
    public <T> T interception(Class<T> clazz, Object... params) {
        if (clazz == IUserService.class) {
            return new IUserService();
        }
        return null;
    }
};
TheRouter.getRouterInject().addInterceptor(interceptor);

3.0 服务缓存

服务提供方运行对提供的服务做配置,对于无状态的服务,尽可能使用缓存方式减少对象创建次数,而有状态的服务,则每次创建新对象保证多次调用有不会互相污染状态(例如订单状态管理、商品销售状态等服务)。

声明服务缓存只需要在 @ServiceProvider的方法上新增额外注解即可,例如下面示例代码:

  • Singleton 表示这个对象会被永久缓存,对外部调用方而言相当于这个对象声明成了单例
  • NewInstance 表示每次都会返回新对象

如果两个注解同时被添加,则只有Singleton会生效。


// 注:如果都不加,默认是LRU+软引用缓存
// 如果两个注解同时被添加,则只有Singleton会生效。
@Singleton // 对外部调用方而言相当于这个对象声明成了单例
@NewInstance  // 每次都会返回新对象
public interface IUserService {
    public String getUserInfo();
}


@ServiceProvider
public static IUserService test() {
    return new IUserService() {
        @Override
        public String getUserInfo() {
            return "返回用户信息";
        }
    };
}
目录
相关文章
|
SQL 关系型数据库 Go
Go语言微服务框架 - 12.ORM层的自动抽象与自定义方法的扩展
随着接口参数校验功能的完善,我们能快速定位到接口层面的参数问题;而应用服务的分层代码,也可以通过log的trace-id发现常见的业务逻辑问题。 但在最底层与数据库的操作,也就是对GORM的使用,经常会因为我们不了解ORM的一些细节,导致对数据的CRUD失败,或者没有达到预期效果。这时,我们希望能在ORM这一层也有一个通用的解决方案,来加速问题的排查。
90 0
|
6月前
|
缓存 监控 安全
AOP则关注如何将那些影响多个类的功能模块化
AOP则关注如何将那些影响多个类的功能模块化
|
7月前
|
安全 Java 程序员
Spring框架的核心特性是什么?
【4月更文挑战第30天】Spring 的特性
415 0
|
4月前
|
设计模式 安全 数据库连接
|
4月前
|
Android开发 开发者
Android项目架构设计问题之使用动态代理来增强 GoodsApi 接口的调用如何解决
Android项目架构设计问题之使用动态代理来增强 GoodsApi 接口的调用如何解决
25 0
|
7月前
|
Java 数据库 Spring
springboot 解耦、隔离、异步的原则以及实战
【5月更文挑战第30天】在Spring Boot中实现解耦、隔离和异步的原则,能够提升应用程序的可维护性、可扩展性和性能。下面我会先介绍这三个原则的基本概念和意义,然后通过实战示例展示如何在Spring Boot应用中应用这些原则。
98 1
|
6月前
|
Go
Gone支持的依赖注入方式
在Go中,依赖注入通过`gone`标签实现,标记有`gone`的结构体字段在Gone启动时接收依赖。支持值类型、指针类型、接口类型、slice及map类型的注入,但值类型不推荐因拷贝导致独立内存。GonerId用于具名注入,允许可选的GonerId在注册时指定,私有属性也可注入以降低耦合。
|
XML Java 数据格式
Spring框架核心功能实现
概要 手写Spring启动以及扫描流程 手写getBean流程 手写Bean生命周期流程 手写依赖注入流程 手写BeanPostProcessor机制 手写Aop机制 Spring启动以及扫描流程实现 我们平时都是使用这两种方法获得spring容器,上面的是通过加载类路径上的配置文件来获得容器。下面的方式和上面的原理相同只不过是通过注解的形式去实现,我们传入的也是一个配置类的class文件,我们可以把这个文件类比成第一种方法中的xml文件,然后这个xml文件里的一个个标签都变成了注解。 基础环境搭建 首先搭建好基础环境: 我们的测试类: public class MySpringT
41 0
|
7月前
|
Java 数据库
java面向对象高级分层实例_数据库操作类
java面向对象高级分层实例_数据库操作类
|
7月前
|
Java Spring 容器
面试题:Spring框架中,一个组件是怎样向自己内部注入组件的
面试题:Spring框架中,一个组件是怎样向自己内部注入组件的
40 0