1.背景
后台服务要求集成一个第三方短信系统(云片:
github.com/yunpian/yun…)第三方规范要求使用单例模式。
第一版代码如下:
public class GetYunpianClient {
private static YunpianClient yunpianClient = null;
private GetYunpianClient() {
}
public static YunpianClient getInstance() throws Exception {
if (yunpianClient == null) {
synchronized (YunpianClient.class) {
if (yunpianClient == null) {
yunpianClient = new YunpianClient("b596ec6ea87fcaa9250f72fbe335ed1a").init();
}
}
}
return yunpianClient;
}
}
2.报错:Parameter 0 of constructor in xxx required a bean of type 'java.lang.String' that could not be found.
本来以双重检查方式实现单例模式,后领导不满意,要求改为Spring注入方式
于是脑抽就有了以下错误代码(构造注入):
@Service
public class GetYunpianClient {
private YunpianClient yunpianClient;
@Autowired
public GetYunpianClient(String apiKey){
this.yunpianClient = new YunpianClient(apiKey).init();
}
public YunpianClient init() {
return yunpianClient;
}
}
启动服务:报错如下:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.zhexinit.callshow.app.common.util.GetYunpianClient required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
由报错信息很容易看出:是由于类中定义了含参数的构造函数,Spring自动构造和注入时未为该Bean传入参数,引起报错(@Service注解默认注入的是不带参的构造函数).
解决方案:
1.使用@Configuration+ @Bean注解来实现注入
2.改为无参构造函数
选用第二种方案:
@Service
public class GetYunpianClient {
private YunpianClient yunpianClient;
@Value("${yunpian.apiKey}")
private String apiKey;
@Autowired
public GetYunpianClient(){
this.yunpianClient = new YunpianClient(apiKey).init();
}
public YunpianClient init() {
return yunpianClient;
}
}
又出现问题:@Value注解不生效,apiKey=null;
3.@Value注解不生效
原因:Java类先执行构造方法,再给@Value/@Autowired注解变量注入值
解决方案:
1.硬编码apiKey
2.改为get set注入
选用第二种方案如下:
@Service
public class GetYunpianClient {
private YunpianClient yunpianClient;
@Value("${yunpian.apiKey}")
private String apiKey;
@Autowired
public YunpianClient getYunpianClient() {
return yunpianClient;
}
@Autowired
public void setYunpianClient() {
this.yunpianClient = new YunpianClient(apiKey).init();
}
}
4.【附】使用@Configuration+ @Bean注解来实现注入
@Configuration
public class YunpianClientConfig {
@Value("${yunpian.apiKey}")
private String apiKey;
@Bean
YunpianClient getYunpianClient(){
return new YunpianClient(apiKey).init();
}
}