Spring mybatis mapperscannerconfigurer cannot get the value in PropertyPlaceholderConfigurer

Keywords: Spring Java xml

Because we don't want to repeat the tedious configuration bean s in xml, we use MapperScannerConfigurer to scan the package and automatically generate instances for spring management. However, it was found that the initialization of datasource failed because the value in PropertyPlaceholderConfigurer could not be obtained.

Through online search, it was found that as long as the id of SqlSessionFactoryBean was modified not to be sqlSessionFactory, it was said that if it was named sqlSessionFactory, it would trigger dataSource initialization in advance, but there was no relevant explanation for why it was so.

The status quo is that the configuration in datasource has not been replaced, so initialization fails. So we need to see when the configuration is replaced first. Let's first look at the process of spring initialization (AbstractApplicationContext):

// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();

Let's look at these relationships:

//MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor;

//PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor
public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport;
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer;
public abstract class PropertyResourceConfigurer implements BeanFactoryPostProcessor;


public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor;

Then we need to take a look at invokeBeanFactoryPostProcessors(beanFactory). Is it the BeanDefinition registered after replacing the property value first?

//other codes...
invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
//other codes...
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

Obviously, it can't be a sequence problem. Look at the error message. There is a problem from autowiredByName.

org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByName(AbstractAutowireCapableBeanFactory.java:1244) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1194) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
	... 39 common frames omitted
protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
        //propertyNames are the properties that the bean may need to inject
        //In MapperScannerConfigurer, there are sqlSessionFactory, nameGenerator, etc
		for (String propertyName : propertyNames) {
       //The point is that if SqlSessionFactoryBean is named sqlSessionFactory, the container will contain the definition of this bean
       //Then SqlSessionFactoryBean will be initialized, and if the datasource in SqlSessionFactoryBean is also named datasource
       //Then SqlSessionFactoryBean initialization will also trigger Datasource crash, which is not at the stage of configuration value replacement
			if (containsBean(propertyName)) {
				Object bean = getBean(propertyName);
				pvs.add(propertyName, bean);
				registerDependentBean(propertyName, beanName);
				
			else {
				
			}
		}
	}

So there are many solutions. Take out autowired by name, SqlSessionFactoryBean does not take sqlSessionFactory, and datasource does not take datasource.

Posted by matbennett on Thu, 23 Apr 2020 09:04:21 -0700