使用内存中元数据的Spring批处理执行时间

时间:2016-02-19 06:42:20

标签: java spring spring-batch

我是Spring批处理的新手,我正在尝试使用具有可重启功能的Spring Batch。我使用MapJobRepositoryFactoryBean作为Job存储库。一切都很好看。但是当我多次运行相同的工作时,我可以看到执行时间大大增加。我想有些内存泄​​漏正在发生。如果没有工作正在运行,我也在清理存储库。但没有运气。我怎么知道到底发生了什么?在运行相同的作业4-5次后,执行时间将是第一次执行的2-3倍。

<jpa:repositories base-package=".reference.data.repository"/>
<context:annotation-config />

<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="validator" 
       class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
    <property name="url"
        value="jdbc:sqlserver://${reference-data-manager.database.hostname}:
        ${reference-data-manager.database.port};
        database=${reference-data-manager.database.name};
        user=${reference-data-manager.database.username};
        password=${reference-data-manager.database.password}" />
</bean> 

<bean id="simpleJobConfiguration" class="reference.job.SimpleJobConfiguration">
</bean>

<bean id="emf"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf" />
</bean>

<bean id="importJob" class="org.springframework.batch.core.job.SimpleJob" scope="prototype">
    <property name="jobRepository" ref="jobRepository"></property>

</bean>

  <batch:step id="importCodesStep">
    <batch:tasklet allow-start-if-complete="true">
        <batch:chunk reader="codeMappingReader" writer="codeMappingWriter" 
                          processor="codeMappingProcessor" commit-interval="${reference-data-manager.batch.size}" 
                          skip-policy="reasonRemarkAssnSkipPolicy" skip-limit="${reference-data-manager.skip.limit}">
            <batch:skippable-exception-classes>
                <batch:include class="org.springframework.batch.item.ParseException"/>
            </batch:skippable-exception-classes>
        </batch:chunk>
    </batch:tasklet>        
    <batch:listeners>
        <batch:listener ref="reasonRemarkAssnStepListener"/>
        <batch:listener ref="reasonRemarkAssnSkipListener"/>            
    </batch:listeners>
  </batch:step>

<bean id="reasonRemarkAssnStepListener" class="reference.listeners.ReasonRemarkAssnStepListener">
</bean>

<bean id="reasonRemarkAssnSkipListener" class="reference.listeners.ReasonRemarkAssnSkipListener">
</bean>

<bean id="reasonRemarkAssnSkipPolicy" class="reference.listeners.ReasonRemarkAssnSkipPolicy">
    <!-- <property name="skipLimit" value="5"/> -->
</bean>

<bean id="codeMappingWriter" class="reference.writer.ReasonRemarkAssnWriter" scope="step">
    <property name="entityManagerFactory" ref="emf" />
</bean>

<bean id="codeMappingProcessor" class="reference.processors.ReasonRemarkAssnProcessor" scope="step">
    <property name="userId" value="#{jobParameters['USER_ID']}" />
    <property name="clientMnemonic" value="#{jobParameters['CLIENT_MENOMONIC']}" />
</bean>

<bean id="codeMappingReader" class="reference.readers.ReasonRemarkAssnReader" scope="step">

    <property name="org" value="#{jobParameters['ORG']}"/>  
    <property name="resource" value="" />
    <property name="linesToSkip" value="1" />

    <property name="lineMapper">
        <bean class="reference.mapper.ReasonRemarkAassnLineMapper">

            <property name="lineTokenizer">
                <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                    <property name="names" value="Reason Code,Remark Code,Category,Category Priority,Ignore Insight Processing,Active,Comment" />
                </bean>
            </property>

            <property name="fieldSetMapper" ref="reasonRemarkAssnMapper"/>
        </bean>
    </property>
</bean>
<bean id="reasonRemarkAssnMapper" class="reference.mapper.ReasonRemarkAssnMapper">
    <property name="codeGroups" value="${reference-data-manager.code.groups}"></property>
</bean>

<bean id="jobRepository"
    class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">      
</bean>

<bean id="jobLauncher"
    class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
</bean>

<bean class="CryptoPropertyPlaceholderConfigurer">
    <property name="configUtil" ref="configUtil" />
    <property name="location"
        value="file:config/reference-data-manager.conf" />
    <property name="ignoreResourceNotFound" value="true" />
    <property name="ignoreUnresolvablePlaceholders" value="true" />     
</bean>

<bean name="configUtil" class="CoreConfigUtil">
    <property name="crypto" ref="crypto" />
</bean>

<bean id="referenceDataManager" class="reference.service.impl.ReferenceDataManagerImpl">
    <property name="step" ref="importCodesStep"></property>
</bean>

这是我的工作调用......

@RestfulServiceAddress( “/参考”) 公共类ReferenceDataManagerImpl实现ReferenceDataManager {

@Autowired
private JobLauncher jobLauncher;    

@Autowired
IDataAccessService dataAccessService;

@Autowired
private IConfigurationServiceFactory configurationServiceFactory;

@Autowired
private SimpleJob job;

@Autowired
private TaskletStep step;

@Autowired
private SimpleJobConfiguration jobConfiguration;

@Autowired
private MapJobRepositoryFactoryBean jobRepository;  

@Override
public Response importData(MultipartBody input, String org,
        String userId, MessageContext mc) throws ServiceFault {
    Response.ResponseBuilder builder = null;
    ReasonRemarkAssnResponse responseObj = null;
    boolean isSuccess = false;
    UserInfo userInfo=  dataAccessService.userInfoFindByUserId(userId);
    JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();

    List<Attachment> attachments = input.getAllAttachments();
    DataHandler dataHandler = attachments.get(0).getDataHandler();
    byte[] bFile = null;
    if(null != dataHandler){

        try {
            InputStream is = dataHandler.getInputStream();  
            bFile = new byte[is.available()];
            is.read(bFile);
            is.close(); 
        } catch (IOException e) {
            //TODO
        } 
    }

    SimpleJobConfiguration.customStorage.put(org, bFile);


    jobParametersBuilder.addLong(ReferenceConstants.JOB_PARAMS_USERID, userInfo.getId());
    jobParametersBuilder.addString(ReferenceConstants.JOB_PARAMS_ORG, org);
    jobParametersBuilder.addString(ReferenceConstants.JOB_PARAMS_TIME, Calendar.getInstance().getTime().toString());
    String response = "{error:Error occured while importing the file}";

    job.setName(ReferenceConstants.JOB_PARAMS_JOB_NAME_PREFIX+org.toUpperCase());
    job.addStep(step);
    job.setRestartable(true);       
    JobExecution execution = null;
    try {
        execution = jobLauncher.run(job, jobParametersBuilder.toJobParameters());
        isSuccess = true;

    } catch (JobExecutionAlreadyRunningException e) {
        //TODO
    }catch (JobRestartException e) {
        //TODO
    }catch (JobInstanceAlreadyCompleteException e) {
        //TODO
    }catch (JobParametersInvalidException e) {
        //TODO
    }

    response = prepareResponse(responseObj); 

    synchronized (SimpleJobConfiguration.customStorage){
        if(null != SimpleJobConfiguration.customStorage.get(org)){
            SimpleJobConfiguration.customStorage.remove(org);
        }
        if(SimpleJobConfiguration.customStorage.isEmpty()){
            jobRepository.clear();
        }
    }

    builder = Response.status(Response.Status.OK);
    builder.type(MediaType.APPLICATION_JSON);       
    builder.entity(response);

    return builder.build();
}   

}

1 个答案:

答案 0 :(得分:0)

  1. 除非用于测试,否则请勿使用MapJobRepositoryFactoryBean。这就是它的全部目的。
  2. 每次调用控制器时都不应构建新的Job实例。如果步骤中有状态组件,请将它们声明为步骤范围,以便每步执行一个新实例。
  3. 基于Map的{​​{1}}会将所有内容保存在内存中。这就是主意。因此,当您执行越来越多的工作时,存储库将会增长......在内存中占用您的空间。
  4. 要在控制器中启动作业,请尝试尝试这样的事情:

    JobRepository