动态地使用注入器从名称实例化类

时间:2017-04-28 13:32:21

标签: java jersey-2.0 hk2

上下文

我为我的公司开发了一种软件,该软件通过多种特征提取算法对包含网站的网络钓鱼和恶意软件进行分类。

一旦提取了特征,我们就会使用一系列经验和机器学习分类器。由于我们自己的选举功能,我们在其中做出选择。

代码

基本上我们有分类器类来实现AnalysisFunction合同。

public abstract class AnalysisFunction {
    abstract public StatusType analyze(List<TokenEntity> tokens);
    abstract public double getPhishingProbability(List<TokenEntity> tokens);
}

我们的分类器池包含一个实现AnalysisFunction的“池”。

public class PoolAnalysisFunction extends AnalysisFunction{
    private final List<AnalysisFunction> candidates;
    private final ChoiceFunction choice;
    private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);

    public PoolAnalysisFunction(List<AnalysisFunction> candidates, ChoiceFunction choice) {
        this.candidates = candidates;
        this.choice = choice;
    }

    @Override
    public StatusType analyze(List<TokenEntity> tokens) {
        try {
            return choice.chooseAmong(candidates, tokens).analyze(tokens);
        } catch (ImpossibleChoiceException e){
            LOG.fatal("Not enough analysis function.", e);
            return StatusType.CLEAN;
        }
    }

    @Override
    public double getPhishingProbability(List<TokenEntity> tokens) {
        try {
            return choice.chooseAmong(candidates, tokens).getPhishingProbability(tokens);
        } catch (ImpossibleChoiceException e){
            LOG.fatal("Not enough analysis function.", e);
            return 0;
        }
    }
}

为了简化新功能的部署和测试,我们希望使我们的池完全可定制,并通过其名称实现每个功能。为了达到这个目的,我们在属性文件中有一个键,如analysis.pool.functions=com.vadesecure.analysis.empirical.Function1,com.vadesecure.analysis.machine.AutomaticClassifier1

我想要实例化我的功能。 我的问题是那些分类器依赖于不同的东西,如自定义配置对象和机器学习模型。 我想注入那些已经绑定在我的hk2注入器中的依赖项。

import org.glassfish.hk2.api.Factory;
public class PoolFunctionFactory implements Factory<AnalysisFunction> {
    private final PoolAnalysisParameters parameters;
    private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
    @Inject
    public PoolFunctionFactory(PoolAnalysisParameters parameters) {
        this.parameters = parameters;
    }

    @Override
    public AnalysisFunction provide() {
        try {

            Class<?> choice = Class.forName(parameters.getChoiceFunctionFQDN());
            ChoiceFunction choiceFunction = new PhishingPriorityChoiceFunction(); // default choice
            if(choice.getSuperclass().isInstance(ChoiceFunction.class)){
                choiceFunction = (ChoiceFunction) choice.newInstance();
            }
            List<AnalysisFunction> analysisFunctions = new LinkedList<>();
            // I want to instantiate here
            }
            return new PoolAnalysisFunction(analysisFunctions, choiceFunction);
        } catch (ClassNotFoundException|IllegalAccessException|InstantiationException e){
            LOG.fatal(e, e);
        }

        return null;
    }

    @Override
    public void dispose(AnalysisFunction analysisFunction) {
        LOG.trace(String.format("%s end of life", analysisFunction));
    }
}

依赖于模型的分类器的例子是:

public class SVMF2AnalysisFunction extends AnalysisFunction {
    private final SVMContainer modelContainer;
    private double probability = 0.0;
    private double threshold = 0.9;
    @Inject // i build this model in a parallel thread
    public SVMF2AnalysisFunction(SVMContainer modelContainer) {
        this.modelContainer = modelContainer;
    }

    @Override
    public StatusType analyze(List<TokenEntity> tokens) {
        if (modelContainer.getModel() == null) {
            return null;
        }
        probability = modelContainer.getModel().analyse(tokens.stream());
        return probability >= threshold ? StatusType.PHISHING : StatusType.CLEAN;
    }

    @Override
    public double getPhishingProbability(List<TokenEntity> tokens) {
        return probability;
    }
}

我如何实现这些实现。

我的第一个方法是注入serviceLocator,但我没有找到这样做的文件,一位同事说我不好。

他告诉我要记录代理人,但这对我来说似乎不是一件好事,或者我错过了一些东西。

1 个答案:

答案 0 :(得分:2)

您可以在活页夹中配置所有这些内容。这样您就不必担心尝试自己实例化所有内容。让HK2完成所有工作

@Override
protected void configure() {
   bindAsContract(PoolAnalysisFunction.class).in(Singleton.class);

   bind(choiceFnClass).to(ChoiceFunction.class);

   for (Class<AnalysisFunction> analysisFnClass: analyisFnClasses) {
       bind(analysisFnClass).to(AnalysisFunction.class).in(Singleton.class);
   }
}

然后您可以将所有内容注入PoolAnalysisFunction课程,而无需使用工厂。

@Inject
public PoolAnalysisFunction(IterableProvider<AnalysisFunction> candidates,
                            ChoiceFunction choice) {
    this.choice = choice;

    this.candidates = new ArrayList<>();
    candidates.forEach(this.candidates::add);
}

注意IterableProvider课程。这是一个HK2类,用于注入绑定到同一合同的多个服务。

或者如果你想使用工厂,你可以,只需将功能注入工厂。这样你就可以使PoolAnalysisFunction类独立于HK2类(即InjectableProvider)。