美文网首页
三种方式解决SpringBoot拦截器不能注入bean的问题

三种方式解决SpringBoot拦截器不能注入bean的问题

作者: 何何与呵呵呵 | 来源:发表于2018-01-25 10:59 被阅读0次
    一.原因
    • 这两天在写代码的时候遇到一个问题,为什么使用SpringBoot的时候,拦截器中使用@Autowired注入bean会报空指针.如下面代码所示,我们知道,Spring管理的bean发现有这个注解时候,它会直接注入相应的另一个Spring管理的bean.当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor (继承InstantiationAwareBeanPostProcessorAdapter)将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有@Autowired 注解时就找到和其匹配(默认按类型匹配)的 Bean,并注入到对应的地方中去。那为什么这里的注解没有生效呢?
    • 网上传说:了解SpringBoot的都知道SpringBoot的目录格式有着明确的规定,它减轻编程人员负担的同时,更加要求了编程的规范化,SpringBoot初始化的时候,会加载com.boot.app下的bean,一层一层加载,当注册LoggerInterceptor的时候,发现LoggerInterceptor中有@Autowired注解,就会去另外一个spring管理器中索取另外一个LoggerJpa,而这时候LoggerJpa根本没有初始化.所以就无法注入LoggerJpa的bean类完成相应的操作.
    • 自我理解:注册拦截器时直接通过new LoggerInterceptor(),并没有触发Spring去管理bean,所以@Autowired没有生效.
    •  /**
       * ========================
       *
       * @author 小龙虾
       * Created with IntelliJ IDEA.
       * Date:2018/1/22
       * Time:20:02
       * ========================
       */
      public class LoggerInterceptor implements HandlerInterceptor {
          public static final String SEND_TIME = "send_time";
          public static final String DATA = "param_data";
          //问题:无法注入loggerDao
          @Autowired
          private LoggerJpa loggerDao;
          /**
          * 进入springMVC的controller之前开始记录日志实体
           * @param httpServletRequest request
           * @param httpServletResponse response
           * @param o 实体类
           * @return  boolean
           * @throws Exception
           */
          @Override
          public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse         httpServletResponse, Object o) throws Exception {
              //创建日记实体类
              LoggerEntity entity = new LoggerEntity();
              //获得sessionId
              String sessionId = httpServletRequest.getRequestedSessionId();
              //请求地址信息
              String requestURI = httpServletRequest.getRequestURI();
              //请求参数信息(利用fastJson转换参数)
              String params = JSON.toJSONString(httpServletRequest.getParameterMap(),
                  SerializerFeature.DisableCircularReferenceDetect,
                  SerializerFeature.WriteMapNullValue);
              //设置客户端ip
              entity.setClientIp(LoggerUtil.getCliectIp(httpServletRequest));
              //设置请求方法
              entity.setMethod(httpServletRequest.getMethod());
              //设置请求类型
              entity.setType(LoggerUtil.getRequestType(httpServletRequest));
              //设置请求参数
              entity.setParamData(params);
              //设置请求地址
              entity.setUri(requestURI);
              //设置sessionId
              entity.setSessionId(sessionId);
              //设置请求开始时间
              httpServletRequest.setAttribute(SEND_TIME, System.currentTimeMillis());
              //设置请求实体到request内,方便afterCompletion调用
              httpServletRequest.setAttribute(DATA, entity);
              return true;
            }
          @Override
          public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
          }
      
          @Override
          public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
              //请求状态
              int status = httpServletResponse.getStatus();
              //当前时间
              long time = System.currentTimeMillis();
              //上次请求时间
              Long requestTime = Long.valueOf(httpServletRequest.getAttribute(SEND_TIME).toString());
              //获取请求日记的实体
              LoggerEntity entity = (LoggerEntity) httpServletRequest.getAttribute(DATA);
              //设置时间差
              entity.setConsuming(Long.valueOf(time-requestTime).toString());
              //设置错误码
              entity.setStatusCode(status+"");
              //设置返回值
              entity.setReturnData(JSON.toJSONString(httpServletRequest.getAttribute(LoggerUtil.LOGGER_RETURN),
                  SerializerFeature.DisableCircularReferenceDetect,
                  SerializerFeature.WriteMapNullValue));
              //通过WebApplicationContextUtils获取loggerDao
             //LoggerJpa loggerDao = getDao(LoggerJpa.class,httpServletRequest);
              //将日记写入数据库
              loggerDao.save(entity);
          }
      }
      
    二.解决方法
    • 了解到原因之后,那么如何解决呢?在这里,有两种常见的解决方法.
    ①.利用WebApplicationContextUtils去获取WebApplicationContext,然后在通过WebApplicationContext去获取相应的bean.
    • public <T> T getDao(Class<T> clazz,HttpServletRequest request){
          //通过该方法获得的applicationContext 已经是初始化之后的applicationContext 容器
          WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
          return applicationContext.getBean(clazz);
      }
      
    ②.在初始化LoggerInterceptor 之前就初始化LoggerJpa
    • /**
       * ========================
       *
       * @author 小龙虾
       * Created with IntelliJ IDEA.
       * Date:2018/1/23
       * Time:11:51
       * ========================
       */
      @Configuration
      public class LoggerConfiguration extends WebMvcConfigurerAdapter {
      
          @Bean
          public LoggerInterceptor loggerInterceptor(){
              System.out.println("嘻嘻嘻嘻");
              return new LoggerInterceptor();
          }
          /**
           * LoggerInterceptor,形成拦截链
           * @param registry 拦截器注册类
           */
          @Override
          public void addInterceptors(InterceptorRegistry registry){
              //在放入拦截器之前调用loggerInterceptor(),触发LocalContainerEntityManagerFactoryBean使得拦截器的在注册之前所有的bean都持久化
              registry.addInterceptor(loggerInterceptor()).addPathPatterns("/**");
              System.out.println("呵呵呵呵");
          }
      }
      
    ③.构造器
    • public class LoggerInterceptor implements HandlerInterceptor {
          private static final String SEND_TIME = "send_time";
          private static final String DATA = "param_data";
          private LoggerJpa loggerDao;
          public LoggerInterceptor(LoggerJpa loggerDao){
              this.loggerDao = loggerDao;
          }
      //拦截器三个方法略...
      }
      
    • /**
       * ========================
       *
       * @author 小龙虾
       * Created with IntelliJ IDEA.
       * Date:2018/1/23
       * Time:11:51
       * ========================
       */
      @Configuration
      public class LoggerConfiguration extends WebMvcConfigurerAdapter {
      
          //@Bean
          //public LoggerInterceptor loggerInterceptor(){
          //    System.out.println("嘻嘻嘻嘻")
          //    return new LoggerInterceptor(loggerDao);
          //}
          @Autowired
          private LoggerJpa loggerDao;
          /**
           * LoggerInterceptor,形成拦截链
           * @param registry 拦截器注册类
           */
          @Override
          public void addInterceptors(InterceptorRegistry registry){
              //利用构造方法注入
             registry.addInterceptor(new LoggerInterceptor(loggerDao)).addPathPatterns("/**");
              System.out.println("呵呵呵呵");
          }
      }
      

    相关文章

      网友评论

          本文标题:三种方式解决SpringBoot拦截器不能注入bean的问题

          本文链接:https://www.haomeiwen.com/subject/wecooxtx.html