Changes between Initial Version and Version 1 of youhua/2017_1


Ignore:
Timestamp:
01/16/2017 04:14:09 PM (9 years ago)
Author:
wuyuanbo
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • youhua/2017_1

    v1 v1  
     1 
     2== 1.java类中EnvUtils使用优化 == 
     3 
     4 
     5在servlet处理请求时,EnvFilter中会调用EnvUtils.getEnv()实例化Env,并对实例进行参数设置,这些都是必要步骤,在非Controller类或jsp中使用EnvUtils.getEnv()可能会跳过这些步骤,从而造成程序出错。 
     6 
     7{{{ 
     8//evn过滤器代码 org.gelivable.web.EnvFilter : 62 
     9public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     10            throws IOException, ServletException { 
     11        ...... 
     12        Env env = EnvUtils.getEnv(); 
     13        envMap.put(env, ""); 
     14        try { 
     15            //下面三个变量只有servlet处理请求时才会被实例化 
     16            env.setRequest((HttpServletRequest) request); 
     17            env.setResponse((HttpServletResponse) response); 
     18            env.setServletContext(servletContext); 
     19 
     20            request.setAttribute("env", env); 
     21 
     22            chain.doFilter(request, response); 
     23 
     24        }  
     25        ...... 
     26    } 
     27}}} 
     28在聚超值项目中,entity类(service偶尔也会出现)中经常会用env获取service或dao类实例的代码。 
     29 
     30{{{ 
     31public class User { 
     32        ...... 
     33        public UserPurchasingInfo getInfo() { 
     34                ...... 
     35                info = EnvUtils.getEnv().getBean(GeliDao.class).find(UserPurchasingInfo.class, this.userId); 
     36                //或者 info = EnvUtils.getEnv().getBean(UserPurchasingInfoService.class).find(this.userId); 
     37                ...... 
     38        } 
     39        ...... 
     40} 
     41}}} 
     42这种代码至少在三种情况下调用会出现NullPointerException错误:[[BR]] 
     431.在单元测试中被调用时[[BR]] 
     442.不依赖于servlet的定时任务中被调用时[[BR]] 
     453.在处理servlet的请求时,通过代码发起的新线程中简单的调用EnvUtils.getEnv().getBean(xxx.class)获取某个类的实例会和1、2点一样出现错误。[[BR]][[BR]] 
     46 
     47'''原因'''[[BR]] 
     481、2点的错误原因比较明显,原因是在代码执行的时候没有经过过滤器,EnvUtils.getEnv()只是把Env实例化了,env对象里的servletContext参数是空的,没有进行设置,调用的时候就报空指针异常了。[[BR]] 
     49第3点报错的原因是因为EnvUtils.getEnv()用到了线程单例(代码如下),当线程第一次调用时threadLocal会实例一个Env对象,之后这个线程再调用都只返回这个对象,而且只能被这个线程调用,当在处理请求过程中如果新启了线程再调用EnvUtils.getEnv()就会得到一个新的Env实例,这个实例和1、2一样,没有设置env对象里的servletContext参数,调用env.getBean(xxx.class)的时候就会报空指针异常。 
     50{{{ 
     51public class EnvUtils { 
     52    public static Env getEnv() { 
     53        return threadLocal.get(); 
     54    } 
     55 
     56    public static void removeEnv() { 
     57        threadLocal.remove(); 
     58    } 
     59 
     60    //通过EnvUtils获取的Env实例是线程单例的,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 
     61    private static final ThreadLocal<Env> threadLocal = new ThreadLocal<Env>() { 
     62        @Override 
     63        protected Env initialValue() { 
     64            return new Env(); 
     65        } 
     66    }; 
     67 
     68} 
     69}}} 
     70'''优化方法'''[[BR]] 
     71将非Controller的java类中的EnvUtils.getEnv().getBean(GeliDao.class)改为GeliUtils.getDao(),[[BR]] 
     72将EnvUtils.getEnv().getBean(xxxService.class)改为SpringCtxUtils.getBean(xxxService.class)。(SpringCtxUtils在cn.pconline.best.util目录下)