天天看點

spring的@Value無法注入值說明

說明

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

spring的@Value無法注入值說明

  今天想把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的注解還不夠熟悉, 寫下來記錄一下吧, 友善以後查閱.