huang
2 天以前 14763d895151f3ddad09906f2233057b8b967881
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package com.mes.plc.factory;
 
import com.mes.device.entity.DeviceConfig;
import com.mes.plc.client.PlcClient;
import com.mes.plc.client.impl.ModbusPlcClient;
import com.mes.plc.client.impl.S7PlcClient;
import com.mes.service.PlcDynamicDataService;
import com.mes.s7.enhanced.EnhancedS7Serializer;
import com.mes.s7.provider.S7SerializerProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
 
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
 
/**
 * PLC客户端工厂
 * <p>
 * 根据设备配置创建不同类型的PLC客户端实例
 * </p>
 *
 * @author huang
 * @date 2025/12/19
 */
@Slf4j
@Component
public class PlcClientFactory {
   // S7序列化器提供者
    @Autowired
    private S7SerializerProvider s7SerializerProvider;
    
    // PLC动态数据服务
    @Autowired
    private PlcDynamicDataService plcDynamicDataService;
    
    // 客户端缓存,提高性能
    private final ConcurrentMap<String, PlcClient> clientCache = new ConcurrentHashMap<>();
    
    /**
     * 根据设备配置创建或获取PLC客户端
     *
     * @param device 设备配置
     * @return PLC客户端实例
     */
    public PlcClient getClient(DeviceConfig device) {
        if (device == null) {
            log.error("设备配置为空,无法创建PLC客户端");
            return null;
        }
        
        // 生成缓存键
        String cacheKey = generateCacheKey(device);
        
        // 尝试从缓存中获取客户端
        PlcClient client = clientCache.get(cacheKey);
        if (client != null && client.isConnected()) {
            return client;
        }
        
        // 缓存中没有或连接已断开,创建新客户端
        try {
            client = createClient(device);
            if (client != null) {
                // 连接PLC
                if (client.connect()) {
                    // 将客户端放入缓存
                    clientCache.put(cacheKey, client);
                    log.info("PLC客户端创建成功: cacheKey={}, plcType={}", cacheKey, client.getPlcType());
                } else {
                    log.error("PLC客户端连接失败: cacheKey={}, plcType={}", cacheKey, client.getPlcType());
                    // 连接失败,不放入缓存
                    client = null;
                }
            }
        } catch (Exception e) {
            log.error("创建PLC客户端失败: cacheKey={}", cacheKey, e);
            client = null;
        }
        
        return client;
    }
    
    /**
     * 生成缓存键
     *
     * @param device 设备配置
     * @return 缓存键
     */
    private String generateCacheKey(DeviceConfig device) {
        StringBuilder sb = new StringBuilder();
        sb.append("device:")
          .append(device.getId())
          .append(":")
          .append(device.getPlcType())
          .append(":")
          .append(device.getPlcIp())
          .append(":")
          .append(device.getPlcPort());
        return sb.toString();
    }
    
    /**
     * 根据设备类型创建不同的PLC客户端
     *
     * @param device 设备配置
     * @return PLC客户端实例
     */
    private PlcClient createClient(DeviceConfig device) {
        if (device == null) {
            return null;
        }
        
        String plcType = device.getPlcType();
        if (plcType == null || plcType.isEmpty()) {
            log.error("PLC类型为空,无法创建客户端: deviceId={}", device.getId());
            return null;
        }
        
        // 根据PLC类型创建不同的客户端
        if (plcType.startsWith("S7")) {
            // S7协议客户端
            return createS7Client(device);
        } else if (plcType.equals("MODBUS")) {
            // Modbus协议客户端
            return createModbusClient(device);
        } else {
            log.error("不支持的PLC类型: deviceId={}, plcType={}", device.getId(), plcType);
            return null;
        }
    }
    
    /**
     * 创建S7协议客户端
     *
     * @param device 设备配置
     * @return S7客户端实例
     */
    private PlcClient createS7Client(DeviceConfig device) {
        try {
            // 获取S7序列化器
            EnhancedS7Serializer s7Serializer = s7SerializerProvider.getSerializer(device);
            if (s7Serializer == null) {
                log.error("获取S7Serializer失败: deviceId={}", device.getId());
                return null;
            }
            
            // 创建S7客户端
            S7PlcClient client = new S7PlcClient(device, s7Serializer);
            // 设置PLC动态数据服务
            client.setPlcDynamicDataService(this.plcDynamicDataService);
            return client;
        } catch (Exception e) {
            log.error("创建S7客户端失败: deviceId={}", device.getId(), e);
            return null;
        }
    }
    
    /**
     * 创建Modbus协议客户端
     *
     * @param device 设备配置
     * @return Modbus客户端实例
     */
    private PlcClient createModbusClient(DeviceConfig device) {
        try {
            // 创建Modbus客户端
            return new ModbusPlcClient(device);
        } catch (Exception e) {
            log.error("创建Modbus客户端失败: deviceId={}", device.getId(), e);
            return null;
        }
    }
    
    /**
     * 关闭并移除指定设备的PLC客户端
     *
     * @param device 设备配置
     */
    public void removeClient(DeviceConfig device) {
        if (device == null) {
            return;
        }
        
        String cacheKey = generateCacheKey(device);
        PlcClient client = clientCache.remove(cacheKey);
        if (client != null) {
            client.disconnect();
            log.info("PLC客户端已移除: cacheKey={}", cacheKey);
        }
    }
    
    /**
     * 关闭并清除所有PLC客户端
     */
    public void clearAllClients() {
        log.info("开始清除所有PLC客户端,当前缓存大小: {}", clientCache.size());
        
        for (PlcClient client : clientCache.values()) {
            try {
                client.disconnect();
            } catch (Exception e) {
                log.error("关闭PLC客户端失败", e);
            }
        }
        
        clientCache.clear();
        log.info("所有PLC客户端已清除");
    }
    
    /**
     * 获取客户端缓存大小
     *
     * @return 缓存大小
     */
    public int getCacheSize() {
        return clientCache.size();
    }
}