3 回答

TA貢獻1830條經驗 獲得超9個贊
假設這Parser是你自己的接口,你可以添加一個方法來告訴它能夠解析的格式:
public interface Parser {
List<Order> parse(String filePath);
String getFormat();
}
然后在所有實現中覆蓋它:
@Component
public class CsvParser implements Parser {
public static final String FORMAT = "csv";
public String getFormat(){
return FORMAT;
}
// ...
}
通過使用 @Bean/@Component 注釋類或在配置類中創建實例來配置解析器 bean。(如果您使用的是 SpringBoot,我建議您使用@ConditionalOn...注釋以避免創建不必要的 bean)
現在您可以將所有Parser實例注入到ParserService.
@Service
public class ParsingService {
private final Map<String, Parser> parsers;
@Autowired
public ParsingService(List<Parser> allParsers) {
this.parsers = allParsers
.stream()
.collect(Collectors.toMap(Parser::getFormat, p -> p));
}
public List<Order> parse(String filePath) {
try {
String format = getFormat(filePath);
Parser parser = parsers.get(format);
if(parser == null) {
// Replace this exception by a more appropriate one
throw new RuntimeException("No parsers found for format : " + format);
} else {
return parser.parse(filePath);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private String getFormat(String filePath){
int i = filePath.lastIndexOf('.');
if (i > 0) {
return filePath.substring(i+1).toLowerCase();
} else {
// Replace this exception by a more appropriate one
throw new RuntimeException("Cannot determine the file format!");
}
}
}
這樣,您ParserService和Main類都不會依賴于您的自定義Parser實現。一旦你需要一個新的解析器,你可以簡單地定義一個實現接口的新類。不再需要更改。
更新
添加Main和AppConfig類
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConf.class);
ParsingService service = context.getBean(ParsingService.class);
for (String arg : args) {
List<Order> listOfParsedObjects = service.parse(arg);
listOfParsedObjects.forEach(System.out::println);
}
}
}
@Configuration
@ComponentScan(basePackages = "your.root.package")
public class AppConf {
// Do something here
}
對于并行處理,請嘗試Main使用以下代碼替換您的 for 循環:
Arrays.stream(args)
.parallel()
.map(service::parse)
.flatMap(List::stream)
.forEach(System.out::println);
或者您可以使用ExecutorService:
int poolSize = 3;
ExecutorService executorService = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
for (String arg : args) {
executorService.submit(() -> {
service.parse(arg).forEach(System.out::println);
});
}

TA貢獻1853條經驗 獲得超6個贊
您可能想要注入一組解析器
@Autowired
private List<Parser> parsers;
然后從該列表中選擇正確的解析器。此外,這可以通過 Map Spring Annotations - Injecting Map of Objects 來完成
您可以在解析器接口中定義方法,該方法返回擴展集合,如下所示
public interface Parser {
List<String> getExtensions();
}
然后你可以利用 Java 8 流來尋找正確的解析器:
parsers.stream().filter(p->p.getExtensions().contains(extension)).findFirst();
這將返回可能包含所需解析器的可選當您添加解析器時,您需要的是添加解析器并定義擴展。無需更改 main 中的代碼

TA貢獻1862條經驗 獲得超7個贊
我的建議是考慮使用 Spring Boot 和@ConditionalOnProperty注釋。在下面的代碼示例中,只有csvParserImpl當 的屬性my.parser值為 時才會調用 bean csv。通過將屬性值從 更改csv為json,jsonParserImpl將創建而不是csvParserImpl。如果my.parser未定義或設置為既不包含csv也不包含 的值json,則不會有 的實例Parser。
@Configuration
public class MyAutoconfiguration {
@Bean
@ConditionalOnProperty(name="my.parser", havingValue="csv")
CsvParserImpl csvParserImpl() {
return new CsvParserImpl();
}
@Bean
@ConditionalOnProperty(name="my.parser", havingValue="json")
JsonParserImpl jsonParserImpl() {
return new JsonParserImpl();
}
}
當我提到“財產”時,它在 Spring Boot 中具有特定的含義。 Spring Boot 中的外部化配置可以從多個來源拉取屬性值,包括環境變量、系統變量和命令行變量。
添加回答
舉報