Análise e solução do problema de falha @Autowired após usar @ServerEndpoint no SpringBoot

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.

Acho que você gosta

Origin blog.csdn.net/j1231230/article/details/114641956
Recomendado
Clasificación