农村建设设计网站首页,做网站的具体内容,做外贸网站要什么条件,黄浦网站设计面向注解编程—Spring注解大全#xff08;AOP篇#xff09;
AOP英文全称#xff1a;Aspect Oriented Programming#xff08;面向切面编程、面向方面编程#xff09;#xff0c;其实说白 了#xff0c;面向切面编程就是面向特定方法编程。
AOP的作用#xff1a;在程序…面向注解编程—Spring注解大全AOP篇
AOP英文全称Aspect Oriented Programming面向切面编程、面向方面编程其实说白 了面向切面编程就是面向特定方法编程。
AOP的作用在程序运行期间在不修改源代码的基础上对已有方法进行增强无侵入性: 解耦
AOP的常见的应用场景 如下
记录系统的操作日志权限控制事务管理我们前面所讲解的Spring事务管理底层其实也是通过AOP来实现的只要添加 Transactional注解之后AOP程序自动会在原始方法运行前先来开启事务在原始方法运行完 毕之后提交或回滚事务 AOP快速入门
Aspect
Component
Aspect //当前类为切面类
Slf4j
public class TimeAspect {Around(execution(* com.itheima.service.*.*(..)))public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {//记录方法执行开始时间long begin System.currentTimeMillis();//执行原始方法Object result pjp.proceed();//记录方法执行结束时间long end System.currentTimeMillis();//计算方法执行耗时log.info(pjp.getSignature()执行耗时: {}毫秒,end-begin);return result;}
}该类实现了统计各个业务层方法执行耗时
AOP核心概念
连接点JoinPoint
连接点指的是可以被aop控制的方法。例如入门程序当中所有的业务方法都是可以被aop控制的方法。 通知Advice
指哪些重复的逻辑也就是共性功能最终体现为一个方法 切入点PointCut
匹配连接点的条件通知仅会在切入点方法执行时被应用 切面Aspect
描述通知与切入点的对应关系通知切入点 切面所在的类我们一般称为切面类被Aspect注解标识的类
通知类型
Around环绕通知此注解标注的通知方法在目标方法前、后都被执行Before前置通知此注解标注的通知方法在目标方法前被执行After 后置通知此注解标注的通知方法在目标方法后被执行无论是否有异常都会执行AfterReturning 返回后通知此注解标注的通知方法在目标方法后被执行有异常不会执 行AfterThrowing 异常后通知此注解标注的通知方法发生异常后执行
在入门程序当中已经展示了一种功能最为强大的通知类型Around环绕通知
//前置通知
Before(execution(* com.itheima.service.*.*(..)))//环绕通知
Around(execution(* com.itheima.service.*.*(..)))//后置通知
After(execution(* com.itheima.service.*.*(..)))//返回后通知程序在正常执行的情况下会执行的后置通知
AfterReturning(execution(* com.itheima.service.*.*(..)))//异常通知程序在出现异常的情况下执行的后置通知
AfterThrowing(execution(* com.itheima.service.*.*(..)))
PointCut解决这个切入点表达式重复的问题
Slf4j
Component
Aspect
public class MyAspect1 {//切入点方法公共的切入点表达式Pointcut(execution(* com.itheima.service.*.*(..)))private void pt(){}//前置通知引用切入点Before(pt())public void before(JoinPoint joinPoint){log.info(before ...);}//环绕通知Around(pt())public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {log.info(around before ...);//调用目标对象的原始方法执行Object result proceedingJoinPoint.proceed();//原始方法在执行时发生异常//后续代码不在执行log.info(around after ...);return result;}//后置通知After(pt())public void after(JoinPoint joinPoint){log.info(after ...);}//返回后通知程序在正常执行的情况下会执行的后置通知AfterReturning(pt())public void afterReturning(JoinPoint joinPoint){log.info(afterReturning ...);}//异常通知程序在出现异常的情况下执行的后置通知AfterThrowing(pt())public void afterThrowing(JoinPoint joinPoint){log.info(afterThrowing ...);}
}
Order()使用Order注解控制通知的执行顺序
Slf4j
Component
Aspect
Order(2) //切面类的执行顺序前置通知数字越小先执行; 后置通知数字越小
越后执行
public class MyAspect2 {//前置通知Before(execution(* com.itheima.service.*.*(..)))public void before(){log.info(MyAspect2 - before ...);}//后置通知After(execution(* com.itheima.service.*.*(..)))public void after(){log.info(MyAspect2 - after ...);}
}Slf4j
Component
Aspect
Order(3) //切面类的执行顺序前置通知数字越小先执行; 后置通知数字越小越后执行
public class MyAspect3 {//前置通知Before(execution(* com.itheima.service.*.*(..)))public void before(){log.info(MyAspect3 - before ...);}//后置通知After(execution(* com.itheima.service.*.*(..)))public void after(){log.info(MyAspect3 - after ...);}
}
切入点表达式
execution
格式 execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
Before(execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer)))*****单个独立的任意符号可以通配任意返回值、包名、类名、方法名、任意类型的一个参数 也可以通配包、类、方法名的一部分… 多个连续的任意符号可以通配任意层级的包或任意类型、任意个数的参数
annotation
自定义注解MyLog
Target(ElementType.METHOD)
Retention(RetentionPolicy.RUNTIME)
public interface MyLog {}业务类DeptServiceImpl
Slf4j
Service
public class DeptServiceImpl implements DeptService {Autowiredprivate DeptMapper deptMapper;OverrideMyLog //自定义注解表示当前方法属于目标方法public ListDept list() {ListDept deptList deptMapper.list();//模拟异常//int num 10/0;return deptList;}OverrideMyLog //自定义注解表示当前方法属于目标方法public void delete(Integer id) {//1. 删除部门deptMapper.delete(id);}Overridepublic void save(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.save(dept);}Overridepublic Dept getById(Integer id) {return deptMapper.getById(id);}Overridepublic void update(Dept dept) {dept.setUpdateTime(LocalDateTime.now());deptMapper.update(dept);}
}切面类
Slf4j
Component
Aspect
public class MyAspect6 {//针对list方法、delete方法进行前置通知和后置通知//前置通知Before(annotation(com.itheima.anno.MyLog))public void before(){log.info(MyAspect6 - before ...);}//后置通知After(annotation(com.itheima.anno.MyLog))public void after(){log.info(MyAspect6 - after ...);}
}execution切入点表达式 根据我们所指定的方法的描述信息来匹配切入点方法这种方式也是最为常用的一种方式 如果我们要匹配的切入点方法的方法名不规则或者有一些比较特殊的需求通过 execution切入点表达式描述比较繁琐annotation 切入点表达式 基于注解的方式来匹配切入点方法。 这种方式虽然多一步操作我们需要自定义一个注解但是相对来比较灵活。我们需要匹配哪个方法就在方法上加上对应的注解就可以了
连接点
在Spring中用JoinPoint抽象了连接点用它可以获得方法执行时的相关信息如目标类名、方法 名、方法参数等。
对于Around通知获取连接点信息只能使用ProceedingJoinPoint类型对于其他四种通知获取连接点信息只能使用JoinPoint它是ProceedingJoinPoint的父类型
示例代码
Slf4j
Component
Aspect
public class MyAspect7 {Pointcut(annotation(com.itheima.anno.MyLog))private void pt(){}//前置通知Before(pt())public void before(JoinPoint joinPoint){log.info(joinPoint.getSignature().getName() MyAspect7 -before ...);}//后置通知Before(pt())public void after(JoinPoint joinPoint){log.info(joinPoint.getSignature().getName() MyAspect7 - after ...);}//环绕通知Around(pt())public Object around(ProceedingJoinPoint pjp) throws Throwable {//获取目标类名String name pjp.getTarget().getClass().getName();log.info(目标类名{},name);//目标方法名String methodName pjp.getSignature().getName();log.info(目标方法名{},methodName);//获取方法执行时需要的参数Object[] args pjp.getArgs();log.info(目标方法参数{}, Arrays.toString(args));//执行原始方法Object returnValue pjp.proceed();return returnValue;}
}//目标方法名String methodName pjp.getSignature().getName();log.info(目标方法名{},methodName);//获取方法执行时需要的参数Object[] args pjp.getArgs();log.info(目标方法参数{}, Arrays.toString(args));//执行原始方法Object returnValue pjp.proceed();return returnValue;}
}