O blog técnico anterior registrou como SpringBoot integra WebSocket para obter envio de mensagem em massa e, principalmente, construiu a estrutura básica:
SpringBoot integra WebSocket para conseguir envio de mensagens em massa
Posteriormente, foi descoberto que após o uso de @ServerEndpoint, @Autowired tornou-se inválido.
Descrição do Problema
Em um cenário de negócios específico, é necessário esperar que o usuário se conecte com êxito e, primeiro, obtenha 10 dados da tabela da biblioteca e os exiba como os dados de inicialização padrão.
Consideramos que o serviço correspondente será uma dependência injetada por meio da anotação @Autowired. Foi descoberto que uma exceção de ponteiro nulo foi relatada, ou seja, o serviço necessário não foi injetado com sucesso.
A redação atual é a seguinte:
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {
@Autowired
private OrderService orderService;
}
analise de problemas
O gerenciamento Spring adota o modo singleton (singleton) , e WebSocket é multi-objeto, ou seja, cada cliente corresponde a um objeto WebSocket no backend, que também pode ser entendido como um novo WebSocket, então é claro que o objeto injetado automaticamente não pode ser obtido , porque os dois apenas entram em conflito.
A operação do objeto de injeção de anotação @Autowired é executada na inicialização, não quando é usada, e o WebSocket apenas instancia o objeto quando a conexão está em uso e há vários objetos quando há várias conexões.
Portanto, podemos concluir que este Serviço não é injetado no WebSocket.
solução
Método um usa objeto estático estático
Altere o serviço que precisa ser injetado para estático, deixe-o pertencer à classe atual e injete por meio do método setOrderService para resolver o problema.
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {
private static OrderService orderService;
@Autowired
public void setOrderService(OrderService service) {
WebSocketServer.orderService = orderService;
}
}
Método dois remove dinamicamente o OrderService do contêiner Spring
/**
* 获取spring容器
* 当一个类实现了这个接口ApplicationContextAware之后,这个类就可以方便获得ApplicationContext中的所有bean。
* 换句话说,这个类可以直接获取spring配置文件中所有有引用到的bean对象
* 前提条件需作为一个普通的bean在spring的配置文件中进行注册
*/
public class SpringCtxUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringCtxUtils.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> type) {
try {
return applicationContext.getBean(type);
} catch (NoUniqueBeanDefinitionException e) {
//出现多个,选第一个
String beanName = applicationContext.getBeanNamesForType(type)[0];
return applicationContext.getBean(beanName, type);
}
}
public static <T> T getBean(String beanName, Class<T> type) {
return applicationContext.getBean(beanName, type);
}
}
Chame no WebSocketServer:
private OrderService orderService = SpringCtxUtils.getBean(OrderService.class);
O método um é relativamente simples e eficaz no pró-teste. O método dois não tem um teste específico. Você pode tentar.