001/* 002 * Copyright 2012-2013 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.springframework.batch.core.configuration.annotation; 017 018import org.aopalliance.intercept.MethodInterceptor; 019import org.aopalliance.intercept.MethodInvocation; 020import org.springframework.aop.framework.ProxyFactory; 021import org.springframework.aop.target.AbstractLazyCreationTargetSource; 022import org.springframework.batch.core.configuration.JobRegistry; 023import org.springframework.batch.core.configuration.support.MapJobRegistry; 024import org.springframework.batch.core.explore.JobExplorer; 025import org.springframework.batch.core.launch.JobLauncher; 026import org.springframework.batch.core.repository.JobRepository; 027import org.springframework.beans.factory.annotation.Autowired; 028import org.springframework.context.ApplicationContext; 029import org.springframework.context.annotation.Bean; 030import org.springframework.context.annotation.Configuration; 031import org.springframework.transaction.PlatformTransactionManager; 032 033import java.util.concurrent.atomic.AtomicReference; 034 035/** 036 * Base {@code Configuration} class providing common structure for enabling and using Spring Batch. Customization is 037 * available by implementing the {@link BatchConfigurer} interface. The main components are created as lazy proxies that 038 * only initialize when a method is called. This is to prevent (as much as possible) configuration cycles from 039 * developing when these components are needed in a configuration resource that itself provides a 040 * {@link BatchConfigurer}. 041 * 042 * @author Dave Syer 043 * @since 2.2 044 * @see EnableBatchProcessing 045 */ 046@Configuration 047public class SimpleBatchConfiguration extends AbstractBatchConfiguration { 048 049 @Autowired 050 private ApplicationContext context; 051 052 private boolean initialized = false; 053 054 private AtomicReference<JobRepository> jobRepository = new AtomicReference<JobRepository>(); 055 056 private AtomicReference<JobLauncher> jobLauncher = new AtomicReference<JobLauncher>(); 057 058 private AtomicReference<JobRegistry> jobRegistry = new AtomicReference<JobRegistry>(); 059 060 private AtomicReference<PlatformTransactionManager> transactionManager = new AtomicReference<PlatformTransactionManager>(); 061 062 private AtomicReference<JobExplorer> jobExplorer = new AtomicReference<JobExplorer>(); 063 064 @Override 065 @Bean 066 public JobRepository jobRepository() throws Exception { 067 return createLazyProxy(jobRepository, JobRepository.class); 068 } 069 070 @Override 071 @Bean 072 public JobLauncher jobLauncher() throws Exception { 073 return createLazyProxy(jobLauncher, JobLauncher.class); 074 } 075 076 @Override 077 @Bean 078 public JobRegistry jobRegistry() throws Exception { 079 return createLazyProxy(jobRegistry, JobRegistry.class); 080 } 081 082 @Override 083 @Bean 084 public JobExplorer jobExplorer() { 085 return createLazyProxy(jobExplorer, JobExplorer.class); 086 } 087 088 @Override 089 @Bean 090 public PlatformTransactionManager transactionManager() throws Exception { 091 return createLazyProxy(transactionManager, PlatformTransactionManager.class); 092 } 093 094 private <T> T createLazyProxy(AtomicReference<T> reference, Class<T> type) { 095 ProxyFactory factory = new ProxyFactory(); 096 factory.setTargetSource(new ReferenceTargetSource<T>(reference)); 097 factory.addAdvice(new PassthruAdvice()); 098 factory.setInterfaces(new Class<?>[] { type }); 099 @SuppressWarnings("unchecked") 100 T proxy = (T) factory.getProxy(); 101 return proxy; 102 } 103 104 /** 105 * Sets up the basic components by extracting them from the {@link BatchConfigurer configurer}, defaulting to some 106 * sensible values as long as a unique DataSource is available. 107 * 108 * @throws Exception if there is a problem in the configurer 109 */ 110 protected void initialize() throws Exception { 111 if (initialized) { 112 return; 113 } 114 BatchConfigurer configurer = getConfigurer(context.getBeansOfType(BatchConfigurer.class).values()); 115 jobRepository.set(configurer.getJobRepository()); 116 jobLauncher.set(configurer.getJobLauncher()); 117 transactionManager.set(configurer.getTransactionManager()); 118 jobRegistry.set(new MapJobRegistry()); 119 jobExplorer.set(configurer.getJobExplorer()); 120 initialized = true; 121 } 122 123 private class PassthruAdvice implements MethodInterceptor { 124 125 @Override 126 public Object invoke(MethodInvocation invocation) throws Throwable { 127 return invocation.proceed(); 128 } 129 130 } 131 132 private class ReferenceTargetSource<T> extends AbstractLazyCreationTargetSource { 133 134 private AtomicReference<T> reference; 135 136 public ReferenceTargetSource(AtomicReference<T> reference) { 137 this.reference = reference; 138 } 139 140 @Override 141 protected Object createObject() throws Exception { 142 initialize(); 143 return reference.get(); 144 } 145 } 146 147}