最近在整合拉卡拉支付的 SDK 时发现初始化失败,然后找了下也找到问题出在哪,就想着换一个方法初始化算了,所以就去查了下几种初始化的方法和区别
先看我下初始化失败的方法,也是我之前一直在用的方法 @PostConstruct
import com.lkl.laop.sdk.Config;
import com.lkl.laop.sdk.LKLSDK;
import com.lkl.laop.sdk.exception.SDKException;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import java.io.FileNotFoundException;
import java.net.URL;
import java.net.URLDecoder;
/**
* @author Sakura
* @date 2025/4/29 16:58
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
public class LklSdkAutoConfig {
private final LklSdkProperties properties;
@PostConstruct
public void initLklSdk() {
try {
Config config = new Config();
config.setAppId(properties.getAppId());
config.setSerialNo(properties.getSerialNo());
config.setPriKeyPath(getPath(properties.getPriKeyPath()));
config.setLklCerPath(getPath(properties.getLklCerPath()));
config.setLklNotifyCerPath(getPath(properties.getLklNotifyCerPath()));
config.setSm4Key(properties.getSm4Key());
config.setServerUrl(properties.getServerUrl());
LKLSDK.init(config);
log.info("拉卡拉 SDK 初始化成功");
} catch (SDKException e) {
log.error("拉卡拉 SDK 初始化失败", e);
throw new RuntimeException("拉卡拉 SDK 初始化失败", e);
}
}
private String getPath(String resourceName) {
try {
URL url = this.getClass().getClassLoader().getResource(resourceName);
if (url == null) {
throw new FileNotFoundException(resourceName + " not found in classpath");
}
return URLDecoder.decode(url.getPath(), "UTF-8");
} catch (Exception e) {
throw new RuntimeException("找不到资源文件: " + resourceName, e);
}
}
}
上面这个方法应该是正常的,我也用下面的方法检测了容器中是否注册了这个类,最后都发类注册成功了,@PostConstruct 注解没有正常执行
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private ApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) {
String[] beans = context.getBeanDefinitionNames();
Arrays.sort(beans);
for (String bean : beans) {
if (bean.toLowerCase().contains("lkl")) {
System.out.println("Bean: " + bean);
}
}
}
}
然后就换了一种方式 InitializingBean,写法如下
import com.lkl.laop.sdk.Config;
import com.lkl.laop.sdk.LKLSDK;
import com.lkl.laop.sdk.exception.SDKException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
import java.io.FileNotFoundException;
import java.net.URL;
import java.net.URLDecoder;
/**
* @author Sakura
* @date 2025/4/29 16:58
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
public class LklSdkAutoConfig implements InitializingBean {
private final LklSdkProperties properties;
@Override
public void afterPropertiesSet() {
log.info("afterPropertiesSet 初始化...");
try {
Config config = new Config();
config.setAppId(properties.getAppId());
config.setSerialNo(properties.getSerialNo());
config.setPriKeyPath(getPath(properties.getPriKeyPath()));
config.setLklCerPath(getPath(properties.getLklCerPath()));
config.setLklNotifyCerPath(getPath(properties.getLklNotifyCerPath()));
config.setSm4Key(properties.getSm4Key());
config.setServerUrl(properties.getServerUrl());
LKLSDK.init(config);
log.info("拉卡拉 SDK 初始化成功");
} catch (SDKException e) {
log.error("拉卡拉 SDK 初始化失败", e);
throw new RuntimeException("拉卡拉 SDK 初始化失败", e);
}
}
private String getPath(String resourceName) {
try {
URL url = this.getClass().getClassLoader().getResource(resourceName);
if (url == null) {
throw new FileNotFoundException(resourceName + " not found in classpath");
}
return URLDecoder.decode(url.getPath(), "UTF-8");
} catch (Exception e) {
throw new RuntimeException("找不到资源文件: " + resourceName, e);
}
}
}
我这边换成 InitializingBean 方式后就能正常初始化了,当然还有其它的几种方式,下面简单介绍一下
1.实现 InitializingBean 接口
优点:安全、明确,依赖注入后执行,适合有初始化依赖的组件。
推荐度:⭐⭐⭐⭐⭐
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}
}
2.使用 @PostConstruct 注解
优点:语义明确,常用于简单初始化。
缺点:受 Spring 代理机制影响(如某些 AOP 或 CGLIB 场景会失效)。
推荐度:⭐⭐⭐(简单场景下使用)
@PostConstruct
public void init() {
// 初始化逻辑
}
3.使用 @Bean(initMethod = “…”) 指定初始化方法
优点:对第三方类/非 Spring Bean 有控制权。
推荐度:⭐⭐⭐(适用于工厂方法创建的 Bean)
@Bean(initMethod = "init")
public MyService myService() {
return new MyService();
}
4.实现 ApplicationRunner 或 CommandLineRunner 接口
用途:程序完全启动后执行任务(如注册服务、检查状态等)。
推荐度:⭐⭐⭐⭐(用于延迟初始化、异步启动)
@Component
public class MyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// 程序启动后执行(可做初始化任务)
}
}
5.监听 Spring 生命周期事件:ApplicationListener
适用:容器级别的监听与操作。
推荐度:⭐⭐⭐(用于复杂初始化或框架级支持)
@Component
public class MyInitListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// Spring 容器刷新完成后执行
}
}
6.@ConfigurationProperties + @EnableConfigurationProperties
搭配方式:与 @Component, @Configuration, @Bean 联合使用。
推荐度:⭐⭐⭐⭐⭐(配置驱动初始化的核心机制)
@ConfigurationProperties(prefix = "my")
public class MyProperties {
private String key;
...
}