SpringAop(日志记录)的实现

基于xml

1、环境搭建,添加需要引入的依赖

  • spring-aop(spring-context, 把aop加载类),
  • spring-aspects
<!-- 导入了context,会自动导入先关依赖,包括spring-aop -->    
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.3.RELEASE</version>
</dependency>
<!--aop实现的框架 Aspects-->
<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.3.RELEASE</version>
 </dependency>

2、创建一个通知/增强类

//将advice包下的LogAdvice交给spring容器管理
@Component("logAdvice") public class LogAdvice { // 使用log4j日志框架进行日志的记录 // Logger Log4j进行日志输出的的类 private Logger log = Logger.getLogger(LogAdvice.class); // 编写增强方法、前置增强 // JoinPoint 连接点对象,就是正在运行的目标方法的对象 public void beforeLog(JoinPoint joinPoint) { /* * log.debug("debug"); // 对应debug输出级别 * log.info("info"); // 对应info输出级别 * log.warn("warn"); // 对应warn输出级别 * log.error("error"); // 对应error输出级别 */ //得到目标对象 Object target = joinPoint.getTarget(); //由对象获取这个对象所在类的类名 getName() 获取的 包.类名的字符串 getSimpleName() 获取类名 String className = target.getClass().getSimpleName(); //得到正在执行的目标方法的签名(例:public int findUserById(int id)) String methodName = joinPoint.getSignature().getName(); //得到调用目标方法传递参数 Object[] args = joinPoint.getArgs(); //输出日志 log.info("开始执行:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args)); //打印结果:com.zl.spring.advice.LogAdvice - 开始执行:UserServiceImpl的findUserById,传递的参数[2] } /** * 后置增强方法 * 得到目标方法的返回值 * rs: 接收目标方法的返回值 如果目标方法没有返回值, 得到null * @param joinPoint */ public void afterLog(JoinPoint joinPoint,Object rs) { Object target = joinPoint.getTarget(); String className = target.getClass().getSimpleName(); String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); log.info("后置增强开始执行:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args)+"目标方法的返回值:"+rs); } //最终增强方法 public void finallyLog(JoinPoint joinPoint) { Object target = joinPoint.getTarget(); String className = target.getClass().getSimpleName(); String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); log.info("最终增强开始执行:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args)); } //异常增强方法 //指定异常(exception\SQLException public void throwLog(JoinPoint joinPoint,RuntimeException e) { Object target = joinPoint.getTarget(); String className = target.getClass().getSimpleName(); String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); log.info("异常增强开始执行:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args) +"出现异常"); }

其中环绕增强应该新建一个类,一个类可以有以上四种增强

//环绕增强
public
Object aroundLogger(ProceedingJoinPoint jp) throws Throwable{ log.info(jp.getSignature().getName()+"方法开始执行"); try { //执行目标方法 Object rs = jp.proceed(); log.info(jp.getSignature().getName()+"方法正常执行完"); return rs; } catch (SQLException e) { log.error("调用"+jp.getTarget()+"的"+jp.getSignature().getName() +"方法发生异常"+e); throw e; } }

3、 进行织入, 在spring的配置文件进行织入

  使用前缀为:aop 的标签

①、导入命名空间

xmlns:aop="http://www.springframework.org/schema/aop"
...
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd

配置aop

②、切入点的配置(将service包下的所有类,运行方法进行增强)

<aop:config>
    <aop:pointcut expression="execution(  *  spring06.service..*.*(..) )" id="pointcut1"/>

语法:

<!-- 切入点
     id: 唯一标示符         expression: 切入点的表达式
语法格式  execution([访问修饰符]  返回值类型   包名.类名.方法名(参数列表) )
execution(public  void   spring06.service.impl.UserServiceImpl.findById(int) )  对一个方法的增强
通配符:  * 任意,   返回值可以使用,  类名可以使用,  方法名可以使用
在类名前加两个点: 表示这个包以及这个包所有的子包下的类参数表示任意: ..
 execution(  *    spring06.service..*.*(..) )
 -->

③、增强的配置

通知类(增强的方法) ref: 对应通知类的bean的id
<aop:aspect ref="logAdvice">

④、织入(满足条件进行织入)

<!-- 增强策略 : 增强分类的调用的方法-->
<!-- 配置一个前置增强
method: 前置增强的方法名      pointcut-ref: 引用的切入点
织入: 对符合切入点的方法进行前置增强, 增强的方法是logAdvice的beforeLog()的方法
 -->
<aop:before method="beforeLog"   pointcut-ref="pointcut1"/>
<!-- 后置增强 
public void  afterLog(JoinPoint joinPoint, Object rs) 
returning="参数名" 告诉spring,把目标方法的返回值赋值给这个增强方法的哪一个参数上,
    要求returning后面的参数,与方法的接收返回值的参数名一样
-->
<aop:after-returning method="afterLog" pointcut-ref="pointcut1" returning="rs" />
<!-- 最终增强:  不管是否发生异常, 都会执行 -->
<aop:after method="finallyLog" pointcut-ref="pointcut1"/>
<!-- 配置异常增强
throwing: 参数名, 告诉spring,把异常对象赋值给增强方法的那个异常参数上
 -->
<aop:after-throwing method="throwLog" pointcut-ref="pointcut1"  throwing="e"/>
  </aop:aspect>
</aop:config>

如果在通知类中没有使用注解的形式交给spring管理可以使用默认构造方法

<!-- 通知类交给spring管理 -->
<bean id="logAdvice" class="spring06.advice.LogAdvice"></bean>

4、扫描注解

<!-- 扫描注解 base-package: 包名, 扫描这个包,以及这个包后代包下所有类上的注解 -->
<context:component-scan base-package="spring06" />

基于注解的方式

通知类使用注解

  @Aspect //定义为一个通知类

方式一:

@Component("logAdvice2")
@Aspect //定义为一个通知类
public class LogAdvice2 {
    private Logger log = Logger.getLogger(LogAdvice2.class);
//最终增强方法
    @After("execution( *  com.zl.spring.service..*.*(..) )")
    public void finallyLog(JoinPoint joinPoint) {
        Object target = joinPoint.getTarget();
        String className = target.getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        
        Object[] args = joinPoint.getArgs();
        log.info("最终增强开始执行2:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args));
    }
        
    //异常增强方法
    //指定异常(exception\SQLException
    @AfterThrowing(value="execution( *  com.zl.spring.service..*.*(..) )",throwing = "e")
    public void throwLog(JoinPoint joinPoint,RuntimeException e) {
        Object target = joinPoint.getTarget();
        String className = target.getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        log.info("异常增强开始执行2:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args) +"出现异常");
    }

方式二:

@Component("logAdvice2")
@Aspect //定义为一个通知类
public class LogAdvice2 {
    private Logger log = Logger.getLogger(LogAdvice2.class);

    //加在方法上
    @Pointcut("execution(  *  spring06.service..*.*(..) )" )  
    private void  pit() {}
    @Before("pit()")
    public void beforeLog(JoinPoint joinPoint) {
        Object target = joinPoint.getTarget();
        String className = target.getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        log.info("开始执行2:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args));
    }
    //后置增强方法
    @AfterReturning(value="pit()",returning="rs")
    public void afterLog(JoinPoint joinPoint,Object rs) {
        Object target = joinPoint.getTarget();
        String className = target.getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        log.info("后置增强开始执行2:"+className+"的"+methodName+",传递的参数"+Arrays.asList(args)+"目标方法的返回值:"+rs);
    }

applicationContext.xml中扫描注解:

    <!-- 扫描注解 base-package: 包名, 扫描这个包,以及这个包后代包下所有类上的注解 -->
    <context:component-scan base-package="com.zl.spring" />
    
    <!-- 扫描通知类中的注解 -->
    <aop:aspectj-autoproxy/>

 

posted @ 2020-06-13 14:28  64Byte  阅读(329)  评论(0编辑  收藏  举报