@946898963
2021-05-28T18:14:18.000000Z
字数 7022
阅读 555
分享
随着业务发展,版本不断的迭代,业务模块也在不断的增加,而且每个模块的代码也会越来越多,代码在垂直和水平方向上耦合都比较严重,基于上述考虑,我们要实施业务组件化。最终的目的是使每个业务模块都类似一个具备独立运行的U盘,即插即用。
一、业务模块独立,模块之间互不直接耦合。
二、组件化是基于模块化的,开发团队的规模会越来越大,不同的组件由不同的工程师来负责,解决app开发过程中的开发与协作的问题。
一、业务组件之间通信:组件内基本上保持原来的调用方式;组件之间的通信通过服务管理中心。
二、组件间的耦合性:各个业务组件之间没有直接依赖关系即不依赖具体的实现,组件之间依赖抽象。
基于上述两点,需要一个基础的服务管理框架解决模块间的耦合和通信问题
实施方法:组件化后由app壳工程提供统一的入口,一个项目工程拆分成若干个组件工程,由壳工程集成需要引入的业务组件,每个业务独立的组件向下依赖公共库,如下图。
各个独立的业务组件之间的调用依赖关系,通过服务管理中心调度他们之间的依赖关系,如下图。
tips1:通过服务管理中心解决业务组件间的水平依懒关系(面向接口编程思想,依懒抽象,不依懒具体实现)。
tips2:业务组件依懒公共库直接以maven库形式导入,直接调用公共库中的方法即可。
项目按照相关的业务进行模块化拆分后,模块以Service的形式对外公开模块的能力,外部通过接口调用服务的方法,模块内部是接口具体的实现,ServiceManager根据接口上的注解来查找具体的服务,并通过反射实例化具体的对象。调用流程图如下:
每个功能Module,由pi module和pm module两个Module组成,其中pi存放了接口,pm中存放了pi中接口的部分实现。
PI(Project Interface)
PI中只是存放接口,其中肯定有两个接口。
IXXService接口:表示自己提供给其他Module的能力,其他模块可以获得该模块的功能。接口有注解修饰。
@Module(packageName = "com.ss....pm_xx",className="com.ss.android.....XXServiceModule")
,注解注入了包名,类名,对应着真正的业务类。
PM(Project Module)
功能实现Module。
XXService,实现了IXXService接口中的方法的单例类。实现的IXXService接口中的方法是暴露给其他Module使用的,XXService也可以加一些非IXXService接口中的方法,这些方法不会暴露给外部,仅供自己使用。
XXServiceModule,对外暴露服务的帮助类(具体实现原理见源码分析),应用在IXXService接口上的注解中的className的值,对应的就是这个类,XXServiceModule通用实现如下:
public class CircleServiceModule implements IModule {
private List<ICreator<?>> updateServer = new ArrayList<>();
@Override
public List<ICreator<?>> getServiceCreators() {
updateServer.add(new ServiceCreator<>(CircleService.getInstance(), ICircleService.class));
return updateServer;
}
}
真正的业务类,大体架构像高阶版的 MVP 模式,使用 lifecycle 做 ViewModel 和 View 之间的通信。具体细节请看微观架构分析。
Module注解类,用来标记业务Module的PI Module中的IXXService接口,主要用来指明PM Module中的XXServiceModule类的位置。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Module {
/**
* @return 服务所在Module的class全名
*/
String className() default "";
/**
* 返回服务所在Module的包名,不同的Module的包名必须不同,不能有一个包名下存在两个不同Module的情况
*
* @return 服务所在Module的包名
*/
String packageName() default "";
/**
* @return 服务所在Module是否由插件提供
*/
boolean isPlugin() default false ;
/**
* @return 服务所在Module由插件提供时的插件包名
*/
String pluginPackageName() default "";
/**
* @return 服务所在Module由插件提供时的插件最小版本
*/
int dependPluginMinVersion() default 0;
}
服务包装类ICreator:
public interface ICreator<T> {
public T get(Object... args);
public Class<T> getKey();
}
服务包装类ICreator的实现类ServiceCreator,主要用来包装XXService,mInstance赋值为XXService,mCls赋值为IXXService:
public class ServiceCreator<T> implements ICreator<T> {
private T mInstance;
private Class<T> mCls;
public ServiceCreator(T instance, Class<T> cls) {
mInstance = instance;
mCls = cls;
}
@Override
public T get(Object... args) {
return mInstance;
}
@Override
public Class<T> getKey() {
return mCls;
}
}
暴露服务的辅助接口IModule。
public interface IModule {
List<ICreator<?>> getServiceCreators();
}
服务管理类ServiceManager,用来管理服务。
public class ServiceManager {
static final String TAG = "ServiceManager";
private static final Map<Class<?>, ICreator<?>> sServiceCreatorMap = new ConcurrentHashMap<>();
static void addServiceCreator(ICreator<?> serviceCreator) {
if (serviceCreator == null) {
return;
}
final Class<?> key = serviceCreator.getKey();
if (key == null) {
return;
}
sServiceCreatorMap.put(key, serviceCreator);
}
public synchronized static <T> T get(Class<T> cls,Object... args) {
if(!cls.isInterface()){
throw new IllegalArgumentException(String.format("cls %s should be a interface class",cls.getCanonicalName()));
}
ICreator<T> serviceCreator = (ICreator<T>) sServiceCreatorMap.get(cls);
if (serviceCreator != null) {
return serviceCreator.get(args);
} else if (cls.isAnnotationPresent(Module.class)) {
try {
final Module module = cls.getAnnotation(Module.class);
if (module == null) {
return null;
}
String packageName = module.packageName();
String className = module.className();
String pluginPackageName = module.pluginPackageName();
int dependPluginMinVersion = module.dependPluginMinVersion();
boolean isPlugin = module.isPlugin();
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) {
return null;
}
if(isPlugin && TextUtils.isEmpty(pluginPackageName)){
return null;
}
final ModuleFactory moduleFactory = ModuleFactory.getModuleFactory();
if (moduleFactory == null) {
return null;
}
// module初始化过程会将自己提供的所有service的servicecreator注册到sServiceCreatorMap
if (!moduleFactory.tryInitModule(packageName, className, isPlugin, pluginPackageName, dependPluginMinVersion)) {
return null;
}
serviceCreator = (ICreator<T>) sServiceCreatorMap.get(cls);
if (serviceCreator == null) {
return null;
}
return serviceCreator.get(args);
} catch (Throwable e) {
e.printStackTrace();
}
}
return null;
}
}
Module包装类ModuleInfo,通过反射创建IModule的实现类的实例,从而将IModule的实现类中的ICreator注册到ServiceManager的Map中。
class ModuleInfo {
public static final String TAG = ModuleFactory.TAG;
private IModule module;
private String className;
private boolean isInstanced;
public ModuleInfo(String className) {
this.className = className;
}
boolean tryInstanceModule() {
if (isInstanced || TextUtils.isEmpty(className)) {
return isInstanced;
}
try {
if (module == null) {
final Class contextClass = Class.forName(className);
final Object instance = contextClass.newInstance();
if (instance instanceof IModule) {
module = (IModule) instance;
}
}
if (module != null) {
// 注册当前Module提供的所有ServiceCreator
final List<ICreator<?>> serviceCreators = module.getServiceCreators();
if (serviceCreators != null && !serviceCreators.isEmpty()) {
for (ICreator<?> serviceCreator : serviceCreators) {
if (serviceCreator == null) {
continue;
}
ServiceManager.addServiceCreator(serviceCreator);
}
isInstanced = true;
}
}
} catch (Throwable e) {
isInstanced = false;
e.printStackTrace();
}
return isInstanced;
}
boolean isInstanced() {
return isInstanced;
}
}
IModule实现类的工厂类ModuleFactory,用来管理IModule的实现类。
public class ModuleFactory {
static final String TAG = "ModuleFactory";
private static volatile ModuleFactory sInstance;
final Map<String, ModuleInfo> mModuleInfoMap = new ConcurrentHashMap<>();
private static IPluginDependListener mPluginDependListener;
private static Application mApplication;
public static ModuleFactory init(ConfigBuilder configBuilder) {
if(configBuilder == null || configBuilder.mPluginListener == null || configBuilder.mApplication == null){
throw new IllegalArgumentException("params cannot be null");
}
if (sInstance == null) {
synchronized (ModuleFactory.class) {
if (sInstance == null) {
sInstance = new ModuleFactory();
mPluginDependListener = configBuilder.mPluginListener;
mApplication = configBuilder.mApplication;
}
}
}
return sInstance;
}
static ModuleFactory getModuleFactory() {
return sInstance;
}
private ModuleFactory() {
}
public boolean tryInitModule(String packageName, String className, boolean isPlugin, String pluginPackageName, int dependPluginMinVersion) {
if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className) || (isPlugin && (TextUtils.isEmpty(pluginPackageName) || mPluginDependListener == null))) {
return false;
}
if(isPlugin && !mPluginDependListener.checkPluginStatus(pluginPackageName,dependPluginMinVersion)){
return false;
}
ModuleInfo moduleInfo = mModuleInfoMap.get(packageName);
if (moduleInfo == null) {
moduleInfo = new ModuleInfo(className);
mModuleInfoMap.put(packageName, moduleInfo);
}
return moduleInfo.isInstanced() || moduleInfo.tryInstanceModule();
}
public static class ConfigBuilder{
private IPluginDependListener mPluginListener;
private Application mApplication;
public ConfigBuilder setPluginListener(IPluginDependListener pluginListener){
this.mPluginListener = pluginListener;
return this;
}
public ConfigBuilder setApplication(Application application){
this.mApplication = application;
return this;
}
}
}