用CDI机制替换基于工厂的对象创建

Seb*_*mba 2 java factory factory-pattern cdi jboss-weld

我想向我们的项目介绍CDI(Weld),现在手动构建的对象遇到了一些麻烦.

所以我们有一些实现IReport接口的类,它有一个应该注入的字段.因为所有这些类是由产生这是在运行时零ReportFactory一类ReportController.

private Map<String,Object> generateReport(ReportInfo ri, ...) {
// some input validation
    IReport report = ReportControllerFactory.getReportInstance( ri.getClassName() );
// ...
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以将@Produces注释与另一个自定义注释一起使用ReportControllerFactory,但是如何一个方法中使用@Injectfor只能在完成一些验证之后创建的变量?我将如何提交参数?构造时对象是未知的.ri.getClassName()riReportController

非常感谢你!

亲切的问候,塞巴斯蒂安

编辑于2011年7月8日(10:00):

ReportFactory类:

public static IReport getReportInstance( String className ) throws ReportException {

    IReport report = null;

    try {
        Class<?> clazz = Class.forName( className );
        report = (IReport) clazz.newInstance();
    }
    catch ( Exception e ) { … }        

    return report;
}
Run Code Online (Sandbox Code Playgroud)

编辑2(选择正确的报告实施)

报告实例由从JSF前端到ReportController的一些路径选择.ManagedBean调用一个会话bean,它有几种方法,具体取决于按下哪个按钮.所有这些方法都设置了报告名称并调用了更通用的方法sendOrGetReport.此方法从数据库中选择指定报告的唯一键,并决定是发送电子邮件还是立即发送报告.我们假设应该交付.

然后ReportController发挥作用.他ReportInfo根据上述方法提供的唯一键和其他信息获取对象,并调用它ReportFactory来创建类型报告ri.getClassName().

好吗,对吧?我认为整个部分可能需要一些重构.如果您没有看到任何简单的位置,我会跳过@Inject报告实现并对该资源执行JDNI查找.

小智 12

为了动态创建正确的报告类,对接受的答案进行小的更改将解决问题.解决方案是Instance <...>为您提供了某种类型的所有bean的列表.不需要生成注释.

创建一个工厂类,可以在运行时在注入的实例之间进行选择

public class ReportFactory {

@Inject Instance<IReport> availableReports;

public IReport createReport(String type) {

   for (IReport report: availableReports) {
      if (report.getType().equals(type)) { //or whatever test you need
         return report;
      }
   }
   return null;
}
Run Code Online (Sandbox Code Playgroud)

现在需要动态选择报告的类可以使用此工厂.

public class ReportCreator {

    @Inject
    private ReportFactory reportFactory;

    public void createReport(String type) {
        IReport report = reportFactory.createReport(type);
        report.execute();
    }
 }
Run Code Online (Sandbox Code Playgroud)


jan*_*oth 8

CDI(和其他DI框架)为了管理依赖关系而背后的想法是接管对托管bean生命周期的控制.这意味着 - 除其他外 - 如果您希望托管bean由容器管理,则不能干扰托管bean的创建.

当然这并不意味着你的场景无法解决,你只需稍微改变你的观点;-)

这个想法是使用托管bean(显然),但让你自己的逻辑决定所有可用实例的哪个实例是正确的.

...
@Inject Instance<IReport> availableReports;
...
@Produces
public IReport createReport() {
   IReport result;
   for (IReport report: availableReports) {
      // choose correct instance, you might want to query the injection
      // point or any attached qualifier a bit more in order to 
      // determine which is the correct instance
      if ...
         result = report;
      ...
   }
   return result;
}
...
Run Code Online (Sandbox Code Playgroud)

随着你喜欢的各种各样的豆类IReport

public class AReport implements IReport {
...
@Inject
...
}

public class BReport implements IReport {
...
@Inject
...
}
Run Code Online (Sandbox Code Playgroud)

像这样的自动化用法

public class MyStuff {
...
@Inject
IReport myReport;
...
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参见此处此处.

如果我没有误解你的问题,这应该会带给你前进 - 随时发布更多问题/评论.

更新:

如果这样的东西符合您的要求,那么一切都可能很简单:

@AReport
public class AReport implements IReport {
...
@Inject
...
}

@BReport
public class BReport implements IReport {
...
@Inject
...
}
Run Code Online (Sandbox Code Playgroud)

有了这样的用法

public class MyStuff {
...
@Inject
@AReport
IReport myAReport;
...
@Inject
@BReport
IReport myBReport;
...
}
Run Code Online (Sandbox Code Playgroud)