当前位置: 首页 > news >正文

AOP复习

AOP

  • AOP
    • 静态代理
    • 动态代理
      • Proxy
      • CGLIB

AOP

面向切面编程
优点:

  • 提高代码的可重用性
  • 业务代码编码更简洁
  • 业务代码维护更高效
  • 业务功能扩展更便捷
Joinpoint(连接点)就是方法
Pointcut(切入点)就是挖掉共性功能的方法
Advice(通知)就是共性功能,最终以一个方法的形式呈现
Aspect(切面)是共性功能与挖的位置的对应关系
Target(目标对象)就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接完成最终工作的
Weaving(织入)就是将挖掉的功能回填的动态过程
Proxy(代理)目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现
Introduction(引入/引介)是对原始对象无中生有的添加成员变量或成员方法

使用到的注解

定义切面
@Aspect
定义再类的上方,设置当前类为切面类

@Aspect
public class AopAdvice {
}

切入点引用
@Pointcut
作用在方法上使用当前的方法名称作为切入点引用名称
举例:

@Pointcut("execution(* *(..))")
public void pt() {
}

五种通知

注解名称解释说明
@Before前置通知原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行
@After后置通知原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知
@AfterReturning当前方法作为返回后通知原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行
@AfterThrowing异常后通知原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行
@Around当前方法作为环绕通知在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行

举例:

@Pointcut("execution(* *(..))")
public void pt() {
}
@Before("pt()")
public void before(){
}
@After("pt()")
public void after(){
}
@AfterReturning(value="pt()",returning = "ret")
public void afterReturning(Object ret) {
}
@AfterThrowing(value="pt()",throwing = "t")
public void afterThrowing(Throwable t){
}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {Object ret = pjp.proceed();return ret;
}

完整的举例:

Component
@Aspect//设置切面
public class AnnotationAop {//设置切入点为有有注解LogAnnotation的方法@Pointcut("@annotation(com.springAop.annotation.LogAnnotation)")public void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("环绕前增强1");//获取方法签名MethodSignature signature = (MethodSignature) pjp.getSignature();Method method1 = signature.getMethod();//获取接口的方法Method method = pjp.getTarget().getClass().getMethod(method1.getName(), method1.getParameterTypes());//获取实现类的方法System.out.println("实现类 = " + method1);String name = method.getName();//获取方法名System.out.println("获取方法名 = " + name);Class<?> returnType = method.getReturnType();//获取返回值类型String name1 = returnType.getName();System.out.println("返回值类型 = " + name1);Class<?>[] parameterTypes = method.getParameterTypes();//获取参数类型for (int i = 0; i < parameterTypes.length; i++) {String name2 = parameterTypes[i].getName();//获取参数类型System.out.println("parameterTypes = " + name2);}//获取参数的值Object[] args = pjp.getArgs();for (int i = 0; i < args.length; i++) {System.out.println("i = " + args[i]);}Object proceed = pjp.proceed();LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);//获取方法上的注解Annotation[] annotations = method.getDeclaredAnnotations();//获取方法上的注解for (Annotation a : annotations) {String annotationName = a.annotationType().getName();//获取注解名Class<? extends Annotation> aClass = a.annotationType();if (a instanceof LogAnnotation) {System.out.println("我是注解LogAnnotation已经执行了 ");}System.out.println("annotationName = " + annotationName);// 在这里可以使用获取到的 annotationName 进行逻辑处理}System.out.println("环绕后增强1");return proceed;}//前置增强@Before("pointCut()")public void before() {System.out.println("前置增强1");}@After("pointCut()")public void after() {System.out.println("后置增强1");}@AfterThrowing("pointCut()")public void afterThrowing() {System.out.println("异常增强1");}@AfterReturning("pointCut()")public void afterReturning() {System.out.println("返回后通知1");}
}/*** 自定义日志注解*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface LogAnnotation {String value() default "";String name() default "";String type() default "";
}@Service("bookService")
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;@Overridepublic void save(Book book) {bookDao.save(book);}@Overridepublic void update(Book book) {bookDao.update(book);}@Overridepublic void delete(Integer id) {bookDao.delete(id);}@Override@LogAnnotation1231(value = "查询value1231",type = "查询type1231",name= "查询name1231")@LogAnnotation(value = "查询value",type = "查询type",name= "查询name")public Book findById(Integer id) {System.out.println("id ====================== " + id);return bookDao.findById(id);}@Overridepublic List<Book> findAll() {System.out.println("===================================== ");return bookDao.findAll();}
}

静态代理

装饰者模式(Decorator Pattern):在不惊动原始设计的基础上,为其添加功能
举例:

public class UserServiceDecorator implements UserService{private UserService userService;public UserServiceDecorator(UserService userService) {this.userService = userService;}public void save() {//原始调用userService.save();//增强功能(后置)System.out.println("刮大白");}
}

动态代理

Proxy

JDKProxy动态代理是针对对象做代理,要求原始对象具有接口实现,并对接口方法进行增强
举例:

public class UserServiceJDKProxy {public UserService createUserServiceJDKProxy(final UserService userService){//获取被代理对象的类加载器ClassLoader classLoader = userService.getClass().getClassLoader();//获取被代理对象实现的接口Class[] classes = userService.getClass().getInterfaces();//对原始方法执行进行拦截并增强InvocationHandler ih = new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//前置增强内容Object ret = method.invoke(userService, args);//后置增强内容System.out.println("刮大白2");return ret;}};//使用原始被代理对象创建新的代理对象UserService proxy = (UserService) Proxy.newProxyInstance(classLoader,classes,ih);return proxy;}
}

CGLIB

  • CGLIB(Code Generation Library),Code生成类库
  • CGLIB动态代理不限定是否具有接口,可以对任意操作进行增强
  • CGLIB动态代理无需要原始被代理对象,动态创建出新的代理对象

举例

public class UserServiceImplCglibProxy {public static UserServiceImpl createUserServiceCglibProxy(Class clazz){//创建Enhancer对象(可以理解为内存中动态创建了一个类的字节码)Enhancer enhancer = new Enhancer();//设置Enhancer对象的父类是指定类型UserServerImplenhancer.setSuperclass(clazz);Callback cb = new MethodInterceptor() {public Object intercept(Object o, Method m, Object[] a, MethodProxy mp) throws Throwable {Object ret = mp.invokeSuper(o, a);if(m.getName().equals("save")) {System.out.println("刮大白");}return ret;}};//设置回调方法enhancer.setCallback(cb);//使用Enhancer对象创建对应的对象return (UserServiceImpl)enhancer.create();}
}

总结
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
动态代理是实现 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过 Proxy 里的 newProxyInstance 得到代理对象
还有一种动态代理 CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的


在面向对象编程(oop)思想中,我们将事物纵向抽成一个个的对象。而在面向切面编程
中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事物>管理,记录日志等
公用操作处理的过程就是面向切面编程的思想。AOP 底层是动态代理,如果是接口采用 JDK 动态代理,如果是类采用
CGLIB 方式实现动态代理。


Java 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler 来处理。
而 cglib 动态代理是利用 asm 开源包,对代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP
2、如果目标对象实现了接口,可以强制使用 CGLIB 实现 AOP
3、如果目标对象没有实现了接口,必须采用 CGLIB 库,spring 会自动在 JDK 动态代理和 CGLIB 之间转换

http://www.lryc.cn/news/289519.html

相关文章:

  • 解决 Required Integer parameter ‘uid‘ is not present
  • Qt/QML编程之路:ListView实现横排图片列表的示例(40)
  • 数据分析-Pandas如何用图把数据展示出来
  • Logistics 逻辑回归概念
  • Elasticsearch安装Head图形插件
  • 【C++】——类和对象(中)
  • uniapp组件库Card 卡片 的使用方法
  • 一款强大的矢量图形设计软件:Adobe Illustrator 2023 (AI2023)软件介绍
  • 对于循环的一次探索
  • 设计模式:简介及基本原则
  • 营销领域有哪些著名的模型?如销售漏斗等
  • JavaScript学习-let、var、const的使用
  • 【Java】SpringMVC参数接收(一)
  • File类知识点回顾
  • 2024新版68套Axure RP大数据可视化大屏模板及通用组件+PSD源文件
  • Optional lab: Linear Regression using Scikit-LearnⅠ
  • CentOS使用
  • [SWPUCTF 2018]SimplePHP1
  • api管理工具的新发现
  • 2024 年 eBPF 和网络趋势预测
  • 2024.1.27 GNSS 学习笔记
  • Unity - 将项目转为HDRP
  • ETCD高可用架构涉及常用功能整理
  • 深度学习中RGB影像图的直方图均衡化python代码and对图片中指定部分做基于掩模的特定区域直方图均衡化
  • PyTorch深度学习实战(33)——条件生成对抗网络(Conditional Generative Adversarial Network, CGAN)
  • 编写Bash脚本程序从记录文件中提取history命令的优化,再介绍linux bash语法和结构
  • Python中Numba库装饰器
  • Spring Boot Aop 执行顺序
  • 100天精通鸿蒙从入门到跳槽——第16天:ArkTS条件渲染使用教程
  • 【Linux C | 进程】Linux 进程间通信的10种方式(1)