View Javadoc

1   /*
2    * Copyright 2012-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.batch.core.configuration.annotation;
17  
18  import java.util.concurrent.atomic.AtomicReference;
19  
20  import org.aopalliance.intercept.MethodInterceptor;
21  import org.aopalliance.intercept.MethodInvocation;
22  import org.springframework.aop.framework.ProxyFactory;
23  import org.springframework.aop.target.AbstractLazyCreationTargetSource;
24  import org.springframework.batch.core.configuration.JobRegistry;
25  import org.springframework.batch.core.configuration.support.MapJobRegistry;
26  import org.springframework.batch.core.launch.JobLauncher;
27  import org.springframework.batch.core.repository.JobRepository;
28  import org.springframework.beans.factory.annotation.Autowired;
29  import org.springframework.context.ApplicationContext;
30  import org.springframework.context.annotation.Bean;
31  import org.springframework.context.annotation.Configuration;
32  import org.springframework.transaction.PlatformTransactionManager;
33  
34  /**
35   * Base {@code Configuration} class providing common structure for enabling and using Spring Batch. Customization is
36   * available by implementing the {@link BatchConfigurer} interface. The main components are created as lazy proxies that
37   * only initialize when a method is called. This is to prevent (as much as possible) configuration cycles from
38   * developing when these components are needed in a configuration resource that itself provides a
39   * {@link BatchConfigurer}.
40   *
41   * @author Dave Syer
42   * @since 2.2
43   * @see EnableBatchProcessing
44   */
45  @Configuration
46  public class SimpleBatchConfiguration extends AbstractBatchConfiguration {
47  
48  	@Autowired
49  	private ApplicationContext context;
50  
51  	private boolean initialized = false;
52  
53  	private AtomicReference<JobRepository> jobRepository = new AtomicReference<JobRepository>();
54  
55  	private AtomicReference<JobLauncher> jobLauncher = new AtomicReference<JobLauncher>();
56  
57  	private AtomicReference<JobRegistry> jobRegistry = new AtomicReference<JobRegistry>();
58  
59  	private AtomicReference<PlatformTransactionManager> transactionManager = new AtomicReference<PlatformTransactionManager>();
60  
61  	@Override
62  	@Bean
63  	public JobRepository jobRepository() throws Exception {
64  		return createLazyProxy(jobRepository, JobRepository.class);
65  	}
66  
67  	@Override
68  	@Bean
69  	public JobLauncher jobLauncher() throws Exception {
70  		return createLazyProxy(jobLauncher, JobLauncher.class);
71  	}
72  
73  	@Override
74  	@Bean
75  	public JobRegistry jobRegistry() throws Exception {
76  		return createLazyProxy(jobRegistry, JobRegistry.class);
77  	}
78  
79  	@Override
80  	@Bean
81  	public PlatformTransactionManager transactionManager() throws Exception {
82  		return createLazyProxy(transactionManager, PlatformTransactionManager.class);
83  	}
84  
85  	private <T> T createLazyProxy(AtomicReference<T> reference, Class<T> type) {
86  		ProxyFactory factory = new ProxyFactory();
87  		factory.setTargetSource(new ReferenceTargetSource<T>(reference));
88  		factory.addAdvice(new PassthruAdvice());
89  		factory.setInterfaces(new Class<?>[] { type });
90  		@SuppressWarnings("unchecked")
91  		T proxy = (T) factory.getProxy();
92  		return proxy;
93  	}
94  
95  	/**
96  	 * Sets up the basic components by extracting them from the {@link BatchConfigurer configurer}, defaulting to some
97  	 * sensible values as long as a unique DataSource is available.
98  	 *
99  	 * @throws Exception if there is a problem in the configurer
100 	 */
101 	protected void initialize() throws Exception {
102 		if (initialized) {
103 			return;
104 		}
105 		BatchConfigurer configurer = getConfigurer(context.getBeansOfType(BatchConfigurer.class).values());
106 		jobRepository.set(configurer.getJobRepository());
107 		jobLauncher.set(configurer.getJobLauncher());
108 		transactionManager.set(configurer.getTransactionManager());
109 		jobRegistry.set(new MapJobRegistry());
110 		initialized = true;
111 	}
112 
113 	private class PassthruAdvice implements MethodInterceptor {
114 
115 		@Override
116 		public Object invoke(MethodInvocation invocation) throws Throwable {
117 			return invocation.proceed();
118 		}
119 
120 	}
121 
122 	private class ReferenceTargetSource<T> extends AbstractLazyCreationTargetSource {
123 
124 		private AtomicReference<T> reference;
125 
126 		public ReferenceTargetSource(AtomicReference<T> reference) {
127 			this.reference = reference;
128 		}
129 
130 		@Override
131 		protected Object createObject() throws Exception {
132 			initialize();
133 			return reference.get();
134 		}
135 	}
136 
137 }