Spring AOP 日志管理

9 篇文章 0 订阅

1.对AOP的理解 ——  分工来做各个部分,运行时候整合的思想


2.理解 面向过程,面向对象,面向切面 的思想

1)面向过程:房间装修时,准备装一个灯,就拉一根电线,连接灯。


2)面向对象:设计房间中哪些位置需要使用电线接口,然后在相应的位置设置电线接口,以备以后使用。


3)面向切面:装修房子,先设计需要在哪些地方装上电线接口,就将电线接口先设置好并且不打开接口,此处即为连接点,当此处电线切口确实需要使用时将接口打开插电器即为切入点。


方面:功能(登陆 日志)

目标:主要方面(登陆)

切面:切入点 植入 通知的综合体

连接点:可以插入副功能(日志)的地方

切入点:准备插入副功能的地方

通知:对副功能的封装对象

植入:将通知插入切入点


3.实现登陆和日志管理(使用Spring AOP)


1)LoginService   LogService   TestMain

2)用Spring 管理  LoginService 和 LogService 的对象

3)确定哪些连接点是切入点,在配置文件中

4)将LogService封装为通知

5)将通知植入到切入点

6)客户端调用目标




  1. <aop:config>
  2.     <aop:pointcut expression="execution(* cn.com.spring.service.impl.*.*(..))" id="myPointcut"/>
  3.     <!--将哪个-->
  4.     <aop:aspect id="dd" ref="logService">
  5.       <aop:before method="log" pointcut-ref="myPointcut"/>
  6.     </aop:aspect>
  7. </aop:config>

execution(* * cn.com.spring.service.impl.*.*(..))

1)* 所有的修饰符

2)* 所有的返回类型

3)* 所有的类名

4)* 所有的方法名

5)* ..所有的参数名


1.ILoginService.java


  1. package cn.com.spring.service;

  2. public interface ILoginService {
  3.     public boolean login(String userName, String password);
  4. }
2.LoginServiceImpl.java


  1. package cn.com.spring.service.impl;

  2. import cn.com.spring.service.ILoginService;

  3. public class LoginServiceImpl implements ILoginService {

  4.     public boolean login(String userName, String password) {
  5.         System.out.println("login:" + userName + "," + password);
  6.         return true;
  7.     }

  8. }

3.ILogService.java


  1. package cn.com.spring.service;

  2. import org.aspectj.lang.JoinPoint;

  3. public interface ILogService {
  4.     //无参的日志方法
  5.     public void log();
  6.     //有参的日志方法
  7.     public void logArg(JoinPoint point);
  8.     //有参有返回值的方法
  9.     public void logArgAndReturn(JoinPoint point,Object returnObj);
  10. }

4.LogServiceImpl.java


  1. package cn.com.spring.service.impl;

  2. import org.aspectj.lang.JoinPoint;

  3. import cn.com.spring.service.ILogService;

  4. public class LogServiceImpl implements ILogService {

  5.     @Override
  6.     public void log() {
  7.         System.out.println("*************Log*******************");
  8.     }
  9.     
  10.     //有参无返回值的方法
  11.     public void logArg(JoinPoint point) {
  12.         //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
  13.         Object[] args = point.getArgs();
  14.         System.out.println("目标参数列表:");
  15.         if (args != null) {
  16.             for (Object obj : args) {
  17.                 System.out.println(obj + ",");
  18.             }
  19.             System.out.println();
  20.         }
  21.     }

  22.     //有参并有返回值的方法
  23.     public void logArgAndReturn(JoinPoint point, Object returnObj) {
  24.         //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
  25.         Object[] args = point.getArgs();
  26.         System.out.println("目标参数列表:");
  27.         if (args != null) {
  28.             for (Object obj : args) {
  29.                 System.out.println(obj + ",");
  30.             }
  31.             System.out.println();
  32.             System.out.println("执行结果是:" + returnObj);
  33.         }
  34.     }
  35. }
5.applicationContext.java


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.     xmlns:p="http://www.springframework.org/schema/p"
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans 
  6.     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  7.     http://www.springframework.org/schema/aop 
  8.     http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  9.     <bean id="logService" class="cn.com.spring.service.impl.LogServiceImpl"></bean>
  10.     <bean id="loginService" class="cn.com.spring.service.impl.LoginServiceImpl"></bean>

  11.     <aop:config>
  12.         <!-- 切入点 -->
  13.         <aop:pointcut
  14.             expression="execution(* cn.com.spring.service.impl.LoginServiceImpl.*(..))"
  15.             id="myPointcut" />
  16.         <!-- 切面: 将哪个对象中的哪个方法,织入到哪个切入点 -->
  17.         <aop:aspect id="dd" ref="logService">
  18.             <!-- 前置通知
  19.             <aop:before method="log" pointcut-ref="myPointcut" />
  20.             <aop:after method="logArg" pointcut-ref="myPointcut"> 
  21.     -->
  22.             <aop:after-returning method="logArgAndReturn" returning="returnObj" pointcut-ref="myPointcut"/>
  23.         </aop:aspect>
  24.     </aop:config>
  25. </beans>
6.TestMain.java


  1. public class TestMain {
  2. public static void testSpringAOP(){
  3.         ApplicationContext ctx = new ClassPathXmlApplicationContext("app*.xml");
  4.         
  5.         ILoginService loginService = (ILoginService)ctx.getBean("loginService");
  6.         loginService.login("zhangsan", "12344");
  7. }
  8. public static void main(String[] args) {
  9. testSpringAOP();
  10. }
  11. }
7.输出结果:

  1. login:zhangsan,12344
  2. 目标参数列表:
  3. zhangsan,
  4. 12344,

  5. 执行结果是:true
解析:1.先调用了login()方法System.out.println("login:" + userName + "," + password);

     2.再调用了logArgAndReturn()方法输出了日志,并且返回了login()方法是否成功


  1. System.out.println("目标参数列表:");
  2.         if (args != null) {
  3.             for (Object obj : args) {
  4.                 System.out.println(obj + ",");
  5.             }
  6.             System.out.println();
  7.             System.out.println("执行结果是:" + returnObj);
  8.         }



  1. <aop:config>
  2.     <aop:pointcut expression="execution(* cn.com.spring.service.impl.*.*(..))" id="myPointcut"/>
  3.     <!--将哪个-->
  4.     <aop:aspect id="dd" ref="logService">
  5.       <aop:before method="log" pointcut-ref="myPointcut"/>
  6.     </aop:aspect>
  7. </aop:config>

execution(* * cn.com.spring.service.impl.*.*(..))

1)* 所有的修饰符

2)* 所有的返回类型

3)* 所有的类名

4)* 所有的方法名

5)* ..所有的参数名


1.ILoginService.java


  1. package cn.com.spring.service;

  2. public interface ILoginService {
  3.     public boolean login(String userName, String password);
  4. }
2.LoginServiceImpl.java


  1. package cn.com.spring.service.impl;

  2. import cn.com.spring.service.ILoginService;

  3. public class LoginServiceImpl implements ILoginService {

  4.     public boolean login(String userName, String password) {
  5.         System.out.println("login:" + userName + "," + password);
  6.         return true;
  7.     }

  8. }

3.ILogService.java


  1. package cn.com.spring.service;

  2. import org.aspectj.lang.JoinPoint;

  3. public interface ILogService {
  4.     //无参的日志方法
  5.     public void log();
  6.     //有参的日志方法
  7.     public void logArg(JoinPoint point);
  8.     //有参有返回值的方法
  9.     public void logArgAndReturn(JoinPoint point,Object returnObj);
  10. }

4.LogServiceImpl.java


  1. package cn.com.spring.service.impl;

  2. import org.aspectj.lang.JoinPoint;

  3. import cn.com.spring.service.ILogService;

  4. public class LogServiceImpl implements ILogService {

  5.     @Override
  6.     public void log() {
  7.         System.out.println("*************Log*******************");
  8.     }
  9.     
  10.     //有参无返回值的方法
  11.     public void logArg(JoinPoint point) {
  12.         //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
  13.         Object[] args = point.getArgs();
  14.         System.out.println("目标参数列表:");
  15.         if (args != null) {
  16.             for (Object obj : args) {
  17.                 System.out.println(obj + ",");
  18.             }
  19.             System.out.println();
  20.         }
  21.     }

  22.     //有参并有返回值的方法
  23.     public void logArgAndReturn(JoinPoint point, Object returnObj) {
  24.         //此方法返回的是一个数组,数组中包括request以及ActionCofig等类对象
  25.         Object[] args = point.getArgs();
  26.         System.out.println("目标参数列表:");
  27.         if (args != null) {
  28.             for (Object obj : args) {
  29.                 System.out.println(obj + ",");
  30.             }
  31.             System.out.println();
  32.             System.out.println("执行结果是:" + returnObj);
  33.         }
  34.     }
  35. }
5.applicationContext.java


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.     xmlns:p="http://www.springframework.org/schema/p"
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans 
  6.     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  7.     http://www.springframework.org/schema/aop 
  8.     http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

  9.     <bean id="logService" class="cn.com.spring.service.impl.LogServiceImpl"></bean>
  10.     <bean id="loginService" class="cn.com.spring.service.impl.LoginServiceImpl"></bean>

  11.     <aop:config>
  12.         <!-- 切入点 -->
  13.         <aop:pointcut
  14.             expression="execution(* cn.com.spring.service.impl.LoginServiceImpl.*(..))"
  15.             id="myPointcut" />
  16.         <!-- 切面: 将哪个对象中的哪个方法,织入到哪个切入点 -->
  17.         <aop:aspect id="dd" ref="logService">
  18.             <!-- 前置通知
  19.             <aop:before method="log" pointcut-ref="myPointcut" />
  20.             <aop:after method="logArg" pointcut-ref="myPointcut"> 
  21.     -->
  22.             <aop:after-returning method="logArgAndReturn" returning="returnObj" pointcut-ref="myPointcut"/>
  23.         </aop:aspect>
  24.     </aop:config>
  25. </beans>
6.TestMain.java


  1. public class TestMain {
  2. public static void testSpringAOP(){
  3.         ApplicationContext ctx = new ClassPathXmlApplicationContext("app*.xml");
  4.         
  5.         ILoginService loginService = (ILoginService)ctx.getBean("loginService");
  6.         loginService.login("zhangsan", "12344");
  7. }
  8. public static void main(String[] args) {
  9. testSpringAOP();
  10. }
  11. }
7.输出结果:

  1. login:zhangsan,12344
  2. 目标参数列表:
  3. zhangsan,
  4. 12344,

  5. 执行结果是:true
解析:1.先调用了login()方法System.out.println("login:" + userName + "," + password);

     2.再调用了logArgAndReturn()方法输出了日志,并且返回了login()方法是否成功



补充一篇AOP注解方式实现的

利用spring AOP实现每个请求的日志输出

前提条件:

除了spring相关jar包外,还需要引入aspectj包。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.2</version>
  </dependency>

要实现此功能,必须完成以下几步:

1.在springmvc-servlet.xml中实现对AOP的支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:aop="http://www.springframework.org/schema/aop" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xsi:schemaLocation="   
  http://www.springframework.org/schema/beans   
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd   
  http://www.springframework.org/schema/context   
  http://www.springframework.org/schema/context/spring-context-4.0.xsd  
  http://www.springframework.org/schema/mvc   
  http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
  http://www.springframework.org/schema/aop 
         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
         
  <aop:aspectj-autoproxy proxy-target-class="true"/>
  <bean class="com.yusj.interceptor.LogAspect" />
.
.
.
.
</beans>

2.注解的方法实现Aspect

package com.yusj.core.interceptor;

import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.gson.Gson;

/**
 * 
* @ClassName: LogAspect 
* @Description: 日志记录AOP实现 
* @author shaojian.yu
* @date 2014年11月3日 下午1:51:59 
*
 */
@Aspect
public class LogAspect {
  private final Logger logger = LoggerFactory.getLogger(this.getClass());

  private String requestPath = null ; // 请求地址
  private String userName = null ; // 用户名
  private Map<?,?> inputParamMap = null ; // 传入参数
  private Map<String, Object> outputParamMap = null; // 存放输出结果
  private long startTimeMillis = 0; // 开始时间
  private long endTimeMillis = 0; // 结束时间

  /**
   * 
   * @Title:doBeforeInServiceLayer
   * @Description: 方法调用前触发 
   *  记录开始时间 
   * @author shaojian.yu 
   * @date 2014年11月2日 下午4:45:53
   * @param joinPoint
   */
  @Before("execution(* com.yusj.controller..*.*(..))")
  public void doBeforeInServiceLayer(JoinPoint joinPoint) {
    startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间
  }

  /**
   * 
   * @Title:doAfterInServiceLayer
   * @Description: 方法调用后触发 
   *  记录结束时间
   * @author shaojian.yu 
   * @date 2014年11月2日 下午4:46:21
   * @param joinPoint
   */
  @After("execution(* com.yusj.controller..*.*(..))")
  public void doAfterInServiceLayer(JoinPoint joinPoint) {
    endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间
    this.printOptLog();
  }

  /**
   * 
   * @Title:doAround
   * @Description: 环绕触发 
   * @author shaojian.yu 
   * @date 2014年11月3日 下午1:58:45
   * @param pjp
   * @return
   * @throws Throwable
   */
  @Around("execution(* com.yusj.controller..*.*(..))")
  public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
    /**
     * 1.获取request信息
     * 2.根据request获取session
     * 3.从session中取出登录用户信息
     */
    RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes sra = (ServletRequestAttributes)ra;
    HttpServletRequest request = sra.getRequest();
    // 从session中获取用户信息
    String loginInfo = (String) session.getAttribute("username");
    if(loginInfo != null && !"".equals(loginInfo)){
      userName = operLoginModel.getLogin_Name();
    }else{
      userName = "用户未登录" ;
    }
    // 获取输入参数
    inputParamMap = request.getParameterMap();
    // 获取请求地址
    requestPath = request.getRequestURI();
    
    // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
    outputParamMap = new HashMap<String, Object>();
    Object result = pjp.proceed();// result的值就是被拦截方法的返回值
    outputParamMap.put("result", result);
    
    return result;
  }

  /**
   * 
   * @Title:printOptLog
   * @Description: 输出日志 
   * @author shaojian.yu 
   * @date 2014年11月2日 下午4:47:09
   */
  private void printOptLog() {
    Gson gson = new Gson(); // 需要用到google的gson解析包
    String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
    logger.info("\n user:"+userName
        +"  url:"+requestPath+"; op_time:" + optTime + " pro_time:" + (endTimeMillis - startTimeMillis) + "ms ;"
        +" param:"+gson.toJson(inputParamMap)+";"+"\n result:"+gson.toJson(outputParamMap));
  }
}
这里 spring的ServletRequestAttributes创建request()得到空指针

((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();

查看RequestContextHolder源代码,发现该类中有提到RequestContextListener

再查看RequestContextListener的源代码,其中有个方法


public void requestInitialized(ServletRequestEvent requestEvent) {
  if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
   throw new IllegalArgumentException(
     "Request is not an HttpServletRequest: " +

requestEvent.getServletRequest());
  }
  HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
  ServletRequestAttributes attributes = new ServletRequestAttributes(request);
  request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
  LocaleContextHolder.setLocale(request.getLocale());
  RequestContextHolder.setRequestAttributes(attributes);  //把requestAttributes的属性设置好
  if (logger.isDebugEnabled()) {
   logger.debug("Bound request context to thread: " + request);
  } }

所以,要在web.xml下面配置好监听,让服务器启动时就初始化改类,可以得到request

<listener>
 <listener-class>
  org.springframework.web.context.request.RequestContextListener
 </listener-class>
</listener>

 

这样就可以了正常执行
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值