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 中的外部化配置可以从多个来源拉取属性值,包括环境变量、系统变量和命令行变量。
添加回答
举报