以前の技術ブログでは、SpringBootがWebSocketを統合して大量のメッセージプッシュを実現する方法を記録し、主に基本的なフレームワークを構築しました。
SpringBootはWebSocketを統合して、大量のメッセージプッシュを実現します
@ServerEndpointが使用された後、@ Autowiredが無効になることが後で発見されました。なぜですか?
問題の説明
特定のビジネスシナリオでは、ユーザーが正常に接続するのを待ってから、最初にライブラリテーブルから10個のデータを取得し、それらをデフォルトの初期化データとして表示する必要があります。
対応するサービスには、@ Autowiredアノテーションを介して依存性が注入されることは当然のことです。nullポインターの例外が報告された、つまり、必要なサービスが正常に挿入されなかったことが発見されました。
現在の執筆は次のとおりです。
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {
@Autowired
private OrderService orderService;
}
問題分析
Spring Managementはシングルトンモード(シングルトン)を採用し、WebSocketはマルチオブジェクトです。つまり、各クライアントはバックエンドのWebSocketオブジェクトに対応します。これは、新しいWebSocketとしても理解できるため、もちろん、自動的に挿入されたオブジェクトを取得することはできません。 、2つはちょうど衝突するので。
@Autowiredアノテーションインジェクションオブジェクト操作は、使用時ではなく起動時に実行され、WebSocketは接続が使用されているときにのみオブジェクトをインスタンス化し、複数の接続がある場合は複数のオブジェクトがあります。
したがって、このサービスはWebSocketにまったく注入されていないと結論付けることができます。
解決
方法1は静的静的オブジェクトを使用します
注入する必要のあるサービスを静的に変更し、それを現在のクラスに所属させてから、setOrderServiceメソッドを介して注入して問題を解決します。
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {
private static OrderService orderService;
@Autowired
public void setOrderService(OrderService service) {
WebSocketServer.orderService = orderService;
}
}
方法2は、SpringコンテナからOrderServiceを動的に削除します
/**
* 获取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);
}
}
WebSocketServerを呼び出します。
private OrderService orderService = SpringCtxUtils.getBean(OrderService.class);
方法1は比較的単純で、プロテストで効果的です。方法2には特定のテストはありません。試してみることができます。