先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注go)
正文
ok,接下来我们分别具体来看这两大核心 @Pointcut 和 Advice .
一、@Pointcut
@Pointcut切点表达式非常丰富,可以将 方法(method)、类(class)、接口(interface)、包(package) 等作为切入点,非常灵活,常用的有@annotation、@within、execution等方式,由于篇幅原因,本文先只介绍@annotation
方式。
@annotation
@annotation方式是指:切入点 是指定作用于方法上的注解
,即被Spring扫描到方法上带有该注解 就会执行切面通知。
@Pointcut(value = “@annotation(com.tiangang.aop.MethodLog)”)
public void pointCut() {
}
案例给出的@Pointcut说明:
语法:@Pointcut(value = "@annotation(注解类名
)")
注:只有注解类名是动态的,其它是固定写法.
二、五种通知Advice
通过@Pointcut定义的切点,共有五种通知Advice方式:
注解 | 说明 |
---|---|
@Before | 前置通知,在被切的方法执行前执行 |
@After | 后置通知,在被切的方法执行后执行,比return更后 |
@AfterRunning | 返回通知,在被切的方法return后执行 |
@AfterThrowing | 异常通知,在被切的方法抛异常时执行 |
@Around | 环绕通知,这是功能最强大的Advice,可以自定义执行顺序 |
执行顺序如下:
我这里在Service里定义了一个除法方法divide(),在这个方法也打上@MethodLog注解
,让它可以被切面横切。
@Service
public class DemoService {
@MethodLog
public Integer divide(Integer a, Integer b) {
System.out.printf(“方法内打印: a=%d b=%d %n”, a, b);
return a / b;
}
}
用于测试的controller代码,都很简单:
@RestController
@RequestMapping(“/demo”)
public class DemoController {
@Autowired
private DemoService demoService;
@GetMapping(“/divide”)
public Integer divide(Integer a, Integer b) {
return demoService.divide(a, b);
}
}
1. @Before前置通知
前置通知在被切的方法执行之前执行!
@Before(“pointCut()”)
public void before(JoinPoint joinPoint) throws NoSuchMethodException {
printMethod(joinPoint, “[前置通知before]”);
}
注解语法:@Before("切点方法名
()")
注:只有《切点方法名》是动态的,其它是固定写法.
方法语法:public void 方法名(JoinPoint joinPoint)
这里有个非常重要参数JoinPoint:连接点 。因为Spring只支持方法
类型的连接点,所以在Spring中连接点指的就是被拦截到的方法
. 里面有三个常用的方法:
getSignature()
获取签名:
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
通过signature可以获取名称 getName() 和 参数类型 getParameterTypes()
getTarget()
获取目标类:
Class<?> clazz = joinPoint.getTarget().getClass();
如果被切的类 是 被别的切面切过的类,可以使用AopUtils.getTargetClass
获取一个数组,再从数组中找你期望的类。
import org.springframework.aop.support.AopUtils;
Class<?>[] targets = AopUtils.getTargetClass(joinPoint.getTarget()).getInterfaces();
getArgs()
获取入参值
Object[] args = joinPoint.getArgs()
基于这3个方法,可以轻松打印:被切的类名、方法名、方法参数值、方法参数类型等,printMethod方法如下:
private void printMethod(JoinPoint joinPoint, String name) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Class<?> clazz = joinPoint.getTarget().getClass();
Method method = clazz.getMethod(signature.getName(), signature.getParameterTypes());
System.out.printf(“[MethodLogAspect]切面 %s 打印 -> [className]:%s -> [methodName]:%s -> [methodArgs]:%s%n”, name, clazz.getName(), method.getName(), Arrays.toString(joinPoint.getArgs()));
}
调用测试类,输出结果如下:
[MethodLogAspect]切面 [前置通知before] 打印 -> [className]:com.tiangang.service.DemoService -> [methodName]:divide -> [methodArgs]:[10, 2]
方法内打印: a=10 b=2
2. @After后置通知
后置通知在被切的方法执行之后执行,无论被切方法是否异常都会执行!
@After(“pointCut()”)
public void after(JoinPoint joinPoint) throws NoSuchMethodException {
printMethod(joinPoint, “[后置通知after]”);
}
注解语法:@After("切点方法名
()")
注:只有《切点方法名》是动态的,其它是固定写法.
方法语法:public void 方法名(JoinPoint joinPoint)
调用测试类,输出结果如下:
[MethodLogAspect]切面 [前置通知after] 打印 -> [className]:com.tiangang.service.DemoService -> [methodName]:divide -> [methodArgs]:[10, 2]
方法内打印: a=10 b=2
[MethodLogAspect]切面 [后置通知after] 打印 -> [className]:com.tiangang.service.DemoService -> [methodName]:divide -> [methodArgs]:[10, 2]
3. @AfterRunning返回通知
返回通知在被切的方法return后执行,带有返回值,如果被切方法异常则不会执行!
这里多了一个参数Object result
,注解上也多了一个参数:returning
@AfterReturning(value = “pointCut()”, returning = “result”)
public void afterReturning(JoinPoint joinPoint, Object result) throws NoSuchMethodException {
printMethod(joinPoint, “[返回通知afterReturning]”);
System.out.printf(“[MethodLogAspect]切面 [返回通知afterReturning] 打印结果 -> result:%s%n”, result);
}
注解语法:@AfterReturning(value = "切点方法名
(), returning = "返回值参数名
")
注:只有《切点方法名》和 《返回值参数名》是动态的,其它是固定写法.
方法语法:public void 方法名(JoinPoint joinPoint, Object result)
调用测试类,输出结果如下:
[MethodLogAspect]切面 [前置通知before] 打印 -> [className]:com.tiangang.service.DemoService -> [methodName]:divide -> [methodArgs]:[10, 2]
方法内打印: a=10 b=2
[MethodLogAspect]切面 [返回通知afterReturning] 打印 -> [className]:com.tiangang.service.DemoService -> [methodName]:divide -> [methodArgs]:[10, 2]
[MethodLogAspect]切面 [返回通知afterReturning] 打印结果 -> result:5
[MethodLogAspect]切面 [后置通知after] 打印 -> [className]:com.tiangang.service.DemoService -> [methodName]:divide -> [methodArgs]:[10, 2]
4. @AfterThrowing异常通知
异常通知只在被切方法异常时执行,否则不执行。
这里多了一个参数Exception e
,表示捕获所有异常,也可以设置为具体某一个异常,例如NullPointerException、RpcException等等。注解上也多了一个参数:throwing
@AfterThrowing(value = “pointCut()”, throwing = “e”)
public void afterThrowing(JoinPoint joinPoint, Exception e) throws NoSuchMethodException {
printMethod(joinPoint, “[异常通知afterThrowing]”);
System.out.printf(“[MethodLogAspect]切面 [异常通知afterThrowing] 打印异常 -> Exception:%s%n”, e);
}
注解语法:@AfterThrowing(value = "切点方法名
(), throwing = "异常参数名
")
注:只有《切点方法名》和 《异常参数名》是动态的,其它是固定写法.
方法语法:public void 方法名(JoinPoint joinPoint, Exception e)
调用测试类,输出结果如下:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
语法:**public void 方法名(JoinPoint joinPoint, Exception e)
调用测试类,输出结果如下:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-vmOQXPhM-1713177425226)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!