Java 春天如何根据应用程序参数注入依赖关系?
我是Spring框架的新手。我开发了一个独立的控制台应用程序。应用程序将获得几个不同格式的文件(CSV、JSP、XML)作为参数。我想根据文件格式注入解析器的特定实现 这是我的服务:Java 春天如何根据应用程序参数注入依赖关系?,java,spring,Java,Spring,我是Spring框架的新手。我开发了一个独立的控制台应用程序。应用程序将获得几个不同格式的文件(CSV、JSP、XML)作为参数。我想根据文件格式注入解析器的特定实现 这是我的服务: @Service public class ParsingService { private final Parser parser; @Autowired public ParsingService(Parser parser) { this.parser = parser; } public L
@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;
}
}
@服务
公共类ParsingService{
私有最终解析器;
@自动连线
公共ParsingService(解析器){
this.parser=解析器;
}
公共列表解析(字符串文件路径){
试一试{
返回parser.parse(文件路径);
}捕获(IOE异常){
e、 printStackTrace();
}
返回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);
}
}
}
公共类主{
公共静态void main(字符串[]args)引发IOException{
AnnotationConfigApplicationContext上下文=新的AnnotationConfigApplicationContext(AppConf.class);
for(字符串arg:args){
ParsingService=context.getBean(ParsingService.class);
ListListofParseObject=service.parse(arg);
forEach(System.out::println)的parsedobjects.forEach列表;
}
}
}
我将向命令行传递几个文件路径,我需要Spring根据文件格式注入必要的实现。您可能需要注入一组解析器
@Autowired
private List<Parser> parsers;
这将返回可能包含所需解析器的可选
添加解析器时,需要添加解析器并定义扩展。不需要在主< /p> 中更改代码。我的建议是考虑使用Spring Bug和<代码> @ Tealalon属性< /COD>注释。在下面的代码示例中,如果
my.parser
的属性值为csv
,则只有名为csvParserImpl
的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();
}
}
当我提到“属性”时,它在SpringBoot中有一个特定的含义。在spring boot中,可以从多个源中提取属性值,包括环境变量、系统变量和命令行变量。假设
解析器是您自己的接口,您可以添加一个方法,告诉它能够解析的格式:
public interface Parser {
List<Order> parse(String filePath);
String getFormat();
}
通过使用@Bean/@Component注释类或在配置类中创建实例来配置解析器Bean。(如果您使用的是SpringBoot,我建议您使用@ConditionalOn…
注释,以避免创建不必要的bean)
现在,您可以将所有解析器
实例注入解析器服务
@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!");
}
}
}
对于并行处理,请尝试将Main
中的For循环替换为以下代码:
Arrays.stream(args)
.parallel()
.map(service::parse)
.flatMap(List::stream)
.forEach(System.out::println);
或者您可以使用执行器服务
:
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);
});
}
intpoolsize=3;
ExecutorService ExecutorService=new ThreadPoolExecutor(池大小、池大小、0L、时间单位为毫秒,
新建LinkedBlockingQueue());
for(字符串arg:args){
executorService.submit(()->{
service.parse(arg.forEach(System.out::println);
});
}
解析器是您自己的类/接口吗?@ETO是的,它是我的接口您可以在单独的帖子中找到我的解决方案谢谢您的回答。在这种情况下,我只需要从上下文范围中获取必要的解析器,而不需要服务?我只需要检查文件格式并执行context.getBean(parserIml.class).parse()。但我需要更方便的解决方案,我可以创建新的实现并注入它,而不改变主方法。但我会试试你的解决办法。但是首先我需要了解如何使用Spring Boot=)您的解决方案看起来很有趣,我一定会尝试。添加了Main
和AppConfig
谢谢,这个解决方案很好用。但我还有一个问题。如何在并发状态下执行此应用程序。所以,我想传递文件路径数组,应用程序应该在几个线程中解析它。
@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!");
}
}
}
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
}
Arrays.stream(args)
.parallel()
.map(service::parse)
.flatMap(List::stream)
.forEach(System.out::println);
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);
});
}