Sobre la importancia de mirar el código fuente, el segundo año escrito al programador

Periodista: desde que me gradué en junio de 2018, estoy a punto de entrar en un punto de inflexión para los programadores en el segundo al tercer año.

Antes de escribir el código, siempre hacía mi propia cabeza, y escribía cada vez más engreído, pero el progreso técnico real rara vez se ve. Ahora que he entrado en el período de suspensión, los requisitos comerciales básicos se pueden escribir, pero el encuentro real En algunos problemas extraños, siento una profunda sensación de impotencia.

La escena que aparece es la siguiente:

1. Las necesidades comerciales de la empresa, los usuarios integrados, desean lograr un método de inicio de sesión único, cierre de sesión, elija el marco de trabajo cas.

2. Fallo extraño, el proyecto original integra el cliente cas ocasionalmente, la excepción no es interceptada por la excepción global y la información de la pila se imprime directamente en la página.

Para el escenario uno:

  El antiguo proyecto original de la compañía está conectado a cas e integrado en el cliente cas del proyecto, pero a menudo no se cierra la sesión en un solo punto. El método utilizado es repetir la escena del error y localizarlo para ver si se genera regularmente. Como sabemos, la máquina no será engañosa. Después de muchas pruebas y reproducciones repetidas, el problema se reproducirá de manera constante. . De la siguiente manera: Sistema A y Sistema B Si el usuario llama a la interfaz de cierre de sesión en el Sistema A, el Sistema B. debe cerrar la sesión. Si el usuario llama a la interfaz de cierre de sesión de un solo punto en el Sistema B, el Sistema A cerrará la sesión con cierta probabilidad.

  El proyecto cas fue escrito anteriormente por un colega de la compañía y ahora que el colega dejó el trabajo y se hizo cargo del proyecto, solo puede mirarlo sin brillo. En vista del problema del escenario recurrente, se solicitó el escenario de implementación, y la suposición fue causada por el problema del clúster. El proyecto A se implementa en un clúster, Java tiene dos máquinas y el proyecto B es una sola máquina. La suposición inicial puede ser que cuando el proyecto A cierra la sesión, se notifica al proyecto B y se debe notificar a la única máquina. Cuando el proyecto B notifica al proyecto A de la notificación ocasional. (Para comprender esta descripción simplemente, el proceso de notificación real es: Proyecto A-> cas-> Proyecto B o Proyecto B-> cas-> Proyecto A).

  Al buscar soluciones en Internet, vi tres soluciones: (1) Cambiar la configuración del proyecto de clúster A a hash de ip, el método en línea real es el sondeo de ip (2) la transmisión de ip se utiliza para la notificación Forma, difunde la IP desplegada por la máquina, y si la máquina no se ejecuta con éxito, se enviará a la siguiente máquina. (3) Reescribir el almacenamiento de la sesión.

  Lo anterior es la solución, pero no hay una explicación muy detallada sobre por qué este problema ocurre en cas. La especulación personal se debe a que el logotipo utilizado como inicio de sesión se almacena en la memoria, no en redis, pero cuando se hizo cargo del proyecto, los colegas dijeron claramente que el logotipo se almacena en redis, y la situación que se ve en la biblioteca de redis sí se almacena. Y cuando falla, esta clave en redis tampoco tiene valor, pero en el caso de falla de cierre de sesión, este valor en redis todavía existe. La solución para leer blogs en Internet es que vi un artículo que decía que -cas en sí mismo no admite la agrupación. De repente me di cuenta de que fui a mirar el código que almacena la ID de sesión en el código fuente, de la siguiente manera:

la clase final pública HashMapBackedSessionMappingStorage implementa SessionMappingStorage { 
    mapa final privado <String, HttpSession> MANAGED_SESSIONS = new HashMap (); 
    mapa final privado <String, String> ID_TO_SESSION_KEY_MAPPING = new HashMap (); 
    privado final Logger logger = LoggerFactory.getLogger (this.getClass ()); 

    public HashMapBackedSessionMappingStorage () { 
    } 

    público vacío sincronizado addSessionById (String mappingId, HttpSession session) { 
        this.ID_TO_SESSION_KEY_MAPPING.put (session.getId (), mappingId); 
        this.MANAGED_SESSIONS.put (mappingId, session); 
    } 
}

  Se puede ver que la clase de implementación de SessionMappingStorage en realidad almacena el contenido de la sesión y la sesión y la asignación de la relación de mapeo se almacena en el mapa, que se escribe en la memoria. Entonces no es difícil resolver este problema. Vuelva a escribir la implementación de este método y agréguelo al filtro. Ambas relaciones se almacenan usando redis. Fin, espolvorea flores. Algunas personas en Internet también usan el método de transmisión, que también es muy bueno, pero en términos comparativos, el costo de implementación es relativamente grande y no es una solución fundamental al problema. También es posible construir un clúster en el servidor de prueba utilizando el método de hash de ip, pero el líder no permite el uso de ip hash enenen en línea, por lo que este es un callejón sin salida.

  En resumen, el código fuente no es tan terrible. Encuentre ideas y concéntrese en el problema para ver el problema, y ​​la solución sale.

Para el escenario dos:

  Al escribir un proyecto de Java, generalmente escribimos una clase global de manejo de excepciones al comienzo de la creación del proyecto, y encapsulamos las excepciones causadas por errores de código u otros problemas en el sistema en una forma fija de mensaje de código y lo devolvemos a la página principal. Antes de que el proyecto se ejecute sin problemas, después de la introducción del cliente cas, cuando se resuelve el problema de cierre de sesión único: el acceso a la interfaz 500, la información de la pila se imprime directamente en primer plano.

  Todavía necesito localizar el problema primero. Sospeché que estaba relacionado con el tipo de excepción. En la interfaz de inicio de sesión, la verificación del ticket no pasó. Si el inicio de sesión falla, se imprime como TicketValidationException. También ha ocurrido porque el servidor redis se cuelga: RedisConnectionFailureException. Simular localmente

@GetMapping ("/ test") 
    public void test () lanza Exception { 
        throw new TicketValidationException ("excepción de validación de ticket"); 
        // lanza una nueva RedisConnectionFailureException ("excepción de conexión redis"); 
    }

  Ambas excepciones pueden ser interceptadas y devueltas normalmente. Hasta ahora, de esta manera no funciona, no hay ninguna razón para que el tipo de excepción encuentre la ubicación de la excepción y encontró el siguiente código:

public void doFilter (ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) arroja IOException, ServletException { 
        HttpServletRequest request = (HttpServletRequest) servletRequest; 
        HttpServletResponse response = (HttpServletResponse) servletResponse; 
        if (! this.handlerInitialized.getAndSet (true)) { 
            HANDLER.init (); 
        } 

        if (HANDLER.process (solicitud, respuesta)) { 
            filterChain.doFilter (servletRequest, servletResponse); // 发生 异常 的 代码 行
        } 

    }

  Bueno, no es fácil. Trataré de atraparte. Primero cogeré la TicketValidationException para simular el fallo del boleto en la línea, y luego me sorprendí. Todavía imprimí la información de la pila en la primera página, y luego el viernes Es casi la hora de salir del trabajo, todos lo saben, esta pregunta se pone en espera. Después de regresar a casa, todavía estaba pensando en este problema. Encendí la computadora e intenté RedisConnectionFailureException, pero la página devuelta seguía siendo incorrecta. Después de reescribir la respuesta aquí, regrese normalmente. El método para reescribir la respuesta es el siguiente:

public static void outResponse (respuesta HttpServletResponse, objeto Object) { 
        response.setCharacterEncoding ("UTF-8"); 
        response.setContentType ("aplicación / json; charset = utf-8"); 
        PrintWriter out = null; 
        pruebe { 
            out = response.getWriter (); 
            out.append (JSONObject.toJSONString (objeto)); 
        } catch (IOException e) { 
            e.printStackTrace (); 
        } finalmente { 
            if (out! = null) { 
                out.close (); 
            } 
        } 
    }

  La conexión de redis se resuelve de manera anormal. ¿Qué pasa con la falla de la verificación del ticket? Después de detectar la excepción de conexión redis, tome la clase de excepción grande Excepción, responda la salida y descubra que puede ser interceptada. Entonces, ¿por qué no se puede interceptar esta excepción si falla la verificación del ticket? Observe la implementación en el código fuente:

catch (TicketValidationException var8) { 
    this.logger.debug (var8.getMessage (), var8); 
    this.onFailedValidation (solicitud, respuesta); 
    if (this.exceptionOnValidationFailure) { 
      lanzar nueva ServletException (var8); 
    } 
    response.sendError (403, var8.getMessage ()); 
    regreso;

  Bueno, lo que arrojó aquí es en realidad el código de modificación de ServletException. El contenido capturado cuando se produce una excepción de ticket debe capturar la excepción ServletException.

  Cuando escuché el código fuente, me sentí como un gran tigre parado allí, pero cuando lo estudié seriamente, fui realmente gentil y amable como un gatito. No se descarta que el código escrito por el jefe sea oscuro y difícil de entender, pero después de todo, está escrito por personas ~, siempre que esté dispuesto a leerlo cuidadosamente, definitivamente ganará algo. Espero que la epidemia pase rápidamente y que todos sean tratados bien en 2020.

Supongo que te gusta

Origin www.cnblogs.com/cswxl/p/12691370.html
Recomendado
Clasificación