Spring Bean加载顺序问题
问题背景
在基于前同事的项目进行改造重构中 其中有将一些强耦合属性关系抽出做成配置时
使用了静态变量存储(从nacos中获取的对象再使用@PostConstruct进行赋值) 本地正常运行
linux也运行正常 突然今晚给我说启动报错
问题
炸一看 这就是bean没注入好 第一反应时缺少了配置 然后没有看到相关的属性缺失
再考虑到依赖出现问题
沟通后得知可能出现再我的静态变量上 服务器变好了 加载顺序没有按照之前的来了?
分析
这种由于再自己电脑和dev环境服务器没有出现 加载顺序大概率是不会变的 但是测试服务器却出现了这样的问题 由于我使用了静态变量那么就可能出现再这个静态变量上
但是我静态变量已经用@PostConstruct进行加载了先附上各个代码
ControlTbmuServiceImpl 注入失败
@Service
@Slf4j
public class ControlTbmuServiceImpl implements ControlTbmuService {
@Autowired
private Msg0x303Handler msg0x303Handler;
Msg0x303Handler 调用静态失败
//TcbmuBootstrapConfig是配置类 用于处理nacos配置中心的集合对象
super.write(TcbmuBootstrapConfig.getTbmu().getPort().toString(), MSG_ID, sendMsg);//null
NettyClient 使用了TcbmuBootstrapConfig
@Configuration
@Slf4j
@Order(1)
//@RefreshScope
public class NettyClient implements CommandLineRunner {
@Value("${netty.host}")
private String host;
@Autowired
private TcbmuBootstrapConfig tcbmuBootstrapConfig;
TcbmuBootstrapConfig 处理配置数据
@Configuration
public class TcbmuBootstrapConfig {
@Autowired
private CarMachineConfig carMachineConfig;
private static TbmuInfo tbmu; //tbmu对象
private static List<CbmuSbmuInfo> cbmus = new CopyOnWriteArrayList<>(); //所有cbmu对象
private static Map<String, CbmuSbmuInfo> cbmuMap = new ConcurrentHashMap<>(); //所有cbmu对象 key为sbmuNumber 这个只作为对象查询
private static List<Integer> allPorts = new CopyOnWriteArrayList<>(); //所有端口
public TcbmuBootstrapConfig() {
System.out.println("TcbmuBootstrapConfig+++++++++++++++++++++++++++");
}
/**
* 初始化
*/
// public void intData(){
System.out.println(111);
// init();
// }
@PostConstruct
private void init(){
System.out.println("TcbmuBootstrapConfigInit++++++++++++++=====");
tbmu = carMachineConfig.getTbmuList().get(0);
cbmus = carMachineConfig.getCbmuSbmuList();
// String jsonString = LocalJsonFileUtil.getFileJsonString(jsonFilePath);
// tbmu = new TbmuInfo(LocalJsonFileUtil.getTbmuConfigData(jsonString).get(0).getPort());//默认只有一个tbmu
// cbmus = LocalJsonFileUtil.getCbmuConfigData(jsonString);
allPorts.add(tbmu.getPort());
allPorts.addAll(cbmus.stream().map(CbmuSbmuInfo::getPort).distinct().collect(Collectors.toList()));
cbmuMap = cbmus.stream().collect(Collectors.toConcurrentMap(CbmuSbmuInfo::getSbmuNumber, a->a,(k1, k2)->k1));
}
CarMachineConfig 注入配置数据
@ConfigurationProperties(prefix = "car-machine")
@Component
@Data
public class CarMachineConfig implements Serializable {
private List<TbmuInfo> tbmuList = new ArrayList<>();
private List<CbmuSbmuInfo> cbmuSbmuList = new ArrayList<>();
public CarMachineConfig() {
System.out.println("CarMachineConfig++++++++++=");
}
}
再说下基础的加载顺序
(1)在springBoot中是实现CommandLineRunner接口类
@Component
@Order(1)
class Runner1 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("step 3: The Runner1 run...");
}
}
@Component
@Order(2)
class Runner2 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("step 4: The Runner1 run...");
}
}
(2)@SpringBootApplication(也就是我改动后的使用方式)
@EnableScheduling
@ComponentScan(basePackages = "com.swap")
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class CarmachineApplication {
public CarmachineApplication(TcbmuBootstrapConfig config) {
}
public static void main(String[] args) {
SpringApplication.run(CarmachineApplication.class, args);
}
}
(3)声明一个实现了CommandLineRunner接口的Bean
@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
@Bean
public ApplicationStartupRunner schedulerRunner() {
return new ApplicationStartupRunner();
}
}
public class ApplicationStartupRunner implements CommandLineRunner {
protected final Log logger = LogFactory.getLog(getClass());
@Override
public void run(String... args) throws Exception {
logger.info("Application Started !!");
}
}
(4)通过@Configuration注解类中bean的定义顺序控制bean的加载顺序;
@Configuration
public class BeanConfig {
@Bean
public TestInterface uiTest() {
return new UiTest();
}
@Bean
public TestInterface interTest() {
return new InterTest();
}
@Bean
public TestInterface unitTest() {
return new UnitTest();
}
}
(5) 等等等等。。
进一步分析
bean加载顺序 构造->@Autowire->@PostConstruct
需要注意@Configuration @Comment等是不会受其他类@Order(1)去影响他们的加载顺序的