Conditional injection of bean

左心房为你撑大大i 提交于 2019-12-18 04:13:00

问题


I want to have inject a bean based on a String parameter passed from client.

public interface Report {
    generateFile();
}

public class ExcelReport extends Report {
    //implementation for generateFile
}

public class CSVReport extends Report {
    //implementation for generateFile
}

class MyController{
    Report report;
    public HttpResponse getReport() {
    }
}

I want report instance to be injected based on the parameter passed. Any help would be greatly appretiated. Thanks in advance


回答1:


Use Factory method pattern:

public enum ReportType {EXCEL, CSV};

@Service
public class ReportFactory {

    @Resource
    private ExcelReport excelReport;

    @Resource
    private CSVReport csvReport

    public Report forType(ReportType type) {
        switch(type) {
            case EXCEL: return excelReport;
            case CSV: return csvReport;
            default:
                throw new IllegalArgumentException(type);
        }
    }
}

The report type enum can be created by Spring when you call your controller with ?type=CSV:

class MyController{

    @Resource
    private ReportFactory reportFactory;

    public HttpResponse getReport(@RequestParam("type") ReportType type){
        reportFactory.forType(type);
    }

}

However ReportFactory is pretty clumsy and requires modification every time you add new report type. If the report types list if fixed it is fine. But if you plan to add more and more types, this is a more robust implementation:

public interface Report {
    void generateFile();
    boolean supports(ReportType type);
}

public class ExcelReport extends Report {
    publiv boolean support(ReportType type) {
        return type == ReportType.EXCEL;
    }
    //...
}

@Service
public class ReportFactory {

    @Resource
    private List<Report> reports;

    public Report forType(ReportType type) {
        for(Report report: reports) {
            if(report.supports(type)) {
                return report;
            }
        }
        throw new IllegalArgumentException("Unsupported type: " + type);
    }
}

With this implementation adding new report type is as simple as adding new bean implementing Report and a new ReportType enum value. You could get away without the enum and using strings (maybe even bean names), however I found strongly typing beneficial.


Last thought: Report name is a bit unfortunate. Report class represents (stateless?) encapsulation of some logic (Strategy pattern), whereas the name suggests it encapsulates value (data). I would suggest ReportGenerator or such.



来源:https://stackoverflow.com/questions/7537620/conditional-injection-of-bean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!