說明
目前在營運一個個人的公衆号, 感興趣可以掃碼關注, 一起成長吧.

今天想把ssm架構整合後的xml檔案都去掉, 因為看到配置檔案中需要配置一個Bean去掃描全部的mapper接口.
xml中配置如下:
<!-- 掃描所有mapper接口檔案 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.incisor.dao"/>
</bean>
&emps;修改成零配置方式後, 就想着用@Bean來建立一個MapperScannerConfigurer的對象.
Java Config類如下:
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
/**
* ClassName: AppConfig
* Author: zhoubihui
* Date: 2019-08-29 17:53
* Version: 1.0
* Description: 替換applicationContext.xml
**/
@Configuration
@ComponentScan(basePackages = {"cn.incisor.service"})
@PropertySource(value = "classpath:jdbc.properties")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
public DruidDataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean getSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return sqlSessionFactory;
}
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer(){
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("cn.incisor.dao");
return mapperScannerConfigurer;
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager getTransactionManager(@Qualifier("dataSource") DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
運作時, 一直提示錯誤, debug後發現, @Value無法注入properties檔案裡的值到對應屬性中.
首先我先排除properties檔案沒加載進來, 打了debug跟蹤properties檔案的加載過程, 發現是成功加載了的, 然後我又去看了@Value的源碼, 也沒找到什麼問題出來.
然後繼續google, 終于被我找到一篇類似的文章. 參考文檔, 感興趣的可以深入的看看這個部落客的部落格, 根據這位部落客所說的, 是因為這個類MapperScannerConfigurer實作BeanDefinitionRegistryPostProcessor接口, 導緻後續spring容器執行的一些問題,我對源碼看的還不深,是以我就直接按照結論修改了.
package cn.incisor.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
/**
* ClassName: AppConfig
* Author: zhoubihui
* Date: 2019-08-29 17:53
* Version: 1.0
* Description: 替換applicationContext.xml
**/
@Configuration
@ComponentScan(basePackages = {"cn.incisor.service"})
@PropertySource(value = "classpath:jdbc.properties")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class AppConfig {
@Configuration
static class DbConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
public DruidDataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean getSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return sqlSessionFactory;
}
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer(){
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("cn.incisor.dao");
return mapperScannerConfigurer;
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager getTransactionManager(@Qualifier("dataSource") DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
這樣修改之後, 倒是不報錯了, 接口通路也沒有問題, 但看控制台日志列印時, 看到一句話:
21:40:19.877 [RMI TCP Connection(2)-127.0.0.1] INFO org.springframework.context.annotation.ConfigurationClassPostProcessor -
Cannot enhance @Configuration bean definition 'appConfig' 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'.
照這個提示來看, 還是MapperScannerConfigurer這個Bean有問題, 應該不是這麼設定的, 是以又找文檔, 最後找到一個注解@MapperScan, 這個注解就是用來替換掃描mapper接口的配置的, 加上這個注解後, MapperScannerConfigurer這個Bean就不用我們手動建立了, 可以去掉這個方法了, 也可以把靜态内部類去掉了.
package cn.incisor.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.IOException;
/**
* ClassName: AppConfig
* Author: zhoubihui
* Date: 2019-08-29 17:53
* Version: 1.0
* Description: 替換applicationContext.xml
**/
@Configuration
@ComponentScan(basePackages = {"cn.incisor.service"})
@PropertySource(value = "classpath:jdbc.properties")
@MapperScan(basePackages = "cn.incisor.dao")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
public DruidDataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setMaxActive(maxActive);
dataSource.setInitialSize(initialSize);
dataSource.setMinIdle(minIdle);
dataSource.setMaxWait(maxWait);
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
dataSource.setValidationQuery(validationQuery);
dataSource.setTestWhileIdle(testWhileIdle);
dataSource.setTestOnBorrow(testOnBorrow);
dataSource.setTestOnReturn(testOnReturn);
return dataSource;
}
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean getSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws IOException {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return sqlSessionFactory;
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager getTransactionManager(@Qualifier("dataSource") DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
總的來說, 這個問題還是出自自己對spring的注解還不夠熟悉, 寫下來記錄一下吧, 友善以後查閱.