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文件。