我是Spring框架的新手。我开发了一个独立的控制台应用程序。应用程序将获取多个不同格式的文件(CSV,JSP,XML)作为参数。我想根据文件格式注入解析器的特定实现。
这些是我的服务
@Service
public class ParsingService {
private final Parser parser;
@Autowired
public ParsingService(Parser parser) {
this.parser = parser;
}
public List<Order> parse(String filePath) {
try {
return parser.parse(filePath);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
我的主班:
public class Main {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConf.class);
for (String arg : args) {
ParsingService service = context.getBean(ParsingService.class);
List<Order> listOfParsedObjects = service.parse(arg);
listOfParsedObjects.forEach(System.out::println);
}
}
}
我将在命令行中传递几个文件路径,我需要Spring根据文件格式注入必要的实现。
答案 0 :(得分:0)
您可能想注入解析器集合
@Autowired
private List<Parser> parsers;
然后从该列表中选择正确的解析器。 另外,通过地图可以做到 Spring Annotations - Injecting Map of Objects
您可以在解析器界面中定义方法,该方法返回扩展的集合,像这样
public interface Parser {
List<String> getExtensions();
}
然后,您可以利用Java 8流来寻找正确的解析器:
parsers.stream().filter(p->p.getExtensions().contains(extension)).findFirst();
这将返回可选的,其中可能包含所需的解析器 添加解析器时,您需要添加一个解析器并定义扩展。无需更改主代码
答案 1 :(得分:0)
我的建议是考虑使用Spring Boot和@ConditionalOnProperty
注释。在下面的代码示例中,如果csvParserImpl
的属性的值为my.parser
,将永远只有一个名为csv
的bean。通过将属性值从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();
}
}
当我指的是“财产”时,在弹簧靴中有特定含义。春季启动中的Externalized Configuration可以从多个来源提取属性值,包括环境变量,系统变量和命令行变量。
答案 2 :(得分:0)
假设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注释类或通过在config类中创建实例来配置解析器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);
});
}