Spring----面向切面编程和通知类型

面向过程:算法+数据结构

面向对象(OOP):对象+消息

面向接口:多态性

面向切面(AOP):把非业务逻辑的功能,提取出来,定义成一个一个的切面。当你的程序运行到这个切面后,自动完成这个切面的所有功能。

AOP简介

 前置通知

 切入点表达式

//在applicationContext.xml文件中配置-----扫描带注解的包----表示使用动态代理

 编写一个切面类

 里面的注解@Before上的value值是切入点(哪个类下的哪个方法)

package com.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//定义了日志切面 
@Aspect//表示这个类是一个切面
@Component//把普通法的pojo实例化到Spring容器中,相当于配置文件中的<bean id="" class=""/>
public class LoggingAspect {
    
    //前置通知===参数:切入点表达式--指定类的所有方法--括号里面是参数
    //切入点为--该指定类且参数为Students的方法---也就是add方法
    @Before("execution(public * com.dao.impl.StudentsDAOImpl.* (com.entity.Students))")
    public void before(JoinPoint point){
        System.out.println("before:"+point.getSignature().getName()+"("+point.getArgs()+")");
    }
}

在applicationContext.xml配置文件中添加相关标签

    <!-- 表示使用注解 -->
    <context:annotation-config/>
    
    <!-- 表示使用动态代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    <!-- 扫描带注解的包 -->
    <context:component-scan base-package="com"/>

测试结果:----会在指定的dao层add方法之前切入这个方法执行

一辆汽车诞生啦...
一个学生创建啦...
执行了setName()方法
service层保存学生Students [sid=s0006, name=IU, gender=女, birthday=Wed Jul 15 00:00:00 GMT+08:00 1998, address=韩国首尔, car=Car [brand=BMW, color=黑色]]
before:add([Ljava.lang.Object;@11cbbeb1)
dao层保存学生Students [sid=s0006, name=IU, gender=女, birthday=Wed Jul 15 00:00:00 GMT+08:00 1998, address=韩国首尔, car=Car [brand=BMW, color=黑色]]

 后置通知

 

切点表达式解释

返回通知

异常通知

环绕通知

 AOP相关术语

使用日志log4j. properties

log4j.rootLogger=INFO,stdout,R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#Pattern to output the caller's file name and line number.
#log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
#Print the date in ISO 8601 format
log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=example.log
log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
# Print only messages of level WARN or above in the package com.foo.
# log4j.logger.com.foo=WARN

定义的日志切面(类)

package com.aspect;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//定义了日志切面 
@Aspect//表示这个类是一个切面
@Component//把普通法的pojo实例化到Spring容器中,相当于配置文件中的<bean id="" class=""/>
public class LoggingAspect {
    
    //创建一个日志对象
    private static Logger logger=LogManager.getLogger(LoggingAspect.class.getName());
    
    
    //前置通知===参数:切入点表达式--指定类的所有方法--括号里面是参数
    //切入点为--该指定类且参数为Students的方法---也就是add方法
    @Before("execution(public * com.dao.impl.StudentsDAOImpl.* (com.entity.Students))")
    public void before(JoinPoint point){
//        System.out.println("before:"+point.getSignature().getName()+"("+point.getArgs()+")");
        System.out.println("前置日志信息:"+point.getSignature().getName()+"");
        logger.info("前置日志信息:"+point.getSignature().getName()+"");
    }
    
    
    //后置通知
    @After("execution(public * com.dao.impl.StudentsDAOImpl.* (com.entity.Students))")
    public void after(JoinPoint point){
        System.out.println("后置日志信息:"+point.getSignature().getName()+"");
        logger.info("后置日志信息:"+point.getSignature().getName()+"");
    }
    
    
    //返回通知
    @AfterReturning(value="execution(public * com.dao.impl.StudentsDAOImpl.* (com.entity.Students))",returning="result")
    public void afterReturning(JoinPoint point,Object result){
        System.out.println("返回通知:"+point.getSignature().getName()+"("+point.getArgs()+")"+",result:"+result);
        logger.info("返回通知:"+point.getSignature().getName()+"("+point.getArgs()+")"+",result:"+result);
    }
    
    //异常通知
    @AfterThrowing(value="execution(public * com.dao.impl.StudentsDAOImpl.* (com.entity.Students))",throwing="ex")
    public void afterThrowing(JoinPoint point,Exception ex){
        System.out.println("异常通知:"+point.getSignature().getName()+"("+point.getArgs()+")"+",exception:"+ex);
        logger.info("异常通知:"+point.getSignature().getName()+"("+point.getArgs()+")"+",exception:"+ex);
    }
    
    //环绕通知
    @Around("execution(public * com.dao.impl.StudentsDAOImpl.* (com.entity.Students))")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        Object result=null;
        System.out.println("环绕通知之前要做的事情:"+point.getSignature().getName());
            //在这个地方是有throws Throwable,以便在异常通知时,获取异常信息
            result=point.proceed();
        
        System.out.println("环绕通知之后要做的事情:"+point.getSignature().getName());
        return result;
    }
    
    
}

applicationContext.xml文件:

    <!-- 表示使用注解 -->
    <context:annotation-config/>
    
    <!-- 表示使用动态代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    <!-- 扫描带注解的包 -->
    <context:component-scan base-package="com"/>

测试然后会在控制台打印出日志,以及生成日志文件example.log文件。

原文地址:https://www.cnblogs.com/xjs1874704478/p/11214299.html