Solve the problem that springboot integrates websocket, redis, openfeign, redisTemplate, and openfeign classes that cannot be injected

In some businesses, we need to use long connections. We can use http long connections or websocket. In the framework of springboot as the backend, the technologies that can be borrowed are (netty, websocket)

The version is as follows

Software Version number
jdk 21
springboot

3.1.5

springcloud

2022.0.4

Scene recurrence

pom file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>testDi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>testDi</name>
    <description>testDi</description>
    <properties>
        <java.version>21</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Configuration class

package com.example.testdi.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

@Configuration
public class WebsocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    @Bean
    public ServletServerContainerFactoryBean createWebSocketContainer() {
        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
        container.setMaxTextMessageBufferSize(8192 * 4);
        container.setMaxBinaryMessageBufferSize(8192 * 4);
        return container;
    }
}

rpc class

package com.example.testdi.rpc;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@FeignClient(value = "http://localhost:9090")
public interface TestRpc {

    @GetMapping("/hello")
    @ResponseBody
    String hello();
}

websocket class

@Slf4j
@Component
@ServerEndpoint(value = "/example")
public class ExampleWebsocket {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private TestRpc testRpc;

    @OnOpen
    public void open(Session session) {
        log.info("===============open=================");
        log.info("redisTemplate: {}", redisTemplate);
        log.info("testRpc: {}", testRpc);
    }
}

Startup class

@EnableFeignClients
@SpringBootApplication
public class TestDiApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestDiApplication.class, args);
    }

}

Configuration file

spring:
  data:
    redis:
      host: xxx.xxx.xxx.xxx
      database:xx
      port: xxxx
      timeout: xxxx
      password: xxxxxxxxxxxxxxx
server:
  port: 9090

Effect

You can see that they are all null pointers.

Problem analysis

Is it possible that the bean is not injected into the spring container?

Modify startup class

package com.example.testdi;

import jakarta.annotation.Resource;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ApplicationContext;

import java.util.Arrays;
import java.util.List;

@EnableFeignClients
@SpringBootApplication
public class TestDiApplication extends SpringBootServletInitializer implements CommandLineRunner {

    @Resource
    private ApplicationContext appContext;

    public static void main(String[] args) {
        SpringApplication.run(TestDiApplication.class, args);
    }


    @Override
    public void run(String... args) throws Exception
    {
        String[] beans = appContext.getBeanDefinitionNames();
        Arrays.sort(beans);
        List<String> list = Arrays.stream(beans).filter(ele -> ele.contains("TestRpc") || ele.contains("redisTemplate")).toList();
        for (String bean : list)
        {
            System.out.println(bean + " of Type :: " + appContext.getBean(bean).getClass());
        }
    }
}

View console

It was found that this was not the case

Not obtained/wrong method of acquisition

Solution

Use auxiliary classes

package com.example.testdi.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationHelper implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationHelper.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

}

Modify websocket code

package com.example.testdi.websocket;

import com.example.testdi.rpc.TestRpc;
import com.example.testdi.utils.ApplicationHelper;
import jakarta.annotation.Resource;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@ServerEndpoint(value = "/example")
public class ExampleWebsocket {

    private RedisTemplate<String, Object> redisTemplate= (RedisTemplate<String, Object>) ApplicationHelper.getBean("redisTemplate");

    private TestRpc testRpc= (TestRpc) ApplicationHelper.getBean("com.example.testdi.rpc.TestRpc");

    @OnOpen
    public void open(Session session) {
        log.info("===============open=================");
        log.info("redisTemplate: {}", redisTemplate);
        log.info("testRpc: {}", testRpc);
    }
}

Effect

Some questions

How to test the websocket interface

Here are 2 recommended ones, one is postman and the other is website

postman

Now you can start testing

Website

Here is a recommended test website for testing, supporting ws/wss

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Network Skill TreeHomepageOverview 42305 people are learning the system