在使用Spring Batch时,JobExplorer作为查询浏览job以及Step的入口,可以方便的让我们及时掌握Batch的执行情况,一般会使用MapJobExplorerFactoryBean,它需要一个MapJobRepositoryFactoryBean属性,在进行xml配置时,如果配置成下面这种情况,会得到一个exception
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" >
<property name="transactionManager" ref="batchTransactionManager" />
</bean>
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean">
<property name="repositoryFactory" ref="jobRepository"/>
</bean>
Caused By: java.lang.IllegalStateException: Cannot convert value of type [$Proxy123 implementing org.springframework.batch.core.repository.JobRepository,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean] for property 'repositoryFactory': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:267)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:449)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:495)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:489)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1465)
Truncated. see log file for complete stacktrace
究其原因, MapJobRepositoryFactoryBean是一个FactoryBean接口的实现,所以在注入到MapJobExplorerFactoryBean时,得到的是getObject()返回的对象实例。
针对这个问题,我们可以将配置改为这种形式:
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean">
<property name="repositoryFactory" ref="&jobRepository"/>
</bean>
在Spring的官方文档中,关于FactoryBean有这样一段描述,注意这句“When you need to ask a container for an actual FactoryBean instance itself instead of the bean it produces, preface the bean’s id with the ampersand symbol ( &) when calling the getBean() method of the ApplicationContext”,大意是说,当通过getBean()想获得一个FactoryBean对象的实际实例时,可以在它的bean id前加上“&”符号。“&”符号在XML中应转义为&,所以,便有了上面的配置
7.8.3 Customizing instantiation logic with a FactoryBean
Implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.
The FactoryBean interface is a point of pluggability into the Spring IoC container’s instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.
The FactoryBean interface provides three methods:
Object getObject(): returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.
boolean isSingleton(): returns true if this FactoryBean returns singletons, false otherwise.
Class getObjectType(): returns the object type returned by the getObject() method or null if the type is not known in advance.
The FactoryBean concept and interface is used in a number of places within the Spring Framework; more than 50 implementations of the FactoryBean interface ship with Spring itself.
When you need to ask a container for an actual FactoryBean instance itself instead of the bean it produces, preface the bean’s id with the ampersand symbol ( &) when calling the getBean() method of the ApplicationContext. So for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container returns the product of the FactoryBean; whereas, invoking getBean("&myBean") returns the FactoryBean instance itself.
另外,通过Spring的源码,也可以看到,对这块逻辑的处理:
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException
{
final String beanName = transformedBeanName(name);
Object sharedInstance = getSingleton(beanName);
Object bean;
if ((sharedInstance != null) && (args == null)) {
if (this.logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug(new StringBuilder().append("Returning eagerly cached instance of singleton bean '").append(beanName).append("' that is not fully initialized yet - a consequence of a circular reference").toString());
}
else
{
this.logger.debug(new StringBuilder().append("Returning cached instance of singleton bean '").append(beanName).append("'").toString());
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//省略....
}
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)
{
if ((BeanFactoryUtils.isFactoryDereference(name)) && (!(beanInstance instanceof FactoryBean))) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
//BeanFactoryUtils.isFactoryDereference判断name是否以"&"开始,如果以"&"开始 返回true
if ((!(beanInstance instanceof FactoryBean)) || (BeanFactoryUtils.isFactoryDereference(name))) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null)
{
FactoryBean factory = (FactoryBean)beanInstance;
if ((mbd == null) && (containsBeanDefinition(beanName))) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null) && (mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
来源:oschina
链接:https://my.oschina.net/u/166585/blog/724270