若相机不存在,则不去调用dll

物流展会算法
LAPTOP-S9HJSOEB\昊天 1 week ago
parent bb92518d32
commit 5b0ca302cc

@ -39,34 +39,83 @@ public class ImageCaptureService {
@Resource @Resource
private AppConfig appConfig; private AppConfig appConfig;
// SDK是否可用:DLL缺失/加载失败/版本不匹配时为false,此时所有相机操作直接返回,不影响主流程
private volatile boolean sdkAvailable = true;
// 是否已尝试过初始化(避免反复尝试加载不存在的DLL)
private volatile boolean sdkInitTried = false;
/** /**
* 构造函数,初始化SDK * 构造函数,初始化SDK
* 注意:未配置海康相机时不初始化SDK,也不会去加载任何DLL
*/ */
@PostConstruct @PostConstruct
public void init() { public void init() {
List<AppConfig.Camera> cameras = appConfig.getHikCamera();
if (cameras == null || cameras.isEmpty()) {
log.info("未配置海康相机(hikCamera),跳过SDK初始化,不加载相机DLL");
return;
}
initSdkAndCameras(cameras);
}
/**
* 初始化SDK并打开配置的相机。
* 任何异常或错误(UnsatisfiedLinkError/NoSuchFieldError/NoClassDefFoundError 等)都只记录日志,
* 绝不向上抛出,避免影响 Spring 容器启动。
*
* @param cameras 相机配置,可为空
*/
private synchronized void initSdkAndCameras(List<AppConfig.Camera> cameras) {
if (sdkInitTried || !sdkAvailable) {
return;
}
sdkInitTried = true;
int nRet;
try { try {
log.info("初始化海康相机SDK..."); log.info("初始化海康相机SDK...");
int nRet = MvCameraControl.MV_CC_Initialize(); nRet = MvCameraControl.MV_CC_Initialize();
if (MV_OK != nRet) { } catch (Throwable t) {
log.error("初始化SDK失败,errcode: [0x{}]", Integer.toHexString(nRet)); log.error("海康相机SDK加载失败(DLL缺失或版本不匹配),相机功能不可用: {}", t.toString());
} else { sdkAvailable = false;
isSdkInitialized = true; return;
log.info("SDK Version: {}", MV_CC_GetSDKVersion()); }
log.info("SDK初始化成功");
} if (MV_OK != nRet) {
if (appConfig.getHikCamera() != null && !appConfig.getHikCamera().isEmpty()){ log.error("初始化SDK失败,errcode: [0x{}]", Integer.toHexString(nRet));
initCamerasFromConfig(appConfig.getHikCamera()); return;
}
isSdkInitialized = true;
try {
log.info("SDK Version: {}", MV_CC_GetSDKVersion());
log.info("SDK初始化成功");
if (cameras != null && !cameras.isEmpty()) {
initCamerasFromConfig(cameras);
} }
} catch (Exception e) { } catch (Throwable t) {
log.error("初始化SDK异常", e); log.error("SDK初始化后处理异常", t);
} }
} }
/**
* SDK是否可用(DLL已加载且初始化成功)
*/
public boolean isSdkAvailable() {
return sdkAvailable && isSdkInitialized;
}
/** /**
* 销毁资源 * 销毁资源
*/ */
@PreDestroy @PreDestroy
public void destroy() { public void destroy() {
if (!sdkAvailable) {
handleMap.clear();
return;
}
log.info("开始清理相机资源..."); log.info("开始清理相机资源...");
// 停止抓图并销毁所有句柄 // 停止抓图并销毁所有句柄
@ -90,6 +139,8 @@ public class ImageCaptureService {
log.info("相机 {} 资源已清理", ip); log.info("相机 {} 资源已清理", ip);
} catch (Exception e) { } catch (Exception e) {
log.error("清理相机 {} 资源时发生异常", ip, e); log.error("清理相机 {} 资源时发生异常", ip, e);
} catch (Throwable t) {
log.warn("清理相机 {} 资源时失败(SDK不可用)", ip);
} }
} }
@ -102,6 +153,8 @@ public class ImageCaptureService {
log.info("SDK反初始化成功"); log.info("SDK反初始化成功");
} catch (Exception e) { } catch (Exception e) {
log.error("SDK反初始化异常", e); log.error("SDK反初始化异常", e);
} catch (Throwable t) {
log.warn("SDK反初始化失败(SDK不可用)");
} }
} }
} }
@ -112,6 +165,13 @@ public class ImageCaptureService {
* @return 成功初始化的相机数量 * @return 成功初始化的相机数量
*/ */
public int initCameras(List<String> ipList) { public int initCameras(List<String> ipList) {
if (!sdkAvailable) {
log.warn("海康相机SDK不可用(DLL未加载),跳过相机初始化");
return 0;
}
if (!isSdkInitialized) {
initSdkAndCameras(appConfig.getHikCamera());
}
if (!isSdkInitialized) { if (!isSdkInitialized) {
log.error("SDK未初始化,无法初始化相机"); log.error("SDK未初始化,无法初始化相机");
return 0; return 0;
@ -133,8 +193,10 @@ public class ImageCaptureService {
return 0; return 0;
} }
log.info("枚举到 {} 个设备", stDeviceList.size()); log.info("枚举到 {} 个设备", stDeviceList.size());
} catch (CameraControlException e) { } catch (Throwable e) {
log.error("枚举设备失败", e); log.error("枚举设备失败,SDK不可用: {}", e.toString());
sdkAvailable = false;
isSdkInitialized = false;
return 0; return 0;
} }
@ -238,6 +300,9 @@ public class ImageCaptureService {
} catch (CameraControlException e) { } catch (CameraControlException e) {
log.error("相机 {} 初始化异常", ip, e); log.error("相机 {} 初始化异常", ip, e);
return null; return null;
} catch (Throwable t) {
log.error("相机 {} 初始化失败(SDK不可用)", ip, t);
return null;
} }
} }
@ -259,6 +324,13 @@ public class ImageCaptureService {
* @return 是否成功 * @return 是否成功
*/ */
private boolean captureImage(String ip, String savePath, boolean isRetry) { private boolean captureImage(String ip, String savePath, boolean isRetry) {
if (!sdkAvailable) {
log.warn("海康相机SDK不可用(DLL未加载),跳过拍照: {}", ip);
return false;
}
if (!isSdkInitialized) {
initSdkAndCameras(appConfig.getHikCamera());
}
if (!isSdkInitialized) { if (!isSdkInitialized) {
log.error("SDK未初始化"); log.error("SDK未初始化");
return false; return false;
@ -326,6 +398,9 @@ public class ImageCaptureService {
} }
} }
return false; return false;
} catch (Throwable t) {
log.error("拍照失败(SDK不可用)", t);
return false;
} }
} }
@ -455,17 +530,17 @@ public class ImageCaptureService {
if (hCamera == null) return; if (hCamera == null) return;
try { try {
MvCameraControl.MV_CC_StopGrabbing(hCamera); MvCameraControl.MV_CC_StopGrabbing(hCamera);
} catch (Exception e) { } catch (Throwable e) {
log.warn("相机 {} 停止抓图异常", ip, e); log.warn("相机 {} 停止抓图异常", ip, e);
} }
try { try {
MvCameraControl.MV_CC_CloseDevice(hCamera); MvCameraControl.MV_CC_CloseDevice(hCamera);
} catch (Exception e) { } catch (Throwable e) {
log.warn("相机 {} 关闭设备异常", ip, e); log.warn("相机 {} 关闭设备异常", ip, e);
} }
try { try {
MvCameraControl.MV_CC_DestroyHandle(hCamera); MvCameraControl.MV_CC_DestroyHandle(hCamera);
} catch (Exception e) { } catch (Throwable e) {
log.warn("相机 {} 销毁句柄异常", ip, e); log.warn("相机 {} 销毁句柄异常", ip, e);
} }
log.info("相机 {} 句柄已销毁", ip); log.info("相机 {} 句柄已销毁", ip);
@ -476,6 +551,10 @@ public class ImageCaptureService {
* @return 新句柄,失败返回null * @return 新句柄,失败返回null
*/ */
private Handle reconnectCamera(String ip) { private Handle reconnectCamera(String ip) {
if (!sdkAvailable) {
log.warn("海康相机SDK不可用(DLL未加载),跳过重连: {}", ip);
return null;
}
log.warn("相机 {} 开始重连...", ip); log.warn("相机 {} 开始重连...", ip);
destroyCameraHandle(ip); destroyCameraHandle(ip);
@ -495,6 +574,11 @@ public class ImageCaptureService {
} }
} catch (Exception e) { } catch (Exception e) {
log.warn("相机 {} 重连异常(第{}/{}次)", ip, i, RECONNECT_MAX_RETRIES, e); log.warn("相机 {} 重连异常(第{}/{}次)", ip, i, RECONNECT_MAX_RETRIES, e);
} catch (Throwable t) {
log.warn("相机 {} 重连失败(SDK不可用)", ip, t);
sdkAvailable = false;
isSdkInitialized = false;
break;
} }
if (i < RECONNECT_MAX_RETRIES) { if (i < RECONNECT_MAX_RETRIES) {
@ -520,6 +604,13 @@ public class ImageCaptureService {
public List<String> captureBatch(String ip, String basePath, int count) { public List<String> captureBatch(String ip, String basePath, int count) {
List<String> successPaths = new ArrayList<>(); List<String> successPaths = new ArrayList<>();
if (!sdkAvailable) {
log.warn("海康相机SDK不可用(DLL未加载),跳过拍照: {}", ip);
return successPaths;
}
if (!isSdkInitialized) {
initSdkAndCameras(appConfig.getHikCamera());
}
if (!isSdkInitialized) { if (!isSdkInitialized) {
log.error("SDK未初始化"); log.error("SDK未初始化");
return successPaths; return successPaths;

@ -50,9 +50,9 @@ public class LxCameraCapture {
// 加载DLL库 // 加载DLL库
this.dcLibrary = Native.loadLibrary(libraryPath, DcLibrary.class); this.dcLibrary = Native.loadLibrary(libraryPath, DcLibrary.class);
log.info("LX相机SDK加载成功"); log.info("LX相机SDK加载成功");
} catch (Exception e) { } catch (Throwable t) {
log.error("LX相机SDK加载失败", e); log.error("LX相机SDK加载失败", t);
throw new RuntimeException("加载LX相机SDK失败: " + e.getMessage()); throw new RuntimeException("加载LX相机SDK失败: " + t.toString());
} }
} }

@ -65,18 +65,36 @@ public class LxCameraServiceImpl implements LxCameraService {
} }
} }
// DLL是否可用:缺失/加载失败时为false,避免反复尝试加载不存在的DLL
private volatile boolean dllAvailable = true;
// 是否已尝试过初始化(用于延迟初始化)
private volatile boolean initTried = false;
@PostConstruct @PostConstruct
public void init() { public void init() {
if (appConfig.getLxCamera() != null && !appConfig.getLxCamera().isEmpty()) { if (appConfig.getLxCamera() != null && !appConfig.getLxCamera().isEmpty()) {
initCameras(); initCameras();
} else {
log.info("未配置Lx相机(lxCamera),跳过SDK初始化,不加载相机DLL");
} }
} }
@Override @Override
public void initCameras() { public void initCameras() {
log.info("开始初始化所有Lx相机,数量: {}", appConfig.getLxCamera().size()); List<AppConfig.Camera> cameras = appConfig.getLxCamera();
if (cameras == null || cameras.isEmpty()) {
log.info("未配置Lx相机(lxCamera),跳过初始化,不加载相机DLL");
return;
}
if (!dllAvailable) {
log.warn("Lx相机DLL不可用(缺失或版本不匹配),跳过初始化");
return;
}
log.info("开始初始化所有Lx相机,数量: {}", cameras.size());
for (AppConfig.Camera camera : appConfig.getLxCamera()) { for (AppConfig.Camera camera : cameras) {
try { try {
// 复制DLL文件,一个相机对应一个独立的DLL // 复制DLL文件,一个相机对应一个独立的DLL
String sourceDll = System.getProperty("user.dir") + "\\libs\\plc\\LxCameraApi.dll"; String sourceDll = System.getProperty("user.dir") + "\\libs\\plc\\LxCameraApi.dll";
@ -101,9 +119,16 @@ public class LxCameraServiceImpl implements LxCameraService {
} catch (Exception e) { } catch (Exception e) {
log.error("初始化相机 {} 时发生异常", camera.getIp(), e); log.error("初始化相机 {} 时发生异常", camera.getIp(), e);
} catch (Error e) {
// DLL缺失/位数不匹配等会抛 UnsatisfiedLinkError(Error,不是Exception),
// 这里必须兜住,否则 @PostConstruct 失败会导致整个Spring容器启动失败
log.error("初始化相机 {} 失败(DLL缺失或不可用),Lx相机功能不可用: {}", camera.getIp(), e.toString());
dllAvailable = false;
break;
} }
} }
initTried = true;
log.info("所有Lx相机初始化完成,成功: {}", instanceMap.size()); log.info("所有Lx相机初始化完成,成功: {}", instanceMap.size());
} }
@ -214,8 +239,13 @@ public class LxCameraServiceImpl implements LxCameraService {
log.info("相机 {} 开始拍照,配置: {}", cameraSn, config); log.info("相机 {} 开始拍照,配置: {}", cameraSn, config);
DcLibrary instance = instanceMap.get(cameraSn); DcLibrary instance = instanceMap.get(cameraSn);
if (instance == null && !initTried) {
// 延迟初始化:启动时尚未初始化过的情况下再试一次
initCameras();
instance = instanceMap.get(cameraSn);
}
if (instance == null) { if (instance == null) {
return CaptureResult.failure(cameraSn, -3, "DcLibrary实例不存在"); return CaptureResult.failure(cameraSn, -3, "DcLibrary实例不存在(Lx相机DLL未加载)");
} }
CaptureResult result = CaptureResult.success(cameraSn); CaptureResult result = CaptureResult.success(cameraSn);
@ -414,6 +444,12 @@ public class LxCameraServiceImpl implements LxCameraService {
return result; return result;
} }
} }
} catch (Error e) {
log.error("相机 {} 第 {} 次拍照失败(SDK不可用)", cameraSn, retryCount, e);
stopStreamIfNeeded(cameraSn, instance);
result = CaptureResult.failure(cameraSn, -6, "拍照失败(SDK不可用): " + e.toString());
result.withRetryCount(retryCount);
return result;
} }
} }
@ -487,6 +523,8 @@ public class LxCameraServiceImpl implements LxCameraService {
} }
} catch (Exception e) { } catch (Exception e) {
log.error("相机 {} 停止流时发生异常", cameraSn, e); log.error("相机 {} 停止流时发生异常", cameraSn, e);
} catch (Error e) {
log.warn("相机 {} 停止流失败(SDK不可用): {}", cameraSn, e.toString());
} }
} }
} }
@ -569,6 +607,8 @@ public class LxCameraServiceImpl implements LxCameraService {
} }
} catch (Exception e) { } catch (Exception e) {
log.error("相机 {} 关闭时发生异常", cameraSn, e); log.error("相机 {} 关闭时发生异常", cameraSn, e);
} catch (Error e) {
log.warn("相机 {} 关闭失败(SDK不可用): {}", cameraSn, e.toString());
} }
handleMap.remove(cameraSn); handleMap.remove(cameraSn);

Loading…
Cancel
Save