spring-batch AbstractListenerFactoryBean 源码
spring-batch AbstractListenerFactoryBean 代码
文件路径:/spring-batch-core/src/main/java/org/springframework/batch/core/listener/AbstractListenerFactoryBean.java
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.core.listener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.batch.support.MethodInvoker;
import org.springframework.batch.support.MethodInvokerUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;
import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerByAnnotation;
import static org.springframework.batch.support.MethodInvokerUtils.getMethodInvokerForInterface;
/**
* {@link FactoryBean} implementation that builds a listener based on the various
* lifecycle methods or annotations that are provided. There are three possible ways of
* having a method called as part of a listener lifecycle:
*
* <ul>
* <li>Interface implementation: By implementing any of the subclasses of a listener
* interface, methods on said interface will be called
* <li>Annotations: Annotating a method will result in registration.
* <li>String name of the method to be called, which is tied to a {@link ListenerMetaData}
* value in the metaDataMap.
* </ul>
*
* It should be noted that methods obtained by name or annotation that don't match the
* listener method signatures to which they belong will cause errors. However, it is
* acceptable to have no parameters at all. If the same method is marked in more than one
* way. (i.e. the method name is given and it is annotated) the method will only be called
* once. However, if the same class has multiple methods tied to a particular listener,
* each method will be called. Also note that the same annotations cannot be applied to
* two separate methods in a single class.
*
* @author Lucas Ward
* @author Dan Garrette
* @since 2.0
* @see ListenerMetaData
*/
public abstract class AbstractListenerFactoryBean<T> implements FactoryBean<Object>, InitializingBean {
private static final Log logger = LogFactory.getLog(AbstractListenerFactoryBean.class);
private Object delegate;
private Map<String, String> metaDataMap;
@Override
public Object getObject() {
if (metaDataMap == null) {
metaDataMap = new HashMap<>();
}
// Because all annotations and interfaces should be checked for, make
// sure that each meta data
// entry is represented.
for (ListenerMetaData metaData : this.getMetaDataValues()) {
if (!metaDataMap.containsKey(metaData.getPropertyName())) {
// put null so that the annotation and interface is checked
metaDataMap.put(metaData.getPropertyName(), null);
}
}
Set<Class<?>> listenerInterfaces = new HashSet<>();
// For every entry in the map, try and find a method by interface, name,
// or annotation. If the same
Map<String, Set<MethodInvoker>> invokerMap = new HashMap<>();
boolean synthetic = false;
for (Entry<String, String> entry : metaDataMap.entrySet()) {
final ListenerMetaData metaData = this.getMetaDataFromPropertyName(entry.getKey());
Set<MethodInvoker> invokers = new HashSet<>();
MethodInvoker invoker;
invoker = getMethodInvokerForInterface(metaData.getListenerInterface(), metaData.getMethodName(), delegate,
metaData.getParamTypes());
if (invoker != null) {
invokers.add(invoker);
}
invoker = getMethodInvokerByName(entry.getValue(), delegate, metaData.getParamTypes());
if (invoker != null) {
invokers.add(invoker);
synthetic = true;
}
if (metaData.getAnnotation() != null) {
invoker = getMethodInvokerByAnnotation(metaData.getAnnotation(), delegate, metaData.getParamTypes());
if (invoker != null) {
invokers.add(invoker);
synthetic = true;
}
}
if (!invokers.isEmpty()) {
invokerMap.put(metaData.getMethodName(), invokers);
listenerInterfaces.add(metaData.getListenerInterface());
}
}
if (listenerInterfaces.isEmpty()) {
listenerInterfaces.add(this.getDefaultListenerClass());
}
if (!synthetic) {
int count = 0;
for (Class<?> listenerInterface : listenerInterfaces) {
if (listenerInterface.isInstance(delegate)) {
count++;
}
}
// All listeners can be supplied by the delegate itself
if (count == listenerInterfaces.size()) {
return delegate;
}
}
boolean ordered = false;
if (delegate instanceof Ordered) {
ordered = true;
listenerInterfaces.add(Ordered.class);
}
// create a proxy listener for only the interfaces that have methods to
// be called
ProxyFactory proxyFactory = new ProxyFactory();
if (delegate instanceof Advised) {
proxyFactory.setTargetSource(((Advised) delegate).getTargetSource());
}
else {
proxyFactory.setTarget(delegate);
}
@SuppressWarnings("rawtypes")
Class[] a = new Class[0];
proxyFactory.setInterfaces(listenerInterfaces.toArray(a));
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(new MethodInvokerMethodInterceptor(invokerMap, ordered)));
return proxyFactory.getProxy();
}
protected abstract ListenerMetaData getMetaDataFromPropertyName(String propertyName);
protected abstract ListenerMetaData[] getMetaDataValues();
protected abstract Class<?> getDefaultListenerClass();
protected MethodInvoker getMethodInvokerByName(String methodName, Object candidate, Class<?>... params) {
if (methodName != null) {
return MethodInvokerUtils.getMethodInvokerByName(candidate, methodName, false, params);
}
else {
return null;
}
}
@Override
public boolean isSingleton() {
return true;
}
public void setDelegate(Object delegate) {
this.delegate = delegate;
}
public void setMetaDataMap(Map<String, String> metaDataMap) {
this.metaDataMap = metaDataMap;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(delegate, "Delegate must not be null");
}
/**
* Convenience method to check whether the given object is or can be made into a
* listener.
* @param target the object to check
* @param listenerType the class of the listener.
* @param metaDataValues array of {@link ListenerMetaData}.
* @return true if the delegate is an instance of any of the listener interface, or
* contains the marker annotations
*/
public static boolean isListener(Object target, Class<?> listenerType, ListenerMetaData[] metaDataValues) {
if (target == null) {
return false;
}
if (listenerType.isInstance(target)) {
return true;
}
if (target instanceof Advised) {
TargetSource targetSource = ((Advised) target).getTargetSource();
if (targetSource != null && targetSource.getTargetClass() != null
&& listenerType.isAssignableFrom(targetSource.getTargetClass())) {
return true;
}
if (targetSource != null && targetSource.getTargetClass() != null
&& targetSource.getTargetClass().isInterface()) {
logger.warn(String.format(
"%s is an interface. The implementing class will not be queried for annotation based listener configurations. If using @StepScope on a @Bean method, be sure to return the implementing class so listener annotations can be used.",
targetSource.getTargetClass().getName()));
}
}
for (ListenerMetaData metaData : metaDataValues) {
if (MethodInvokerUtils.getMethodInvokerByAnnotation(metaData.getAnnotation(), target) != null) {
return true;
}
}
return false;
}
}
相关信息
相关文章
spring-batch ChunkListenerSupport 源码
spring-batch CompositeChunkListener 源码
spring-batch CompositeItemProcessListener 源码
spring-batch CompositeItemReadListener 源码
spring-batch CompositeItemWriteListener 源码
spring-batch CompositeJobExecutionListener 源码
spring-batch CompositeSkipListener 源码
spring-batch CompositeStepExecutionListener 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦