美文网首页
CC 原理简单分析

CC 原理简单分析

作者: feifei_fly | 来源:发表于2020-03-01 21:54 被阅读0次

    一、CC 的基本使用方式

    1、在模块A中定义Component

    /**
     * @author billy.qi
     */
    public class ComponentA implements IComponent {
        @Override
        public String getName() {
            //组件的名称,调用此组件的方式:
            // CC.obtainBuilder("ComponentA")...build().callAsync()
            return "demo.ComponentA";
        }
    
        /**
         * 组件被调用时的入口
         * 要确保每个逻辑分支都会调用到CC.sendCCResult,
         * 包括try-catch,if-else,switch-case-default,startActivity
         * @param cc 组件调用对象,可从此对象中获取相关信息
         * @return true:将异步调用CC.sendCCResult(...),用于异步实现相关功能,例如:文件加载、网络请求等
         *          false:会同步调用CC.sendCCResult(...),即在onCall方法return之前调用,否则将被视为不合法的实现
         */
        @Override
        public boolean onCall(CC cc) {
            String actionName = cc.getActionName();
            switch (actionName) {
                case "showActivityA":
                    openActivity(cc);
                    break;
                case "getLifecycleFragment":
                    //demo for provide fragment object to other component
                    getLifecycleFragment(cc);
                    break;
                case "lifecycleFragment.addText":
                    lifecycleFragmentDoubleText(cc);
                    break;
                case "getInfo":
                    getInfo(cc);
                    break;
                default:
                    //这个逻辑分支上没有调用CC.sendCCResult(...),是一种错误的示例
                    //并且方法的返回值为false,代表不会异步调用CC.sendCCResult(...)
                    //在LocalCCInterceptor中将会返回错误码为-10的CCResult
                    break;
            }
            return false;
        }
    
        private void lifecycleFragmentDoubleText(CC cc) {
            LifecycleFragment lifecycleFragment = cc.getParamItem("fragment");
            if (lifecycleFragment != null) {
                String text = cc.getParamItem("text", "");
                lifecycleFragment.addText(text);
                CC.sendCCResult(cc.getCallId(), CCResult.success());
            } else {
                CC.sendCCResult(cc.getCallId(), CCResult.error("no fragment params"));
            }
        }
    
        private void getLifecycleFragment(CC cc) {
            CC.sendCCResult(cc.getCallId(), CCResult.successWithNoKey(new LifecycleFragment()));
        }
    
        private void getInfo(CC cc) {
            String userName = "billy";
            CC.sendCCResult(cc.getCallId(), CCResult.success("userName", userName));
        }
    
        private void openActivity(CC cc) {
            CCUtil.navigateTo(cc, ActivityA.class);
            CC.sendCCResult(cc.getCallId(), CCResult.success());
        }
    }
    
    

    2、在主工程中调用A模块中的Component

     public static final String COMPONENT_NAME_A = "demo.ComponentA";
      
     IComponentCallback printResultCallback = new IComponentCallback() {
        @Override
        public void onResult(CC cc, CCResult result) {
            showResult(cc, result);
        }
    };
        
    CC.obtainBuilder(COMPONENT_NAME_A)
                            .setActionName("showActivityA")
                            .build().callAsyncCallbackOnMainThread(printResultCallback);
                            
                            
    

    二、CC的调用流程

    1、CC 是一次组件接口调用的载体类(data)

    承载接口调用的各种参数,调用结果。

    也可以理解为是一个装饰器类。

    
    public class CC {
        private static final String TAG = "ComponentCaller";
        private static final String VERBOSE_TAG = "ComponentCaller_VERBOSE";
        public static final String CC_NULL_KEY = "CC_NULL_KEY";
        /**
         * 默认超时时间为2秒
         */
        private static final long DEFAULT_TIMEOUT = 2000;
        static boolean DEBUG = false;
        static boolean VERBOSE_LOG = false;
        /**
         * 是否响应跨app的组件调用
         * 为了方便开发调试,默认设置为允许响应跨app组件调用
         * 为了安全,app上线时可以将此值设置为false,避免被恶意调用
         */
        private static boolean REMOTE_CC_ENABLED = false;
    
        private volatile CCResult result;
    
        private final byte[] wait4resultLock = new byte[0];
    
        private static Application application;
    
        WeakReference<Activity> cancelOnDestroyActivity;
    
        WeakReference<Fragment> cancelOnDestroyFragment;
    
        private volatile boolean waiting;
    
        static {
            Application app = CCUtil.initApplication();
            if (app != null) {
                init(app);
            }
        }
    
        /**
         * 初始化方法
         * 仅初始化CC,不初始化组件和拦截器
         * 在Application.onCreate(...)中调用
         * @param app Application
         */
        public static synchronized void init(Application app) {
            init(app, false, false);
        }
    
        /**
         * 初始化方法
         * 同时初始化组件和全局拦截器
         * @param app Application
         * @param initComponents 如果设置为true则同时初始化组件
         * @param initGlobalInterceptors 如果设置为true则同时初始化全局拦截器
         */
        public static synchronized void init(Application app, boolean initComponents, boolean initGlobalInterceptors) {
            if (application == null && app != null) {
                application = app;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    application.registerActivityLifecycleCallbacks(new CCMonitor.ActivityMonitor());
                }
            }
            if (initComponents) {
                ComponentManager.init();
            }
            if (initGlobalInterceptors) {
                GlobalCCInterceptorManager.init();
            }
        }
        
        
    
        private WeakReference<Context> context;
        /**
         * 组件名称
         */
        private String componentName;
        /**
         * 组件中某个功能的名称,用以区别同一个组件中不同功能的调用
         */
        private String actionName;
        private final Map<String, Object> params = new HashMap<>();
        /**
         * 回调对象
         */
        private IComponentCallback callback;
        /**
         * 是否异步执行
         */
        private boolean async;
        private final List<ICCInterceptor> interceptors = new ArrayList<>();
        private boolean callbackOnMainThread;
        /**
         * 调用超时时间,默认值(同步调用:2000, 异步调用:0)
         */
        private long timeout = -1;
        long timeoutAt;
        private final AtomicBoolean finished = new AtomicBoolean(false);
        private String callId;
        private volatile boolean canceled = false;
        private volatile boolean timeoutStatus = false;
        private boolean withoutGlobalInterceptor = false;
    
        private CC(String componentName) {
            this.componentName = componentName;
        }
    
        /**
         * 创建CC对象的Builder<br>
         * <b>此对象会被CC框架复用,请勿在程序中保存</b>
         * @param componentName 要调用的组件名称
         * @return 创建CC对象的Builder
         */
        public static Builder obtainBuilder(String componentName) {
            return BUILDER_POOL.get(componentName);
        }
    
        /**
         * 获取当前app的Application对象
         * @return application对象
         */
        public static Application getApplication() {
            return application;
        }
    
        @Override
        public String toString() {
            JSONObject json = new JSONObject();
            put(json, "callId", callId);
            put(json, "context", getContext());
            put(json, "componentName", componentName);
            put(json, "actionName", actionName);
            put(json, "timeout", timeout);
            put(json, "withoutGlobalInterceptor", withoutGlobalInterceptor);
            put(json, "callbackOnMainThread", callbackOnMainThread);
            put(json, "params", CCUtil.convertToJson(params));
            put(json, "interceptors", interceptors);
            put(json, "callback", getCallback());
            return json.toString();
        }
    
        public Context getContext() {
            if (context != null) {
                Context context = this.context.get();
                if (context != null) {
                    return context;
                }
            }
            return application;
        }
    
        void forwardTo(String componentName) {
            this.componentName = componentName;
        }
    
        public String getActionName() {
            return actionName;
        }
    
        /**
         * get all params
         * @return all params as map
         */
        public Map<String, Object> getParams() {
            return params;
        }
    
        /**
         * 获取通过 {@link Builder#setParamWithNoKey(Object)} 设置的参数
         * @param defaultValue 默认值
         * @param <T> 泛型,返回值的类型
         * @return 未设置key(使用默认key)的参数
         */
        public <T> T getParamItemWithNoKey(T defaultValue) {
            return getParamItem(CC_NULL_KEY, defaultValue);
        }
    
        /**
         * 获取通过 {@link Builder#setParamWithNoKey(Object)} 设置的参数
         * @param <T> 泛型,返回值的类型
         * @return 未设置key(使用默认key)的参数
         */
        public <T> T getParamItemWithNoKey() {
            return getParamItem(CC_NULL_KEY);
        }
    
        /**
         * get param(auto class casted) by key
         * @param key key for param
         * @param defaultValue default value if not found or class cast error
         * @param <T> class to cast for param
         * @return class casted param
         */
        public <T> T getParamItem(String key, T defaultValue) {
            T item = getParamItem(key);
            if (item == null) {
                return defaultValue;
            }
            return item;
        }
    
        /**
         * get param(auto class casted) by key
         * @param key key for param
         * @param <T> class to cast for param
         * @return class casted param
         */
        public <T> T getParamItem(String key) {
            try {
                return (T) params.get(key);
            } catch(Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        boolean isAsync() {
            return async;
        }
    
        boolean isCallbackOnMainThread() {
            return callbackOnMainThread;
        }
    
        long getTimeout() {
            return timeout;
        }
    
        public String getCallId() {
            return callId;
        }
    
        boolean isCanceled() {
            return canceled;
        }
    
        /**
         * 判断是否需要中止运行,本次调用被手动取消或已超时。
         * 组件在处理耗时操作时,要根据此状态进行判断,以免进行无效操作
         * @return <code>true</code>:需要中止继续执行;false:可以继续运行
         */
        public boolean isStopped() {
            return canceled || timeoutStatus;
        }
    
        boolean isTimeout() {
            return timeoutStatus;
        }
    
        boolean isWithoutGlobalInterceptor() {
            return withoutGlobalInterceptor;
        }
    
        CCResult getResult() {
            return result;
        }
    
        void setResult(CCResult result) {
            finished.set(true);
            this.result = result;
        }
    
        void setResult4Waiting(CCResult result) {
            try {
                synchronized (wait4resultLock) {
                    if (VERBOSE_LOG) {
                        verboseLog(callId, "setResult" + (waiting ? "4Waiting" : "")
                                + ". CCResult:" + result);
                    }
                    setResult(result);
                    if (waiting) {
                        waiting = false;
                        wait4resultLock.notifyAll();
                    }
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    
        void wait4Result() {
            //等待调用CC.sendCCResult(callId, result)
            synchronized (wait4resultLock) {
                if (!isFinished()) {
                    try {
                        verboseLog(callId, "start waiting for CC.sendCCResult(...)");
                        waiting = true;
                        wait4resultLock.wait();
                        verboseLog(callId, "end waiting for CC.sendCCResult(...)");
                    } catch (InterruptedException ignored) {
                    }
                }
            }
        }
    
        IComponentCallback getCallback() {
            return callback;
        }
    
        /**
         * 在onDestroy后,自动cancel
         */
        void cancelOnDestroy(Object reason) {
            if (!isFinished()) {
                if (VERBOSE_LOG) {
                    verboseLog(callId, "call cancel on " + reason + " destroyed");
                }
                cancel();
            }
        }
    
        void addCancelOnFragmentDestroyIfSet() {
            if (cancelOnDestroyFragment == null) {
                return;
            }
            Fragment fragment = cancelOnDestroyFragment.get();
            if (fragment == null) {
                return;
            }
            FragmentManager manager = fragment.getFragmentManager();
            if (manager != null) {
                manager.registerFragmentLifecycleCallbacks(
                        new CCMonitor.FragmentMonitor(this)
                        , false);
            }
        }
    
        public String getComponentName() {
            return componentName;
        }
    
        List<ICCInterceptor> getInterceptors() {
            return interceptors;
        }
    
        /**
         * 异步调用,且不需要回调
         * @return callId,可用于取消调用的任务
         */
        public String callAsync() {
            return callAsync(null);
        }
        /**
         * 异步调用,在异步线程执行回调
         * @param callback 回调函数
         * @return callId 用于取消
         */
        public String callAsync(IComponentCallback callback) {
            this.callbackOnMainThread = false;
            return processCallAsync(callback);
        }
        /**
         * 异步调用,在主线程执行回调
         * @param callback 回调函数
         * @return callId 用于取消
         */
        public String callAsyncCallbackOnMainThread(IComponentCallback callback) {
            this.callbackOnMainThread = true;
            return processCallAsync(callback);
        }
    
        private String processCallAsync(IComponentCallback callback) {
            if (callback != null) {
                this.callback = callback;
            }
            this.async = true;
            //调用方未设置超时时间,默认为无超时时间
            if (timeout < 0) {
                timeout = 0;
            }
            setTimeoutAt();
            this.callId = nextCallId();
            this.canceled = false;
            this.timeoutStatus = false;
            if (VERBOSE_LOG) {
                verboseLog(callId, "start to callAsync:" + this);
            }
            ComponentManager.call(this);
            return callId;
        }
    
        /**
         * 同步调用
         * @return CCResult
         */
        public CCResult call() {
            this.callback = null;
            this.async = false;
            boolean mainThreadCallWithNoTimeout = timeout == 0 && Looper.getMainLooper() == Looper.myLooper();
            //主线程下的同步调用必须设置超时时间,默认为2秒
            if (mainThreadCallWithNoTimeout || timeout < 0) {
                timeout = DEFAULT_TIMEOUT;
            }
            setTimeoutAt();
            this.callId = nextCallId();
            this.canceled = false;
            this.timeoutStatus = false;
            //加上开关判断,防止开关关闭的情况下也执行this.toString()方法
            if (VERBOSE_LOG) {
                verboseLog(callId, "start to call:" + this);
            }
            return ComponentManager.call(this);
        }
    
       
        /**
         * 在任意位置回调结果
         * 组件的onCall方法被调用后,<b>必须确保所有分支均会调用</b>到此方法将组件调用结果回调给调用方
         * @param callId 回调对象的调用id
         * @param ccResult 回调的结果
         */
        public static void sendCCResult(String callId, CCResult ccResult) {
            if (VERBOSE_LOG) {
                verboseLog(callId, "CCResult received by CC.sendCCResult(...).CCResult:" + ccResult);
            }
            CC cc = CCMonitor.getById(callId);
            if (cc != null) {
                if (cc.markFinished()) {
                    if (ccResult == null) {
                        ccResult = CCResult.defaultNullResult();
                        logError("CC.sendCCResult called, But ccResult is null, set it to CCResult.defaultNullResult(). "
                                + "ComponentName=" + cc.getComponentName());
                    }
                    cc.setResult4Waiting(ccResult);
                } else {
                    logError("CC.sendCCResult called, But ccResult is null. "
                            + "ComponentName=" + cc.getComponentName());
                }
            } else {
                log("CCResult received, but cannot found callId:" + callId);
            }
        }
    
        /**
         * 在任意位置回调结果
         * @param callId 回调对象的调用id
         * @param result 回调的结果
         * @deprecated use {@link #sendCCResult(String, CCResult)}
         */
        @Deprecated
        public static void invokeCallback(String callId, CCResult result) {
            sendCCResult(callId, result);
        }
    
        /**
         * 获取当前app内是否含有指定的组件
         * @param componentName 组件名称
         * @return true:有, false:没有
         */
        public static boolean hasComponent(String componentName) {
            return ComponentManager.hasComponent(componentName);
        }
    
        /**
         * 开关跨app调用组件支持,默认为关闭状态
         *  1. 某个componentName当前app中不存在时,是否尝试调用其它app的此组件
         *  2. 接收到跨app调用时,是否执行本次调用
         *  3. 建议仅在开发阶段调试时打开,正式发布时关闭
         * @param enable 开关(true:会执行; false:不会)
         */
        public static void enableRemoteCC(boolean enable) {
            REMOTE_CC_ENABLED = enable;
            if (enable && application != null) {
                RemoteCCInterceptor.getInstance().enableRemoteCC();
            }
        }
    
        public static boolean isRemoteCCEnabled() {
            return REMOTE_CC_ENABLED;
        }
    
        /**
         * 当前进程是否以包名在运行(当前进程是否为主进程)
         */
        public static boolean isMainProcess(){
            return CCUtil.isMainProcess();
        }
    
        public static boolean isDebugMode() {
            return DEBUG;
        }
    }
    
    

    其核心方法 call(),其实是代理到了
    ComponentManager.call(this)中。

       /**
         * 同步调用
         * @return CCResult
         */
        public CCResult call() {
            this.callback = null;
            this.async = false;
            boolean mainThreadCallWithNoTimeout = timeout == 0 && Looper.getMainLooper() == Looper.myLooper();
            //主线程下的同步调用必须设置超时时间,默认为2秒
            if (mainThreadCallWithNoTimeout || timeout < 0) {
                timeout = DEFAULT_TIMEOUT;
            }
            setTimeoutAt();
            this.callId = nextCallId();
            this.canceled = false;
            this.timeoutStatus = false;
            //加上开关判断,防止开关关闭的情况下也执行this.toString()方法
            if (VERBOSE_LOG) {
                verboseLog(callId, "start to call:" + this);
            }
            return ComponentManager.call(this);
        }
    

    2、ComponentManager 类是CC 中的总线类,或者说仓库类。维护着CC 中的路由信息

    <组件名字符串,Component组件对象>

        private static final ConcurrentHashMap<String, IComponent> COMPONENTS = new ConcurrentHashMap<>();
    

    组件映射关系的收集是通过gradle插件 cc-register 来完成的。

    https://github.com/luckybilly/AutoRegister

    scanInterface : (必须)字符串,接口名(完整类名),所有直接实现此接口的类将会被收集
    codeInsertToClassName : (必须)字符串,类名(完整类名),通过编译时生成代码的方式将收集到的类注册到此类的codeInsertToMethodName方法中
    codeInsertToMethodName: 字符串,方法名,注册代码将插入到此方法中。若未指定,则默认为static块,(方法名为:)
    registerMethodName : (必须)字符串,方法名,静态方法,方法的参数为 scanInterface
    scanSuperClasses : 字符串或字符串数组,类名(完整类名),所有直接继承此类的子类将会被收集
    include : 数组,需要扫描的类(正则表达式,包分隔符用/代替,如: com/billy/android/.*),默认为所有的类
    exclude : 数组,不需要扫描的类(正则表达式,包分隔符用/代替,如: com/billy/android/.*),
    

    自动收集原理是:

    • gradle插件包含了一个叫Transform的API,这个API允许第三方插件在class文件转为为dex文件前操作编译好的class文件。
    • 在Tansform中 收集相关类,编译期间修改字节码,加入到管理类中。
    /**
     * 组件调用管理类
     * @author billy.qi
     * @since 17/6/28 20:14
     */
    class ComponentManager {
        /** 当前进程中的组件集合 */
        private static final ConcurrentHashMap<String, IComponent> COMPONENTS = new ConcurrentHashMap<>();
        /**
         * 组件名称对应的进程名称集合
         * 当前进程为主进程:包含当前app内的所有静态组件和动态组件的(名称 - 进程名)的映射表
         * 当前进程为子进程:包含当前app内的所有静态组件和当前进程内注册的动态组件的(名称 - 进程名)的映射表
         */
        private static final ConcurrentHashMap<String, String> COMPONENT_PROCESS_NAMES = new ConcurrentHashMap<>();
        private static final String SUB_PROCESS_SEPARATOR = ":";
    
        static {
            registerComponent(new DynamicComponentOption());
            //加载类时自动调用初始化:注册所有组件
            //通过auto-register插件生成组件注册代码
            //生成的代码如下:
            //registerComponent(new ComponentA());
            //registerComponent(new ComponentAA());
        }
    
        /**
         * 提前初始化所有全局拦截器
         */
        static void init(){
            //调用此方法时,虚拟机会加载ComponentManager类
            //会自动执行static块中的组件自动注册,调用组件类的无参构造方法
            //如果不提前调用此方法,static块中的代码将在第一次进行组件调用时(cc.callXxx())执行
        }
    }
    

    核心调用方法call(),交给了一个拦截器调用链。

     /**
         * 组件调用统一入口
         * @param cc 组件调用指令
         * @return 组件调用结果(同步调用的返回值)
         */
        static CCResult call(CC cc) {
            String callId = cc.getCallId();
            Chain chain = new Chain(cc);
            if (!cc.isWithoutGlobalInterceptor()) {
                chain.addInterceptors(INTERCEPTORS);
            }
            chain.addInterceptors(cc.getInterceptors());
            // 有效性校验放在自定义拦截器之后执行,优先执行自定义拦截器,让其可以拦截到所有组件调用
            // 执行实际调用的拦截器在校验有效性结束后再添加
            chain.addInterceptor(ValidateInterceptor.getInstance());
            ChainProcessor processor = new ChainProcessor(chain);
            //异步调用,放到线程池中运行
            if (cc.isAsync()) {
                if (CC.VERBOSE_LOG) {
                    CC.verboseLog(callId, "put into thread pool");
                }
                CC_THREAD_POOL.submit(processor);
                //异步调用时此方法返回null,CCResult通过callback回调
                return null;
            } else {
                //同步调用,直接执行
                CCResult ccResult;
                try {
                    ccResult = processor.call();
                } catch (Exception e) {
                    ccResult = CCResult.defaultExceptionResult(e);
                }
                if (CC.VERBOSE_LOG) {
                    CC.verboseLog(callId, "cc finished.CCResult:" + ccResult);
                }
                //同步调用的返回结果,永不为null,默认为CCResult.defaultNullResult()
                return ccResult;
            }
        }
    
    

    Chain 实现了一个拦截器调用链:

    
    /**
     * 组件调用链,用于管理拦截器的运行顺序
     * @author billy.qi
     */
    public class Chain {
        private final List<ICCInterceptor> interceptors = new ArrayList<>();
        private final CC cc;
        private int index;
    
        Chain(CC cc) {
            this.cc = cc;
            this.index = 0;
        }
    
        void addInterceptors(Collection<? extends ICCInterceptor> interceptors) {
            if (interceptors != null && !interceptors.isEmpty()) {
                this.interceptors.addAll(interceptors);
            }
        }
        void addInterceptor(ICCInterceptor interceptor) {
            if (interceptor != null) {
                this.interceptors.add(interceptor);
            }
        }
    
        public CCResult proceed() {
            if (index >= interceptors.size()) {
                return CCResult.defaultNullResult();
            }
            ICCInterceptor interceptor = interceptors.get(index++);
            //处理异常情况:如果为拦截器为null,则执行下一个
            if (interceptor == null) {
                return proceed();
            }
            String name = interceptor.getClass().getName();
            String callId = cc.getCallId();
            CCResult result;
            if (cc.isFinished()) {
                //timeout, cancel, CC.sendCCResult(callId, ccResult), cc.setResult, etc...
                result = cc.getResult();
            } else {
                if (CC.VERBOSE_LOG) {
                    CC.verboseLog(callId, "start interceptor:" + name + ", cc:" + cc);
                }
                try {
                    result = interceptor.intercept(this);
                } catch(Throwable e) {
                    //防止拦截器抛出异常
                    result = CCResult.defaultExceptionResult(e);
                }
                if (CC.VERBOSE_LOG) {
                    CC.verboseLog(callId, "end interceptor:" + name + ".CCResult:" + result);
                }
            }
            //拦截器理论上不应该返回null,但为了防止意外(自定义拦截器返回null,此处保持CCResult不为null
            //消灭NPE
            if (result == null) {
                result = CCResult.defaultNullResult();
            }
            cc.setResult(result);
            return result;
        }
    
        public CC getCC() {
            return cc;
        }
    }
    
    
    image.png

    三、CC 库有点可以值得我们仔细研究和学习。

    • gradle编程 Transform +ASM 动态修改字节码的技术。自动生成类,或者自动修改类没完成插桩操作。
    • 拦截器链(责任链)的应用
    • 通过ContentProvider来实现远程调用。值得研究一下原理。

    相关文章

      网友评论

          本文标题:CC 原理简单分析

          本文链接:https://www.haomeiwen.com/subject/scalkhtx.html