SpringBoot 使用 @ServerEndpoint 后 @Autowired 失效问题分析和解决

在SpringBoot中集成WebSocket时,@ServerEndpoint注解会导致@Autowired注解失效,因为WebSocket的多实例特性与Spring的单例模式冲突。为了解决这个问题,可以使用静态变量结合setter方法注入,或者利用SpringCtxUtils动态从Spring容器中获取Servicebean。
摘要由CSDN通过智能技术生成

SpringBoot 集成 WebSocket 实现消息群发推送

后续发现使用 @ServerEndpoint 后,@Autowired 就失效了,这是为什么呢?

问题描述

在具体的业务场景中,需要等用户连接成功后,从库表中先获取10条数据,作为默认的初始化数据进行显示。

我们想当然的通过 @Autowired 注解将对应 Service 进行依赖注入。却发现报了空指针的异常,也就是说,所需要的 Service 没有被成功注入。

当前写法如下:


@ServerEndpoint("/imserver/{userId}")

@Component

public class WebSocketServer {

    @Autowired

    private OrderService orderService;

}

问题分析

Spring管理采用单例模式(singleton),而 WebSocket 是多对象的,即每个客户端对应后台的一个 WebSocket 对象,也可以理解成 new 了一个 WebSocket,这样当然是不能获得自动注入的对象了,因为这两者刚好冲突。
@Autowired 注解注入对象操作是在启动时执行的,而不是在使用时,而 WebSocket 是只有连接使用时才实例化对象,且有多个连接就有多个对象。
所以我们可以得出结论,这个 Service 根本就没有注入到 WebSocket 当中。

解决方案

@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {
    private static OrderService orderService;
    @Autowired
    public void setOrderService(OrderService service) {
        WebSocketServer.orderService = orderService;
    }
}

方法二 动态的从 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);
好的,下面是一个基于 Spring Boot 的用户登录案例: 1. 创建 User 实体类 ```java @Data public class User { private String username; private String password; } ``` 2. 创建 UserService 接口和实现类 ```java public interface UserService { User login(String username, String password); } @Service public class UserServiceImpl implements UserService { @Override public User login(String username, String password) { // 在这里校验用户名和密码是否正确,省略实现 return new User(username, password); } } ``` 3. 创建 UserController 控制器 ```java @Controller public class UserController { @Autowired private UserService userService; @PostMapping("/login") @ResponseBody public String login(@RequestBody User user) { User loginUser = userService.login(user.getUsername(), user.getPassword()); if (loginUser != null) { return "登录成功"; } else { return "用户名或密码错误"; } } } ``` 4. 配置 mybatis 和数据库信息 在 application.properties 文件中添加以下配置: ``` spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10 spring.datasource.username=root spring.datasource.password=root mybatis.mapper-locations=classpath:mapper/*.xml ``` 5. 创建 UserMapper 接口和 XML 映射文件 ```java @Mapper public interface UserMapper { User selectByUsernameAndPassword(@Param("username") String username, @Param("password") String password); } ``` 在 mapper 文件夹下创建 UserMapper.xml 文件,编写 SQL 语句: ```xml <mapper namespace="com.example.demo.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.example.demo.entity.User"> <id column="username" property="username" /> <result column="password" property="password" /> </resultMap> <select id="selectByUsernameAndPassword" resultMap="BaseResultMap"> select * from user where username=#{username} and password=#{password} </select> </mapper> ``` 6. 编写测试代码 ```java @RunWith(SpringRunner.class) @SpringBootTest public class UserControllerTests { @Autowired private UserController userController; @Test public void testLogin() { User user = new User(); user.setUsername("admin"); user.setPassword("123456"); String result = userController.login(user); assertEquals("登录成功", result); } } ``` 以上就是一个基于 Spring Boot 的用户登录案例的实现过程,希望对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值