甘肃网站设计公司,云南省建设工作网站,阿里网站导航怎么做的,一个网页设计大概多少钱代理模式和动态代理模式代表#xff1a;被选中或当选为他人投票或代理的人– Merriam-Webster 。 委托模式#xff1a;在软件工程中#xff0c;委托模式是面向对象编程中的一种设计模式#xff0c;其中#xff0c;一个对象而不是执行其陈述的任务之一#xff0c;而是将该… 代理模式和动态代理模式 代表被选中或当选为他人投票或代理的人– Merriam-Webster 。 委托模式在软件工程中委托模式是面向对象编程中的一种设计模式其中一个对象而不是执行其陈述的任务之一而是将该任务委托给一个关联的辅助对象Wikipedia 。 使事情尽可能简单但不要简单- 爱因斯坦 Albert Einstein释义 。 Spring Batch是Enterprise Java工具箱中的重要工具。 它提供了开箱即用的强大功能尤其是从不同来源读取和写入数据时。 我们在此博客中提供了几篇介绍Spring Batch的文章。 如果您不熟悉Spring Batch和ReaderProcessorWriter Tasklet请花点时间回顾一下。 我上面使用的措辞对我来说很重要。 我尝试做的一件事就是保持我提供的代码尽可能可维护。 我希望它能正常工作但是我今天签入的代码将在以后某个日期由某些人维护。 保持代码尽可能简单是确保代码易于维护的一种方法。 那么当您必须处理复杂的数据源时会发生什么呢 我们发现经常需要处理的输入文件并不像每行一个记录那么简单。 通常文件中有多行描述一个记录。 例如 HKaren Traviss
LAB00KW3VG2G
LI0345478274
LI0345511131
F00000003
HJim Butcher
LI0451457811
F00000001
HDave Duncan
LI0380791277
LI0345352912
F00000002
HRik Scarborough
LI9999999999
F00000001 在这里我们有一个文件其中包含十五行中的四个记录。 每条记录均以页眉行开头包含一个或多个正文行并以页脚结尾。 标头包含线型标头为H和名称。 该行还包含线型L查找类型在此示例中为ISBN或Amazon代码以及查找书本的键。 页脚再次包含线型和此块中的记录数。 使用标准的读取器将读取每一行然后传递给处理器然后处理器必须确定处理的是哪种类型的行。 然后处理器在处理每个正文行时必须保留每个标头中的信息直到处理了页脚。 然后编写者将必须知道处理器发送的每一行以及是否应将其写入。 这在某种程度上很复杂因为多个对象必须知道如何读取文件而不是处理器只关心单个对象而编写器只关心编写给定的对象。 相反让我们将Delegate模式引入Reader并让其处理创建整个记录的过程。 由于我们具有来自多行的信息以及用于创建每条记录的页眉和页脚因此我们将必须向处理者传递记录列表。 你们当中的观察者会注意到每个记录都包含一个ISBN或Amazon图书符号并且可以用来查找作者也包含在标题中。 在现实生活中这种冗余可能也不会发生。 让我们将输出包装在另一个对象中以使其更易于使用。 public class OrderReaderStep implements ItemReaderOrderList {private static final Logger logger LoggerFactory.getLogger(OrderReaderStep.class);private FlatFileItemReader
FieldSet delegate;private static final String FOOTER F*;private static final String BODY L*;private static final String HEADER H*;BeforeSteppublic void beforeStep(StepExecution stepExecution) {delegate new FlatFileItemReader();delegate.setResource(new ClassPathResource(orders.txt));final DefaultLineMapper
FieldSet defaultLineMapper new DefaultLineMapper();final PatternMatchingCompositeLineTokenizer orderFileTokenizer new PatternMatchingCompositeLineTokenizer();final MapString, LineTokenizer tokenizers new HashMap();tokenizers.put(HEADER, buildHeaderTokenizer());tokenizers.put(BODY, buildBodyTokenizer());tokenizers.put(FOOTER, buildFooterTokenizer());orderFileTokenizer.setTokenizers(tokenizers);defaultLineMapper.setLineTokenizer(orderFileTokenizer);defaultLineMapper.setFieldSetMapper(new PassThroughFieldSetMapper());delegate.setLineMapper(defaultLineMapper);delegate.open(stepExecution.getExecutionContext());}AfterSteppublic void afterStep(StepExecution stepExecution) {delegate.close();}Overridepublic OrderList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {logger.info(start read);OrderList record null;FieldSet line;ListOrder bodyList new ArrayList();while ((line delegate.read()) ! null) {String prefix line.readString(lineType);if (prefix.equals(H)) {record new OrderList();record.setName(line.readString(name));} else if (prefix.equals(L)) {Order order new Order();order.setLookup(line.readString(lookupKey));order.setLookupType(line.readString(keyType));bodyList.add(order);} else if (prefix.equals(F)) {if (record ! null) {if (line.readLong(count) ! bodyList.size()) {throw new ValidationException(Size does not match file count);}record.setOrders(bodyList);}break;}}logger.info(end read);return record;}private LineTokenizer buildBodyTokenizer() {FixedLengthTokenizer tokenizer new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 2), // keyTypenew Range(3, 12) // lookup key});tokenizer.setNames(new String[]{ //lineType,keyType,lookupKey}); //tokenizer.setStrict(false);return tokenizer;}private LineTokenizer buildFooterTokenizer() {FixedLengthTokenizer tokenizer new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 9) // count});tokenizer.setNames(new String[]{ //lineType,count}); //tokenizer.setStrict(false);return tokenizer;}private LineTokenizer buildHeaderTokenizer() {FixedLengthTokenizer tokenizer new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 20), // name});tokenizer.setNames(new String[]{ //lineType,name}); //tokenizer.setStrict(false);return tokenizer;}} 此Reader实现ItemReader接口。 这为我们提供了一个由作业调用的read方法直到它返回null或发生错误时引发异常。 在我们的Reader中我们声明另一个Reader这是一个FlatFileItemReader。 这是我们的代表即为我们执行功能所选择的对象。 我们的read方法将以委托的读取为循环直到读取Footer。 然后它将整个记录捆绑到其包装器中并将其传递给处理器。 必须先打开委托阅读器然后才完成使用。 我必须在此处将它初始化并在此处进行设置因此在BeforeStep中在此处打开它。 我也可以将包含的阅读器实现为ItemStreamReader并使用Interface给我们的openclose以及update方法。 将简化的对象返回给Processor可以使我们大大简化Processor Override
public ListBookList process(OrderList orderList) throws Exception {logger.info(process);ListBookList books new ArrayList();for (Order order : orderList.getOrders()) {BookList bl doProcessing(orderList.getName(), order);books.add(bl);}return books;
} doProcessing方法可以包含此Job的业务逻辑并且需要创建一个有效的BookList对象。 由于我们正在处理多个记录因此该过程将创建多个可返回的BookList并将其传递给Writer。 我将留给您填写该对象的其余部分但这只是一个标准的ItemProcessor。 处理器不必在调用之间保留记录信息因此程序员可以专注于业务逻辑。 我们的编写器实现ItemStreamWriter。 这给我们提供了比ItemWriter更多的方法但是如果您希望像使用Reader一样使用ItemWriter请确保在BeforeStep中打开Delegate在AfterStep中将其关闭。 在Writer中使用委托使我们能够遍历Writer从Reader和Process收到的List。 public class ListWriter implements ItemStreamWriterListBookList {private static final Logger logger LoggerFactory.getLogger(ListWriter.class);private FlatFileItemWriterBookList delegate;BeforeSteppublic void beforeStep(StepExecution stepExecution) {delegate new FlatFileItemWriter();delegate.setResource(new FileSystemResource(booklist.csv));delegate.setShouldDeleteIfEmpty(true);delegate.setAppendAllowed(true);DelimitedLineAggregatorBookList dla new DelimitedLineAggregator();dla.setDelimiter(,);BeanWrapperFieldExtractorBookList fieldExtractor new BeanWrapperFieldExtractor();fieldExtractor.setNames(new String[]{bookName, author});dla.setFieldExtractor(fieldExtractor);delegate.setLineAggregator(dla);}Overridepublic void close() throws ItemStreamException {delegate.close();}Overridepublic void open(ExecutionContext ec) throws ItemStreamException {delegate.open(ec);}Overridepublic void update(ExecutionContext ec) throws ItemStreamException {delegate.update(ec);}Overridepublic void write(List? extends ListBookList list) throws Exception {logger.info(write);for (ListBookList bookList : list) {delegate.write(bookList);}}} 这为我们提供了以下输出 Going Grey,Karen Traviss
Hard Contact,Karen Traviss
501st,Karen Traviss
Storm Front,Jim Butcher
Lord of the Fire Lands,Dave Duncan
The Reluctant Swordsman,Dave Duncan
Wolfbrander Series Unpublished,Rik Scarborough 那么如果稍微复杂一点并且输入文件不包含页脚会发生什么呢 逻辑记录仍然从标题行开始但在下一个标题之前的行结束。 在我们之前的示例中系统必须先读取下一行然后才能知道该行已完成然后具有一些复杂的逻辑来保留该信息以用于下一轮。 HKaren Traviss
LAB00KW3VG2G
LI0345478274
LI0345511131
HJim Butcher
LI0451457811
HDave Duncan
LI0380791277
LI0345352912
HRik Scarborough
LI9999999999 让我们当前的作者提前阅读并在下一次通话时保留该记录是不必要的复杂操作这会导致维护麻烦。 但是我们可以使用PeekableItemReader简化此过程 class OrderReaderStep2 implements ItemStreamReaderOrderList {private static final String BODY L*;private static final String HEADER H*;private static final Logger logger LoggerFactory.getLogger(OrderReaderStep2.class);private SingleItemPeekableItemReader
FieldSet delegate;BeforeSteppublic void beforeStep(StepExecution stepExecution) {FlatFileItemReader fileReader new FlatFileItemReader();fileReader.setResource(new ClassPathResource(orders2.txt));final DefaultLineMapper
FieldSet defaultLineMapper new DefaultLineMapper();final PatternMatchingCompositeLineTokenizer orderFileTokenizer new PatternMatchingCompositeLineTokenizer();final MapString, LineTokenizer tokenizers new HashMap();tokenizers.put(HEADER, buildHeaderTokenizer());tokenizers.put(BODY, buildBodyTokenizer());orderFileTokenizer.setTokenizers(tokenizers);defaultLineMapper.setLineTokenizer(orderFileTokenizer);defaultLineMapper.setFieldSetMapper(new PassThroughFieldSetMapper());fileReader.setLineMapper(defaultLineMapper);delegate new SingleItemPeekableItemReader();delegate.setDelegate(fileReader);}Overridepublic void close() throws ItemStreamException {delegate.close();}Overridepublic void open(ExecutionContext ec) throws ItemStreamException {delegate.open(ec);}Overridepublic OrderList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {logger.info(start read);OrderList record null;FieldSet line;ListOrder bodyList new ArrayList();while ((line delegate.read()) ! null) {String prefix line.readString(lineType);if (prefix.equals(H)) {record new OrderList();record.setName(line.readString(name));} else if (prefix.equals(L)) {Order order new Order();order.setLookup(line.readString(lookupKey));order.setLookupType(line.readString(keyType));bodyList.add(order);}FieldSet nextLine delegate.peek();if (nextLine null || nextLine.readString(lineType).equals(H)) {record.setOrders(bodyList);break;}}logger.info(end read);return record;}Overridepublic void update(ExecutionContext ec) throws ItemStreamException {delegate.update(ec);}private LineTokenizer buildBodyTokenizer() {FixedLengthTokenizer tokenizer new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 2), // keyTypenew Range(3, 12) // lookup key});tokenizer.setNames(new String[]{ //lineType,keyType,lookupKey}); //tokenizer.setStrict(false);return tokenizer;}private LineTokenizer buildHeaderTokenizer() {FixedLengthTokenizer tokenizer new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 20), // name});tokenizer.setNames(new String[]{ //lineType,name}); //tokenizer.setStrict(false);return tokenizer;}} 这次我确实将包含的Reader实现为ItemStreamReader以向您展示它们之间的区别。 可以像上一个一样将其实现为ItemReader。 PeekableItemReader允许我们向前查看下一条记录以查看是否到达记录的末尾或文件的末尾。 然后可以使用相同的Processor和Writer来产生与以前相同的输出。 最后的想法 乍一看委托模式似乎不像使用单个读取器或写入器那么简单。 这两个对象都有更多的配置。 但是我最喜欢的释义是说要尽可能简单而且再简单不过。 稍微复杂一点的Reader和Writer将使您的Processor更加简单并有助于进行后续维护。 代码很好我的朋友。 翻译自: https://www.javacodegeeks.com/2016/03/introducing-delegate-pattern.html代理模式和动态代理模式