且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用 Guice 将我的 api 注入数据流作业而无需可序列化?

更新时间:2023-09-26 20:44:28

以这样一种方式解决:mock 不再需要静态或序列化,因为玻璃桥接了数据流的世界(在生产和测试中)像这样

Solved in such a way that mocks no longer need static or serialization anymore by one since glass bridging the world of dataflow(in prod and in test) like so

注意:我们公司还有一个额外的魔法,它通过从一个服务到另一个服务的标头并通过数据流传递其中的一些你可以忽略的东西(即 RouterRequest 请求 = Current.request();)所以对于其他人,他们每次都必须将 projectId 传入 getInstance.

NOTE: There is additional magic-ness we have in our company that passes through headers from service to service and through dataflow and that is some of it in there which you can ignore(ie. the RouterRequest request = Current.request();). so for anyone else, they will have to pass in projectId into getInstance each time.

public abstract class DataflowClientFactory implements Serializable {
    private static final Logger log = LoggerFactory.getLogger(DataflowClientFactory.class);

    public static final String PROJECT_KEY = "projectKey";
    private transient static Injector injector;
    private transient static Module overrides;

    private static int counter = 0;

    public DataflowClientFactory() {
        counter++;
        log.info("creating again(usually due to deserialization). counter="+counter);
    }

    public static void injectOverrides(Module dfOverrides) {
        overrides = dfOverrides;
    }

    private synchronized void initialize(String project) {
        if(injector != null)
            return;

        /********************************************
         * The hardest part is this piece since this is specific to each Dataflow
         * so each project subclasses DataflowClientFactory
         * This solution is the best ONLY in the fact of time crunch and it works
         * decently for end to end testing without developers needing fancy
         * wrappers around mocks anymore.
         ***/
        Module module = loadProjectModule();

        Module modules = Modules.combine(module, new OrderlyDataflowModule(project));
        if(overrides != null) {
            modules = Modules.override(modules).with(overrides);
        }

        injector = Guice.createInjector(modules);
    }

    protected abstract Module loadProjectModule();

    public <T> T getInstance(Class<T> clazz) {
        if(!Current.isContextSet()) {
            throw new IllegalStateException("Someone on the stack is extending DoFn instead of OrderlyDoFn so you need to fix that first");
        }
        RouterRequest request = Current.request();
        String project = (String)request.requestState.get(PROJECT_KEY);

        initialize(project);
        return injector.getInstance(clazz);
    }

}