第一次发博客,如有不对的请各位大佬不吝指正,批评的时候请口下留情 。 。 。 。
今天需要生成一个 RocketMq 的producer , 同一个 ProducerId 在项目中要求是单例的,首先想到了使用静态代码块,在项目启动的时候加载一次就行了。
但是在上线的时候说是需要动态的配置 serverAddress , 从配置文件中读取。
一开始定义一个静态变量直接使用@Value 注解 , 结果肯定是什么都写入不了 , @Value 注解无法为静态变量赋值
@Value(value = "${xxx.mqcp.serveraddress}") // 这种方法是无效的
private static String serverAddress ;
然后就采用了如下的方法 :
public static String serverAddress; @Value("${xxx.mqcp.serveraddress}") public void setServerAddress(String serveraddress) { serverAddress = serveraddress ; }
但是有一个问题,生成 Producer 的静态代码块和这个静态属性在同一个类下,当用到 这个静态属性的时候 setServerAddress() 这个方法还没有被调用,又是空引用异常(ps:这种方法本身也存在问题)
然后想着那再加一个@PostConstract 注解行不行呢,肯定不行 , static 修饰的代码在类加载的时候开始初始化了
后来就是把 Producer 声明成静态变量,但是不赋值 , 在需要这个类的时候再使用普通方法初始化这个静态变量 , 这样问题基本解决了 , 运行起来也没问题,可能出现的线程问题直接忽视了。
然后就去划水了。 。 。 。
但是,但是,公司的代码规范不让这样操作静态变量,禁止非静态方法修改静态属性 ,可能会有线程安全的问题
其实这个问题很容易解决 , 使用spring 的容器就好了,只要定义一个注册类(@Configuration),在spring中托管这个(@Bean)Producer 就行了 。
@Configuration
public class MqcpProducerConfig{
@Value("${xxx.mqcp.serveraddress}")
private String serverAddress ;
@Bean
public MqcpProducer mqcpProducer(){
Properties p = new Properties() ;
MqcpProducer mqcpProducer = MqcpFactory.createProducer(p) ;
mqcpProducer.start() ;
return mqcpProducer ;
}
}
调用的时候直接使用 依赖注入就行了 。
@Autowried
private MqcpProducer mqcpProducer ;
public Object xxxSendMessage(){
mqcpProducer .sendMessage(message) ;
return "success" ;
}
总结一下:
@Bean作用在方法上,初始化一个类托管给spring容器 ,只执行一次 ,适合一些需要单例的实例
@Value 不能作用在静态属性,因为类加载的时候静态变量和静态代码块最先开始初始化
少定义静态属性和静态方法,除非有这个必要
一开始就不该执著于静态属性和静态代码,干什么事都不能偷懒和着急!!!!!!!