问题
我们在项目中使用多数据源,创建了多个sqlSessionFactory类型的Bean,名字类似:sqlSessionFactory
, sqlSessionFactory1
…,注入的代码如下:
@Autowired
public void createTemplate(SqlSessionFactory sqlSessionFactory)
{
setSqlSessionFactory(sqlSessionFactory);
}
在本地运行时,这段代码可以正常的注入我们创建的sqlSessionFactory
这个bean,但是,通过流水线打包后,运行会报错:
nested exception is No qualifying bean of type [org.apache.ibatis.session.SqlSessionFactory] is defined: expected single matching bean but found 2: sqlSessionFactory,sqlSessionFactory2 ...
原理
spring注入时,会根据类型和名称自动装配,在我们本地开发时,注入的方法
@Autowired
public void createTemplate(SqlSessionFactory sqlSessionFactory)
{
setSqlSessionFactory(sqlSessionFactory);
}
中使用的参数名是 sqlSessionFactory
,可以根据名称匹配成功,正常注入,但是,在通过流水线javac编译后,方法中的参数名称信息会被丢弃,生成的class会变成类似
@Autowired
public void createTemplate(SqlSessionFactory var1)
{
setSqlSessionFactory(var1);
}
因此,spring根据名字var1
找不到对应的bean,就会尝试用类型去装配,而我们项目中同类型的bean有多个,就不知道应该装配哪个了,导致失败。
解决
方案1
javac默认情况下编译不会默认保留参数名字,会生成类似 var1 arg1之类的名字,但是我们可以通过增加编译指令-parameters
,让他保留参数名,以maven项目为例:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
</configuration>
</plugin>
方案2
spring默认会根据参数名来获取bean,但除此以外,spring还提供了@Qualifier
注解来指定bean,对于本例,我们可以把代码改成:
@Autowired
@Qualifier("sqlSessionFactory")
public void createTemplate(SqlSessionFactory sqlSessionFactory)
{
setSqlSessionFactory(sqlSessionFactory);
}
这样,spring会根据我们提供的名字来查找,就不会再怕javac编译后参数丢失的问题了