在使用Spring Batch时,JobExplorer做为查询浏览job以及Step的入口,能够方便的让咱们及时掌握Batch的执行状况,通常会使用MapJobExplorerFactoryBean,它须要一个MapJobRepositoryFactoryBean属性,在进行xml配置时,若是配置成下面这种状况,会获得一个exceptionjava
<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()返回的对象实例。spring
针对这个问题,咱们能够将配置改成这种形式:express
<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中应转义为&,因此,便有了上面的配置app
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的源码,也能够看到,对这块逻辑的处理:ide
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; }