Websocket引入springbean无效

发现websocket引入springbean是无效的.如下:

@Component

@ServerEndpoint(value = "/websocket/{token}")

public class WebSocketAction {

   

    @Autowired

    private UserService userService;

   

使用userService方法时报了空指针,于是在构造方法里打印排查下,主要是通过打印对象的hashcode判断对象:


 

@Component

@ServerEndpoint(value = "/websocket/{token}")

public class WebSocketAction {

   

    @Autowired

    private UserService userService;

   

   

    public ApiWebSocketAction() {

       super();
      
       WebSocketAction bean = null;
       try {
            bean = SpringUtil.getBean(ApiWebSocketAction.class);
       } catch (Exception e) {       

       }

       int code = 0;

       if (bean != null) {
           code = bean.hashCode();
       }

       System.out.println("==============="+this.hashCode());
       System.out.println("==============="+code);
       System.out.println("===============");

      

    }

项目启动中打印日志

===============1861083998

===============0

===============

每次建立连接时打印日志

===============1171159013

===============1861083998

===============

===============1171844554

===============1861083998

===============

 

可以发现spring初始化时启动了一个bean,但每次请求时并没有使用那个bean,而是建立了一个新的Object.而且这个Object并没有注入成为springbean.因为如果是springbean的话,getbean获取到的hashcode是会变的.如果还不放心,可以在onMessage里打印一下springbean,会发现其hash也没有变化.

这个初始创建的bean没有一点用啊看来.那是什么在起作用呢?

追查创建Object的栈,可以发现最终是这里执行的:

package org.apache.tomcat.websocket.server;

public class DefaultServerEndpointConfigurator

        extends ServerEndpointConfig.Configurator {

    @Override

    public <T> T getEndpointInstance(Class<T> clazz)

            throws InstantiationException {

        try {

            return clazz.getConstructor().newInstance();//这里执行

        } catch (InstantiationException e) {

            throw e;

        } catch (ReflectiveOperationException e) {

            InstantiationException ie = new InstantiationException();

            ie.initCause(e);

            throw ie;

        }

    }

而这个东西是tomcat的实现,可以发现最终调用websocket的并不是Spring的getBean方法,而是获取到了clazz直接反射获取.

那么它本身就不是bean,自然无从引入spring的bean了.
同时由于每次都是一个新的对象,那么局部变量将不再共享.

扩展一下:

怎么生成websocket对象是依据ServerEndpointConfig.Configurator,一般来说servlert容器都会有实现,比如这个例子里就是由Tomcat去实现的,我们查下会发现spring也实现了.

如下:

public class SpringConfigurator extends Configurator {


      @Override

   public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {


      WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();

      if (wac == null) {

         String message = "Failed to find the root WebApplicationContext. Was ContextLoaderListener not used?";

         logger.error(message);

         throw new IllegalStateException(message);

      }


      //通过WebApplicationContext获取该endpointClass 对应的bean
    ...
    ...

     

那么我们可以在类上注解指定Configurator

@ServerEndpoint(value = "/websocket/{token}",configurator = SpringConfigurator.class)

那么推测这样的话, websocket对象就会是springbean对象,就可以外部引入springbean.
但这个会报错,在上述方法里,wac = null, ApplicationContext不存在.

原因在于currentContextPerThread; 因为这个map里什么都没有,查看下这个mapput方法都被谁调用了,则发现最终调用者是org.springframework.web.context.ContextLoaderListenerinit调用的,这个类在springboot之前是非常重要的,因为web.xml都需要配置:

<listener>
    <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
</listener>

springboot之后不再采取这样加载了,于是乎context就没有放进去过.

所以在取出的时候报错了.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值