spring batch(二):核心部分(1):配置Spring batch

spring batch(二):核心部分(1):配置Spring batch

博客分类:

chapter 3、Batch configuration

1、spring batch 的命名空间

spring xml中指定batch的前缀作为命名空间。

示例:

Xml代码  

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:batch="http://www.springframework.org/schema/batch"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/batch
  8. http://www.springframework.org/schema/batch/spring-batch.xsd">
  9. <batch:job id="importProductsJob">
  10. (...)
  11. </batch:job>
  12. </beans>

当指定batch命名空间之后,bean中的声明都需要加上batch的前缀,例如:<batch:job id="importProductsJob">

spring的命名空间的前缀可以指定任意的名称,这里采用batch作为前缀,为了方便理解。

2、spring batch XML的主要标签有:job、step、tasklet、chunk、job-repository

3、Job配置。job元素是整个配置的顶级元素,它的属性有:

a、id

b、restartable

c、incrementer

d、abstract

e、parent

f、job-repository

restartable 属性如果是false,则程序不允许重启。如果发生重启,会抛出JobRestartException异常。

Java代码  

  1. <batch:job id="importProductsJob" restartable="false">
  2. (...)
  3. </batch:job>

job除了这些属性外,还可以配置验证器<batch:validator ref="parameterValidator" />,用来校验工作参数(job parameters),可以实现JobParametersValidator接口。

如果无法通过验证,会抛出JobParametersInvalidException异常。spring batch提供了一个默认的实现类DefaultJobParametersValidator,完成绝大部分的工作。如果还是无法满足需求,可以自己编码实现接口。

实例:

Java代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:validator ref="validator"/>
  4. </batch:job>
  5. <bean id="validator" class="org.springframework.batch.core.job.DefaultJobParametersValidator">
  6. <property name="requiredKeys">
  7. <set>
  8. <value>date</value>
  9. </set>
  10. </property>
  11. <property name="optionalKeys">
  12. <set>
  13. <value>productId</value>
  14. </set>
  15. </property>
  16. </bean>

4、step步骤的配置。

step的属性:

a、next

b、parent

c、abstract

示例:

Java代码  

  1. <job id="importProductsJob">
  2. <step id="decompress" next="readWrite">
  3. (...)
  4. </step>
  5. <step id="readWrite">
  6. (...)
  7. </step>
  8. </job>

5、tasklet和chunk的配置。

tasklet和chunk是用来指定处理过程的。

一个tasklet对应于一个事务性的、潜在可重复的过程中发生的一个步骤。

你可以自己实现Tasklet 接口,定义自己的tasklet。这个特性很有用,比如:用于解压文件,执行系统命令,执行存储过程等待。

你也可以使用系统tasklet的属性有:

a、ref指定应用的bean

b、transaction-manager事物管理器

c、start-limittasklet重试retry的次数

d、allow-start-if-complete如果tasklet成功完成之后,是否可以进行重试retry操作。

示例:

Java代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:step id="readWriteStep">
  4. <batch:tasklet
  5. transaction-manager="transactionManager"
  6. start-limit="3"
  7. allow-start-if-complete="true">
  8. (...)
  9. </batch:tasklet>
  10. </batch:step>
  11. </batch:job>
  12. <bean id="transactionManager" class="(...)">
  13. (...)
  14. </bean>

chunk ,ChunkOrientedTasklet 类实现类“块处理(chunk processing)”。

配置tasklet很简单,但是配置“块处理”就会复杂一点,因为它涉及的内容更多。

chunk的属性有:

a、reader

b、processor

c、writer

d、commit-interval事物提交一次处理的items的数量。也是chunk的大小。

e、skip-limit跳跃的次数

f、skip-policy跳跃的策略:要实现SkipPolicy接口

g、retry-policy重试的策略:要实现RetryPolicy接口

h、retry-limit最大的重试次数

i、cache-capacity重试的缓存策略

j、reader-transactional-queue从一个拥有事务的JMS的queue读取item数据

k、processor-transactional处理器是否包含事务处理

l、chunk-completion-policychunk的完成策略

示例:

Java代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:step id="readWrite">
  4. <batch:tasklet>
  5. <batch:chunk
  6. reader="productItemReader"
  7. processor="productItemProcessor"
  8. writer="productItemWriter"
  9. commit-interval="100"
  10. skip-limit="20"
  11. retry-limit="3"
  12. cache-capacity="100"
  13. chunk-completion-policy="timeoutCompletionPolicy"/>
  14. </batch:tasklet>
  15. </batch:step>
  16. </batch:job>
  17. <bean id="productItemReader" class="(...)">
  18. (...)
  19. </bean>
  20. <bean id="productItemProcessor" class="(...)">
  21. (...)
  22. </bean>
  23. <bean id="productItemWriter" class="(...)">
  24. (...)
  25. </bean>
  26. <bean id="timeoutCompletionPolicy"
  27. class="org.springframework.batch.repeat.policy.TimeoutTerminationPolicy">
  28. <constructor-arg value="60"/>
  29. </bean>

chunk还有几个子标签,包括:reader、processor、writer、skip-policy、retry-policy

示例:

Java代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:step id="readWrite">
  4. <batch:tasklet>
  5. <batch:chunk commit-interval="100">
  6. <batch:reader>
  7. <bean class="(...)">
  8. (...)
  9. </bean>
  10. </batch:reader>
  11. <batch:processor>
  12. <bean class="(...)">
  13. (...)
  14. </bean>
  15. </batch:processor>
  16. <batch:writer>
  17. <bean class="(...)">
  18. (...)
  19. </bean>
  20. </batch:writer>
  21. </batch:chunk>
  22. </batch:tasklet>
  23. </batch:step>
  24. </batch:job>

chunk的一些其他额外的子标签:retry-listeners、skippable-exception-classes、retryable-exception-classes、streams

示例:

Xml代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:step id="readWrite">
  4. <batch:tasklet>
  5. <batch:chunk commit-interval="100"
  6. skip-limit="10">
  7. <skippable-exception-classes>
  8. <include class="org.springframework.batch.item.file.FlatFileParseException"/>
  9. <exclude class="java.io.FileNotFoundException"/>
  10. </skippable-exception-classes>
  11. </batch:chunk>
  12. </batch:tasklet>
  13. </batch:step>
  14. </batch:job>

在chunk里面配置streams

示例:

Xml代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:step id="readWrite">
  4. <batch:tasklet>
  5. <batch:chunk reader="productItemReader" writer="compositeWriter"/>
  6. <streams>
  7. <stream ref="productItemWriter1"/>
  8. <stream ref="productItemWriter2"/>
  9. </streams>
  10. </batch:tasklet>
  11. </batch:step>
  12. </batch:job>
  13. <bean id="compositeWriter"
  14. class="org.springframework.batch.item.support.CompositeItemWriter">
  15. <property name="delegates">
  16. <list>
  17. <ref bean="productItemWriter1"/>
  18. <ref bean="productItemWriter2"/>
  19. </list>
  20. </property>
  21. </bean>

使用一个复合的stream形式,如上例的itemWriter,内部是writer1和writer2是stream的,需要在chunk里面的streams元素里面注册。

6、事务配置。

事务是spring batch的一个重要主题。主要作用于batch处理程序的健壮性,chunk处理的合并来完成它的工作。因为事务调用的对象类型不同,你可以在不同的层次配置事务。

示例:

Xml代码  

  1. <batch:job id="importProductsJob">
  2. (...)
  3. <batch:step id="readWrite">
  4. <batch:tasklet transaction-manager="transactionManager" (...)>
  5. (...)
  6. </batch:tasklet>
  7. </batch:step>
  8. </batch:job>

事务,有几个定义的属性:行为,隔离 isolation,超时 timeout。

spring batch提供transaction-attributes标签来描述这些事务的属性。

示例:

Xml代码  

  1. <batch:tasklet>
  2. <batch:chunk reader="productItemReader"
  3. writer="productItemReader"
  4. commit-interval="100"/>
  5. <batch:transaction-attributes isolation="DEFAULT"
  6. propagation="REQUIRED"
  7. timeout="30"/>
  8. </batch:chunk>
  9. </batch:tasklet>

isolation 定义数据库的隔离级别以及对外部事务的可见性。

spring的事务处理是基于java的异常体系的。java里面的异常分为两类:检查型异常(extends Exception)和非检查型异常(extends RuntimeException)

spring对检查型异常进行commit提交处理,对非检查型异常进行rollback回滚处理。

spring batch运行你对不需要触发rollback回滚动作的异常进行定义。你可以在tasklet的no-rollback-exception-class元素中进行指定。

示例:

Xml代码  

  1. <batch:tasklet>
  2. (...)
  3. <batch:no-rollback-exception-classes>
  4. <batch:include
  5. class="org.springframework.batch.item.validator.ValidationException"/>
  6. </batch:no-rollback-exception-classes>
  7. </batch:tasklet>

对于JMS,spring batch提供chunk的reader-transactional-queue 属性,提供事务处理。

7、配置job仓库

job仓库(job repository)是spring batch底层基础的一个关键特征,它为spring batch的运行提供信息。

job仓库必须实现JobRepository接口,spring batch只提供了一个具体的实现类:SimpleJobRepository。

spring batch为DAO提供了两种实现:

a、内存无持久化

b、jdbc元数据的持久化

第一种“内存无持久化”的方式可以用来spring batch的测试和开发,但是不能应用于生产环境。因为内存中的东西会丢失。

设定job仓库的参数

(1)、配置内存模式的job仓库:Configuring an in-memory job repository

示例:

Xml代码  

  1. <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
  2. <property name="transactionManager-ref" ref="transactionManager"/>
  3. </bean>
  4. <bean id="transactionManager"    class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
  5. <batch:job id="importInvoicesJob"    job-repository="jobRepository">
  6. (...)
  7. </batch:job>

由于job仓库是内存模式的,所以事务管理器采用ResourcelessTransactionManager。 这个类是NOOP (NO OPeration)无操作的PlatformTransactionManager接口实现。

(2)、持久化的job仓库:Configuring a persistent job repository

关系型数据库的job仓库的属性如下:data-source,transaction-manager,isolation-level-for-create,max-varchar-length,table-prefix,lob-handler

示例:

Xml代码  

  1. <bean id="dataSource"
  2. class="org.apache.commons.dbcp.BasicDataSource"
  3. destroy-method="close">
  4. <property name="driverClassName" value="${batch.jdbc.driver}" />
  5. <property name="url" value="${batch.jdbc.url}" />
  6. <property name="username" value="${batch.jdbc.user}" />
  7. <property name="password" value="${batch.jdbc.password}" />
  8. </bean>
  9. <bean id="transactionManager" lazy-init="true"
  10. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  11. <property name="dataSource" ref="dataSource" />
  12. </bean>
  13. <batch:job-repository id="jobRepository"
  14. data-source="dataSource"
  15. transaction-manager="transactionManager"
  16. isolation-level-for-create="SERIALIZABLE"
  17. table-prefix="BATCH_"
  18. />
  19. <batch:job id="importInvoicesJob" job-repository="jobRepository">
  20. (...)
  21. </batch:job>

[问题:如果在不同的物理节点上面运行同样的job会发生什么呢?]

前提:使用同一份spring batch的元数据,即采用同一份数据库上面的表结构。

当创建job实例和执行信息的元数据的时候,job仓库扮演了一个集中维护的工作库的角色。当job并发运行的时候,spring batch 的job仓库,可以防止创建相同的工作情况。这个功能依赖于底层数据库的事务能力,完成job的同步任务。我们设置job仓库的属性isolation-level-for-create="SERIALIZABLE",来避免发生job的并发问题。由于有这种防护措施,你可以把你的spring batch的job分布到各个不同的物理节点,保证你的job实例不会被创建两次。

job仓库是spring batch底层结构中的重要部分,它记录了batch处理的信息,并且跟踪job运行的成功与失败。

8、spring batch配置的高级主题。

(1)、使用step作用域。当使用SpEL的时候,step作用域很有用,来实现属性的晚绑定。

(2)、Spring表达式语言:Spring Expression Language (SpEL)

Spring3.× 开始提供。

step的作用的实例范围包括:jobParameters、jobExecutionContext、stepExecutionContext

示例:

Xml代码  

  1. <bean id="decompressTasklet"
  2. class="com.manning.sbia.ch01.batch.DecompressTasklet"
  3. scope="step">
  4. <property name="inputResource"
  5. value="#{jobParameters[‘inputResource‘]}" />
  6. <property name="targetDirectory"
  7. value="#{jobParameters[‘targetDirectory‘]}" />
  8. <property name="targetFile"
  9. value="#{jobParameters[‘targetFile‘]}" />
  10. </bean>

SpEL由 #{ 和 } 组成

在jobExecutionContext 和 stepExecutionContext也可以应用SpEL表达式。

(3)、使用Linteners提供的更多的处理。

Spring batch在job和step级别上面提供listener。

Spring batch提供的listener的类型:

a、Job listener:在job级别监听处理过程

b、Step listeners:在step级别监听处理过程

c、Item listeners:监听item的retry重试和repeat重做动作

一、Job listener 可以监听job的运行,在job运行前和后添加动作。可以利用 listener标签,在job标签下面作为子元素进行添加。

示例1:

Xml代码  

  1. <batch:job id="importProductsJob">
  2. <batch:listeners>
  3. <batch:listener ref="importProductsJobListener"/>
  4. </batch:listeners>
  5. </batch:job>

importProductsJobListener不管job运行成功还是失败,它都会在job运行的开始和结束的时候,接收job的通知,进行监听。

还可以通过普通的POJO的java对象来做监听器,只需要进行简单的配置即可。

示例2:

Xml代码  

  1. <batch:listeners>
  2. <batch:listener ref="importProductsJobListener" after-job-method="afterJob" before-job-method="beforeJob"/>
  3. </batch:listeners>

可以在listener里面的ref指定引用的POJO的bean,通过after-job-method="afterJob" before-job-method="beforeJob" 来指定job之前和之后的执行方法。不过,被指定的这两个方法的参数都需要是:JobExecution jobExecution。 这个2个方法的返回值都是void

还有一种方法是利用“注释”来配置listener,spring batch会自己发现并运行该类。

二、Step listener

Step有一系列的listener来跟踪step的处理过程。这里所有的listener接口都继承了StepListener接口。

Spring batch提供的Step的listener有:

a、ChunkListener:在chunk执行的之前和之后调用。

b、ItemProcessListener:在 ItemProcessor得到一个item之前和之后调用,在ItemProcessor抛出一个异常的时候调用。

c、ItemReadListener:在读取item之前和读取item之后调用,或者在读取item的过程中触发异常的时候调用。

d、ItemWriteListener:在一个item输出之前和之后调用,或者在item输出的过程中调用。

e、SkipListener:当读取、处理和输出的过程中产生了skip跳跃一个item的时候调用。

f、StepExecutionListener:在step运行之前和之后调用。

接口代码:

Java代码  

  1. public interface StepExecutionListener extends StepListener {
  2. void beforeStep(StepExecution stepExecution);
  3. ExitStatus afterStep(StepExecution stepExecution);
  4. }
  5. public interface ChunkListener extends StepListener {
  6. void beforeChunk();
  7. void afterChunk();
  8. }
  9. public interface ItemProcessListener<T, S> extends StepListener {
  10. void beforeProcess(T item);
  11. void afterProcess(T item, S result);
  12. void onProcessError(T item, Exception e);
  13. }
  14. public interface ItemReadListener<T> extends StepListener {
  15. void beforeRead();
  16. void afterRead(T item);
  17. void onReadError(Exception ex);
  18. }
  19. public interface ItemWriteListener<S> extends StepListener {
  20. void beforeWrite(List<? extends S> items);
  21. void afterWrite(List<? extends S> items);
  22. void onWriteError(Exception exception, List<? extends S> items);
  23. }
  24. public interface SkipListener<T,S> extends StepListener {
  25. void onSkipInRead(Throwable t);
  26. void onSkipInProcess(T item, Throwable t);
  27. void onSkipInWrite(S item, Throwable t);
  28. }

Step listener 作为tasklet标签的一个子标签进行配置。

上面这些所有的Step listener都可以作为tasklet标签的子标签以相同的方式和等级进行配置。

示例:

Xml代码  

  1. <bean id="importProductsJobListener"
  2. class="test.case01.java.batch.listener.job.ImportProductsJobListener" />
  3. <bean id="productStepExecutionListener"
  4. class="test.case01.java.batch.listener.step.ProductStepExecutionListener" />
  5. <bean id="productChunkListener"
  6. class="test.case01.java.batch.listener.step.chunk.ProductChunkListener" />
  7. <bean id="productItemProcessListener"
  8. class="test.case01.java.batch.listener.step.chunk.item.ProductItemProcessListener" />
  9. <batch:job id="importProducts" restartable="false">
  10. <batch:step id="readWriteProducts">
  11. <batch:tasklet>
  12. <batch:chunk reader="reader" writer="writer" processor="processor"
  13. commit-interval="100" skip-limit="5">
  14. <batch:skippable-exception-classes>
  15. <batch:include
  16. class="org.springframework.batch.item.file.FlatFileParseException" />
  17. </batch:skippable-exception-classes>
  18. </batch:chunk>
  19. <batch:listeners>
  20. <!-- here configure three kinds listeners for StepExecutionListener ,  ChunkListener , ItemProcessListener  for example.-->
  21. <batch:listener ref="productStepExecutionListener" />
  22. <batch:listener ref="productChunkListener" />
  23. <batch:listener ref="productItemProcessListener" />
  24. </batch:listeners>
  25. </batch:tasklet>
  26. </batch:step>
  27. <batch:validator ref="parameterValidator" />
  28. <batch:listeners>
  29. <batch:listener ref="importProductsJobListener" />
  30. </batch:listeners>
  31. </batch:job>

三、retry重试和repeat重做的listener

repeat listener拥有的方法名称:before、after、close(在一个item最后一次repeat重做之后调用,不管repeat成功与否)、onError、open

retry listener拥有的方法名称:close(在一个item上面最后一次尝试retry之后调用,不管retry成功与否)、onError、open

接口代码:

Java代码  

  1. public interface RepeatListener {
  2. void before(RepeatContext context);
  3. void after(RepeatContext context, RepeatStatus result);
  4. void open(RepeatContext context);
  5. void onError(RepeatContext context, Throwable e);
  6. void close(RepeatContext context);
  7. }
  8. public interface RetryListener {
  9. <T> void open(RetryContext context, RetryCallback<T> callback);
  10. <T> void onError(RetryContext context,
  11. RetryCallback<T> callback, Throwable e);
  12. <T> void close(RetryContext context,
  13. RetryCallback<T> callback, Throwable e);
  14. }

这2个接口,和上面的step listener的配置位置和方式一致,都是tasklet标签的子标签位置

四、配置继承关系

spring的XML提供配置的继承。使用abstract和parent两个属性。从一个parent的bean继承,表示该bean可以利用parent bean中的所有的属性,并且可以覆盖这些属性。

示例:

Xml代码  

  1. <bean id="parentBean" abstract="true">
  2. <property name="propertyOne" value="(...)"/>
  3. </bean>
  4. <bean id="childBean" parent="parentBean">
  5. <property name="propertyOne" value="(...)"/>
  6. <property name="propertyTwo" value="(...)"/>
  7. </bean>

这种继承关系是由spring提供的,在spring batch里面也可以使用。

listeners标签,提供merge属性,可以用来合并parent和自身的listener

示例:

Xml代码  

  1. <job id="parentJob" abstract="true">
  2. <listeners>
  3. <listener ref="globalListener"/>
  4. <listeners>
  5. </job>
  6. <job id="importProductsJob" parent="parentJob">
  7. (...)
  8. <listeners merge="true">
  9. <listener ref="specificListener"/>
  10. <listeners>
  11. </job>

spring XML的这种继承关系,使得spring batch的XML配置更简单。

时间: 2024-10-06 13:32:54

spring batch(二):核心部分(1):配置Spring batch的相关文章

(二)springcloud 集中配置-spring cloud config

setup a Config Server and then build a client that consumes the configuration on startup and then refreshes the configuration without restarting the client. config server pom.xml <?xml version="1.0" encoding="UTF-8"?> <project

[Spring实战系列](6)配置Spring IOC容器的Bean

1. 简介 Spring提供了一个强大的IOC容器来管理组成应用的bean.为了利用容器服务,必须配置运行于Spring IOC容器中的Bean. 2. 解决方案 你可以通过XML文件,属性文件,注释甚至API来设置Spring IOC容器中的Bean. Spring允许你在一个或者多个bean配置文件中配置bean.对于简单的应用程序,可以在单个配置文件中集中配置bean.但是对于有许多bean的大型应用,你应该根据其功能将其分割到多个配置文件中. 3. 创建Spring配置 正如前面所讲的,

Spring(二):AOP(面向切面编程),Spring的JDBC模板类

1 AOP概述 1.2 什么是AOP 在软件业,AOP为Aspect Oriented Programmig的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. AOP解决了OOP遇到一些问题,采取横向抽取机制,取代了传统

Spring+mybatis+struts框架整合的配置具体解释

学了非常久的spring+mybatis+struts.一直都是单个的用他们,或者是两两组合用过,今天总算整合到一起了,配置起来有点麻烦.可是配置完一次之后.就轻松多了,那么框架整合配置具体解释例如以下. 1.导入对应的jar包 由于我们建造的是maven的web项目,全部我们在pom.xml中须要导入这些包. pom.xml 具体凝视 <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&q

Spring框架的核心模块的作用

Spring框架由7个定义良好的模块(组件)组成,各个模块可以独立存在,也可以联合使用. (1)Spring Core:核心容器提供了Spring的基本功能.核心容器的核心功能是用Ioc容器来管理类的依赖关系.Spring采用的模式是调用者不理会被调用者的实例的创建,由Spring容器负责被调用者实例的创建和维护,需要时注入给调用者.这是目前最优秀的解耦模式. (2)Spring AOP:Spring的AOP模块提供了面向切面编程的支持.SpringAOP采用的是纯Java实现.Spring A

spring boot不同环境读取不同配置

具体做法: 不同环境的配置设置一个配置文件,例如:dev环境下的配置配置在application-dev.properties中:prod环境下的配置配置在application-prod.properties中. 在application.properties中指定使用哪一个文件 1.application-dev.properties(dev环境下的配置) [plain] view plain copy profile = dev_envrimont 2.application-prod.p

Spring入门(四):使用Maven管理Spring项目

让我们先回顾下本系列的前3篇博客: Spring入门(一):创建Spring项目 Spring入门(二):自动化装配bean Spring入门(三):通过JavaConfig装配bean 1.为什么要使用Maven? 之前我们新建的项目,项目所要依赖的第三方jar包都在项目的类路径下(通常为lib目录),如下所示: 使用这种方式,我们无法知道第三方类库的依赖关系,比如导入一个特定的jar包时,可能此jar包还依赖于其他的jar包,其他的jar包又依赖于更多的jar包,这也是我们平常遇到的Clas

Spring 系列,第 3 部分: 进入 Spring MVC

在 Spring 系列 的第 3 部分中,我介绍 Spring MVC 框架.就像在以前的文章中一样,我用银行示例介绍如何建模和构建简单的应用程序.示例应用程序包含了已经学过的一些技术(例如依赖注入),但是主要演示 Spring MVC 的特性. 在开始之前,请 下载这篇文章的源代码.请参阅 参考资料 访问 Spring 框架和 Tomcat 5.0,运行示例需要它们. Spring MVC 框架 Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的

深入探索spring技术内幕(二): 剖析spring管理Bean的原理与配置

求二叉树的宽度和深度 给定一个二叉树,获取该二叉树的宽度和深度. 例如输入 a / \ b c / \ / \ d e f g 返回3. 详细描述: 接口说明 原型: int GetBiNodeInfo(BiNode &head, unsigned int *pulWidth, unsigned int *pulHeight) 输入参数: head 需要获取深度的二叉树头结点 输出参数(指针指向的内存区域保证有效): pulWidth 宽度 pulHeight 高度 返回值: 0 成功 1 失败