C#的HttpModule中及Java的Servlet中成员变量乱用导致的不易重现的BUG

3年前写的在HttpModule中记录访问日志的代码,在最近使用日志数据分析登录账号的IP情况时,才发现了一个不易重现的BUG——日志中记录的登录账号出现串掉的情况。之所以这个时候才发现该问题,是因为部分用户的IP是固定的,但是日志里却出现了别人的IP。而之所以3年后才发现,是因为这块日志数据一直没怎么用过。回头想想,根本原因还是在用成员变量的时候没考虑到多线程的情况,或者说多用户同时访问的情况。因为HttpModule里的事件,是所有页面实例共用的。

问题代码:

        string dateBeginRequest;//开始请求时间
        string userName;//用户名

        public void Init(HttpApplication application)
        {
            application.AcquireRequestState += (new EventHandler(this.Application_AcquireRequestState));
            application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
            application.EndRequest += (new EventHandler(this.Application_EndRequest));
        }

实现System.Web.IHttpModule的类中,有两个导致BUG的字符串成员变量。其中字符串成员变量dateBeginRequest在Application_BeginRequest事件方法中赋值,字符串成员变量userName在AcquireRequestState 事件方法中赋值,值来源于Session。当在本地调试时很难重现用户A的账号记录到用户B的日志数据中,这种情况。但是当生产环境有一定的并发请求的时候,就会出现用户A的账号记录到用户B的日志数据中,日志数据中请求开始时间这个字段也会出现同样的问题。

解决办法就是把这部分记录请求日志的代码,转移到各页面的基类中,因为各页面的后台类实例是独立的,互不影响。

上述问题在我们写的基于Servlet的Java开发框架中也出现了,解决办法是在方法内部创建对象实例,而不是使用类的成员变量来赋值再使用。之所以Servlet中成员变量也会出现该问题,是因为Servlet的service等方法也是所有映射到的请求都会进入该方法,存在并发的情况。

本文首发于我的CSDN博客:https://blog.csdn.net/n_ithero/article/details/104062423

原文地址:https://www.cnblogs.com/xuezhizhang/p/12228519.html

时间: 2024-11-08 16:52:28

C#的HttpModule中及Java的Servlet中成员变量乱用导致的不易重现的BUG的相关文章

什么是java的局部变量,成员变量,全局变量?

public class Test { private String name;//成员变量,也是全局变量 public void changeName() { String n = "tomoya";//n就是局部变量 name = n; }} 总的来说,定义在类里的,也就是name那个位置,就是成员变量,在JAVA里全局变量和成员变量是一个意思.定义在方法里或域里就叫做局部变量,所谓域就是{}里面,比如public void show() { int b = 2;//局部变量 if

[Java][Web] Servlet中转发和重定向比较

Servlet中页面跳转的两种方式 请求转发 使用requestDispatcher对象 request.getRequestDispatcher("path").forward(request, response); 使用JSP动作元素 <jsp:forward page="/"> 请求重定向 使用response的sendRedirect方法 response.sendRedirect("path"); 请求转发与请求重定向的区别

Strut2中的session和servlet中的session的区别

在jsp中,内通过内置对象 HttpServletRequest的getSession()方法可以获取到HttpSession,比如: 1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@taglib uri="http://www.wyl.suneyaee" prefi

[Java] 继承中,父类被覆盖的成员变量、方法的可访问性

在 Java 的继承机制里,在子类内部,可以访问父类被覆盖的变量和方法:在子类外部,可以访问父类的被覆盖变量,但是不能访问父类的被覆盖方法. 父类中被覆盖的方法不能在外部被方法,这是出于封装的考虑. 例子: Super, 父类,拥有一个成员变量 x ,和成员方法 doSomething(). Point,继承 Super, 但覆盖了 Super 的 x 和 doSomething(),拥有自己的同名成员成员 x 和 doSomething(). StaticDemo1, 演示在继承中,在内部,可

java中的类修饰符、成员变量修饰符、方法修饰符。

类修饰符: public(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类. abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现. final,将一个类生命为最终(即非继承类),表示他不能被其他类继承. friendly,默认的修饰符,只有在相同包中的对象才能使用这样的类. 成员变量修饰符: public(公共访问控制符),指定该变量为公共的,他可以被任何对象的方法访问. private(私有访问控制符)指定该变量只允许自己的类的方法

java中的类修饰符、成员变量修饰符、方法修饰符

类修饰符:  public(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类. abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现. final,将一个类生命为最终(即非继承类),表示他不能被其他类继承. friendly,默认的修饰符,只有在相同包中的对象才能使用这样的类. 成员变量 和 方法的访问权限

java面向对象学习之——java中的类修饰符、成员变量修饰符、方法修饰符

类修饰符: public(访问控制符)-->将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类.abstract-->将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现.final-->将一个类生命为最终(即非继承类),表示他不能被其他类继承.friendly-->默认的修饰符,只有在相同包中的对象才能使用这样的类. 成员变量修饰符: public(公共访问控制符)-->指定该变量为公共的,他可以被任何对象的方法访问.private(私有访问控制符

Java接口里定义成员变量 说明

首先你要弄清接口的含义.接口就是提供一种统一的'协议',而接口中的属性也属于'协议'中的成员.它们是公共的,静态的,最终的常量.相当于全局常量. 在interface里面的变量都是public static final 的.所以你可以这样写: public static final int i=10; 或则 int i=10;(可以省略掉一部分,在接口里的成员变量默认就是public static final) 注意在声明的时候要给变量赋予初值 解释: 首先你要弄清接口的含义.接口就是提供一种统

Java 的局部变量和成员变量

在Java语言中没有全局变量  分析各种变量的作用域的最简单方法是以花括号为界, 1.在类体中定义的是成员变量,成员变量会被默认初始化 2.在方法中定义的是局部变量,局部变量不会被默认初始化