1、问题描述
org.springframework.context.annotation.ConfigurationClassPostProcessor enhanceConfigurationClasses
Cannot enhance @Configuration bean definition 'mybatisConfiguration' since its singleton instance has been created too early.
The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.
大致意思就是不能对加了
@Configuration
注解的MybatisConfiguration
进行增强代理,因为这个类过早实例化了。
2、解决方法
检查一下在
@Configuraion
注解的类中加了@Bean
注解的方法,看是否有类是BeanDefinitionRegistryPostProcessor
的子类,将该方法改为static
修饰的静态方法即可。作者这边是用了MapperScannerConfigurer
,后面将这个方法去掉,改为@MapperScan
注解也能解决。
3、简单分析
若
@Bean
注解的非静态方法返回的类为BeanDefinitionRegistryPostProcessor
的子类,则会导致其所在的类过早实例化。如下mapperScannerConfigurer()
方法。
package com.example.demo.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.sql.DataSource;
//@MapperScan(value = {"com.example.demo.mapper"})
@Configuration
public class MybatisConfiguration {
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=UTC");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/UserMapper.xml"));
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLogImpl(Jdk14LoggingImpl.class);
sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean;
}
// MapperScannerConfigurer 类是 BeanDefinitionRegistryPostProcessor 的子类
// 在对后置处理器 MapperScannerConfigurer 进行实例化时,会导致 MybatisConfiguration 也实例化
// 如下图
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.example.demo.mapper");
return mapperScannerConfigurer;
}
}
在
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
中实例化后置处理器MapperScannerConfigurer
实例化后置处理器
MapperScannerConfigurer
时,会先创建MybatisConfiguration
。但时在这个时候创建,它的Class
还未被代理。
打印日志时,此时
Spring
的生命周期还未到Bean
实例化的阶段,但容器中singletonObjects
已经存在MybatisConfiguration
如下图,
MybatisConfiguration
的Class
已经被代理了,那么从这里开始,MybatisConfiguration
只要等到实例化时就可创建为代理类,但是它是单例的,前面实例化一次,不会再次实例化了,也就不能被增强代理了。所以才会提示"Cannot enhance @Configuration bean definition 'mybatisConfiguration' since its singleton instance has been created too early."。