android自定义serviceloader接口隔离及获取自定义properties参数配置

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android自定义serviceloader接口隔离及获取自定义properties参数配置相关的知识,希望对你有一定的参考价值。

参考技术A   之前看过大神的 美团组件化方案 ,其中提到了通过servicelaoder进行解耦的思路,主要是通过配置接口及其实现类的方式坐到接口隔离作用,本文主要是实现此思路并延伸出通过加载自定义properties文件获取参数配置信息

  通过查看ServiceLoader源码可知,ServiceLoader是通过加载META-INF/services/路径下的接口实现类,加载方式是通过读取配置文件并通过反射的方式获取类的实例
1.配置文件读取,获取文件流

其中PREFIX = "META-INF/services/";
由此可见加载路径是META-INF文件夹下面的文件

2.通过流获取实现类全路径

其中parseLine方法里面是做了类全路径名校验

思路:
  1.读取配置文件
  2.获取配置的类全名
  3.通过反射获取类的实例

  我们的配置文件将写在assets文件夹下

  通过查看apk包结构可以发现assets文件夹位置是与META-INF平级的,由此我们可以将系统的ServiceLoader加载文件路径改为assets路径

1.配置文件读取,获取文件流

2.通过流获取接口类与实现类的对应集合
  由于接口类与实现类是一对一关系,所以通过Map以键值对的方式存储接口类与实现类,在系统ServiceLoader做简单修改:

3.获取实现类
  在上一步已经获取了所有接口类和实现类的集合,在此通过接口类全名来获取实现类全名,并通过反射的方式获取实现类实例:

到此我们自定义ServiceLoader已经初步实现,在实际开发中,我们一般只需要一个实例及单利,在此我们可以用Map将类的实例与接口类名绑定起来即可。

使用

  加载properties配置参数的思路与ServiceLoader基本一致,只是获取配置参数可以通过java类Properties获取
1.获取流
  和自定义ServiceLoader获取流一致

2.获取Properties实例

3.获取value

4.使用

1.在查看Iterable 接口时无意中发现了default关键字,经查看资料显示为java8新加的,用于在接口中写默认的方法函数体

有兴趣的可以去 https://github.com/dengzhi00/deployloader 看看

ServiceLoader的使用

ServiceLoader这个类来从配置文件中加载子类或者接口的实现类,主要是从META-INF/services这个目录下的配置文件加载给定接口或者基类的实现,ServiceLoader会根据给定的类的full name来在META-INF/services下面找对应的文件,在这个文件中定义了所有这个类的子类或者接口的实现类,返回一个实例。

技术分享 技术分享

在此文件中定义一个或者多个实现类,如:

1 com.pkuhit.iihip.rce.core.MessageRepositoryImp1
2 com.pkuhit.iihip.rce.core.MessageRepositoryImp2

调用方法:

//need to define related class full name in /META-INF/services/....
ServiceLoader<IService> serviceLoader = ServiceLoader.load(IService.class);
for (IService service : serviceLoader) {
    //循环出来的各个接口实现类
}

工具类例子:

import java.util.Iterator;
import java.util.ServiceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ServiceLoaderUtils
{
    protected static Logger logger = LoggerFactory.getLogger(ServiceLoaderUtils.class);
/**
 * 使用Java标准的ServiceLoader方式加载给定Service的实现。
 * 加载时优先使用系统属性中设定的实现类。如果没有设定,则按照
 * Java标准ServiceLoader加载方式遍历系统中找到的实现,选择
 * 第一个返回。
 * 
 * 系统属性可以通过启动java命令时的-D×××=yyy的方式来设定,也
 * 可以通过编程的方式直接调用System.setProperty来设定。
 * 
 * @param clazz
 * @return
 */
@SuppressWarnings("unchecked")
public static <T> T getService(Class<T> clazz)
{
    String engineClazz = System.getProperty(clazz.getName());
    try
    {
        if(engineClazz != null)
            return (T) Class.forName(engineClazz).newInstance();
    }
    catch (InstantiationException | IllegalAccessException | ClassNotFoundException e)
    {
        throw new RuntimeException(e);
    }
    T instance = null;
    ServiceLoader<T> loader = ServiceLoader.load(clazz);
    Iterator<T> it = loader.iterator();
    while(it.hasNext())
    {
        instance = it.next();
        break;
    }
    if(instance == null)
        logger.error("没有找到{}的实现。", clazz.getName());
    return instance;
  }
}

 

以上是关于android自定义serviceloader接口隔离及获取自定义properties参数配置的主要内容,如果未能解决你的问题,请参考以下文章

使用ServiceLoader辅助责任链模式

根据动态代理手写一个AOP

根据动态代理手写一个AOP

Dubbo内核实现之SPI简单介绍

Java之ServiceLoader

服务发现 —— ServiceLoader