📫作者简介:zhz小白
公众号:小白的Java进阶之路
专业技能:
1、Java基础,并精通多线程的开发,熟悉JVM原理
2、熟悉Java基础,并精通多线程的开发,熟悉JVM原理,具备⼀定的线上调优经验
3、熟悉MySQL数据库调优,索引原理等,⽇志原理等,并且有出过⼀篇专栏
4、了解计算机⽹络,对TCP协议,滑动窗⼝原理等有⼀定了解
5、熟悉Spring,Spring MVC,Mybatis,阅读过部分Spring源码
6、熟悉SpringCloud Alibaba体系,阅读过Nacos,Sentinel,Seata,Dubbo,Feign,Gateway核⼼源码与设计,⼆次开发能⼒
7、熟悉消息队列(Kafka,RocketMQ)的原理与设计
8、熟悉分库分表ShardingSphere,具有真实⽣产的数据迁移经验
9、熟悉分布式缓存中间件Redis,对其的核⼼数据结构,部署架构,⾼并发问题解决⽅案有⼀定的积累
10、熟悉常⽤设计模式,并运⽤于实践⼯作中
11、了解ElasticSearch,对其核⼼的原理有⼀定的了解
12、了解K8s,Jekins,GitLab
13、了解VUE,GO
14、⽬前有正在利⽤闲暇时间做互游游戏,开发、运维、运营、推销等
本人著作git项目:https://gitee.com/zhouzhz/star-jersey-platform,有兴趣的可以私聊博主一起编写,或者给颗star
领域:对支付(FMS,FUND,PAY),订单(OMS),出行行业等有相关的开发领域
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
文章目录
- 1、AOP简介
- 2、作用
- 3、实现原理
- 4、优势
- 5、应用场景
- 6、AOP相关术语
- 7、AOP入门实战
- 7.1、实现AOP打印每个方法结束后打印日志
- 7.1.1、aop切面类
- 7.1.2、要被aop的类
- 7.1.3、MainConfig配置类
- 7.1.4、测试类
- 7.1.5、运行结果
- 8、AOP通知类型
- 9、AOP切点表达式
1、AOP简介
- AOP的全称是Aspect Oriented Programming,即面向切面编程。是实现功能统一维护的一种技术,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。
2、作用
- 在不修改源码的基础上,对已有方法进行增强。
3、实现原理
- 动态代理技术。
4、优势
- 减少重复代码、提高开发效率、维护方便
5、应用场景
- 事务处理
- 日志管理
- 权限控制
- 异常处理等方面。
6、AOP相关术语
名称 | 说明 |
---|---|
Joinpoint(连接点) | 指能被拦截到的点,在Spring中只有方法能被拦截。 |
Pointcut(切点) | 指要对哪些连接点进行拦截,即被增强的方法。 |
Advice(通知) | 指拦截后要做的事情,即切点被拦截后执行的方法。 |
Aspect(切面) | 切点+通知称为切面 |
Target(目标) | 被代理的对象 |
Proxy(代理) | 代理对象 |
Weaving(织入) | 生成代理对象的过程 |
7、AOP入门实战
- AspectJ是一个基于Java语言的AOP框架,在Spring框架中建议使用AspectJ实现AOP。
7.1、实现AOP打印每个方法结束后打印日志
7.1.1、aop切面类
package com.zhz.aspect;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import java.util.Date;
/**
* @author zhouhengzhe
* @date 2022/11/19
*/
@Slf4j
@Aspect
public class AopAspect {
/**
* 指定切面的切入点
*/
@Pointcut("execution(* com.zhz.dao.BookDao.*(..))")
public void pointCut() {
}
/**
* 前置通知:执行目标方法前 触发
*/
@Before("pointCut()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",前置通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs()));
}
/**
* 后置通知:执行目标方法后触发
*/
@After(value = "pointCut()")
public void logAfter(JoinPoint joinPoint) {
System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",后置通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs()));
}
/**
* 返回通知:目标方法执行完并返回参数后触发。
*/
@AfterReturning(value = "pointCut()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",返回通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs())+"返回结果:"+ JSON.toJSONString(result));
}
/**
* 异常通知:目标方法抛出异常后触发
*/
@AfterThrowing(value = "pointCut()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",异常通知——方法名:"+joinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(joinPoint.getArgs())+",异常信息:" + ex.getMessage());
}
/**
* 环绕通知,围绕着方法执行
* 环绕通知需要携带ProceedingJoinPoint类型的参数
* 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
* 而且环绕通知必须有返回值,返回值即为目标方法的返回值
*/
@Around(value = "pointCut()")
public Object logAround(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("当前时间为:"+(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"))+",环绕通知前——方法名:"+proceedingJoinPoint.getSignature().getName()+",参数:"+JSON.toJSONString(proceedingJoinPoint.getArgs()));
Object result = null;
//执行目标方法
try {
result = proceedingJoinPoint.proceed();
System.out.println("环绕后");
} catch (Throwable e) {
System.out.println("环绕异常后");
throw new RuntimeException(e);
}
return result;
}
}
7.1.2、要被aop的类
package com.zhz.dao;
import org.springframework.stereotype.Repository;
/**
* @author zhouhengzhe
* @description: todo
* @date 2022/11/4 10:56
* @since v1
*/
@Repository
public class BookDao {
public void add(){
System.out.println("新增图书");
}
public void delete(){
System.out.println("删除图书");
}
public void update(){
System.out.println("更新图书");
}
}
7.1.3、MainConfig配置类
package com.zhz.config;
import com.zhz.aspect.AopAspect;
import com.zhz.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @author zhouhengzhe
* @description: todo
* @date 2022/11/4 10:27
* @since v1
*/
@EnableAspectJAutoProxy
@Configuration
public class MainConfig {
@Bean
public BookDao bookDao(){
return new BookDao();
}
// 将切面类加入到容器中
@Bean
public AopAspect aopAspect() {
return new AopAspect();
}
}
7.1.4、测试类
@Test
public void test4(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
BookDao bean = applicationContext.getBean(BookDao.class);
bean.add();
applicationContext.close();
}
7.1.5、运行结果
8、AOP通知类型
通知类型 | 描述 |
---|---|
前置通知 | 在方法执行前添加功能 |
后置通知 | 在方法正常执行后添加功能 |
异常通知 | 在方法抛出异常后添加功能 |
最终通知 | 无论方法是否抛出异常,都会执行该通知 |
环绕通知 | 在方法执行前后添加功能 |
9、AOP切点表达式
使用AspectJ需要使用切点表达式配置切点位置,写法如下:
- 标准写法:访问修饰符 返回值 包名.类名.方法名(参数列表)
- 访问修饰符可以省略。
- 返回值使用 * 代表任意类型。
- 包名使用 * 表示任意包,多级包结构要写多个 * ,使用 *… 表示任意包结构
- 类名和方法名都可以用 * 实现通配
- 参数列表
- 基本数据类型直接写类型
- 引用类型写 包名.类名
- ***** 表示匹配一个任意类型参数
- … 表示匹配任意类型任意个数的参数
- 全通配: *** ….*(…)**