深入AOP原理与应用

简介: AOP(Aspect Oriented Programming)就是面向切面编程,也是一种编程思想,接触了JAVA是Spring框架后我才了解AOP,在我的工作中会经常用到,举个存储分层的例...

AOP(Aspect Oriented Programming)就是面向切面编程,也是一种编程思想,接触了JAVA是Spring框架后我才了解AOP,在我的工作中会经常用到,举个存储分层的例子,就像硬盘、内存和CPU中的寄存器,对应的高性能应用系统会有普通数据库、Redis和本地内存:

那么这里的缓存操作我们可以抽出来统一做,这里我们就用到了AOP,切点就是对数据的存取方法,还有就是调用外部系统的接口获取数据时,我们也可以用AOP来实现统一的缓存操作,我们通常用的AOP的框架是aspectj,实现的原理是动态代理,动态代理的方案有JDK Proxy、cglib等,cglib是代码的动态生成技术,用asm提供的动态生成JAVA字节码的技术,而JDK的动态代理是一种设计模式,依懒接口的实现。写一个AOP简单如下

@Aspect
@Component
public class CacheUpdateProcessor {

    @Around("@annotation(com.xxx.xxx.cache.CacheUpdate)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        Object result = joinPoint.proceed();
        
        try {
            // 获取被切方法的所有入参
            Object[] methodArgs = joinPoint.getArgs();
            Signature signature = joinPoint.getSignature();
            if (signature instanceof MethodSignature) {

            }
        } catch (Exception e) {
            
        }
        return result;
    }

}
我们还在spring的XML配置文件中加上

<aop:aspectj-autoproxy proxy-target-class="true" />
表示使用cglib动态代理技术织入增强,利用cglib的好处是提高了系统的性能,利用注解让spring帮我们完成了自动代码织入,注解@Around中的参数就是织入的切点,around表示包围了整个方法,被切的代码的执行可以通过joinPoint(连接点)来调用,当然除了around的还有其他的织入方式,例如before和after,表示在被切方法前执行和被切方法后执行。

我们可以在around、before或after的方法里进行统一的缓存处理,而在需要进行此类操作的地方只需要加个被设置为切点的注解即可,如果还需要传方法参数以外的数据,可以对自定义的注解进行优化,例如我自定义的的作为切点的注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface CacheUpdate {
    
    CacheKeys key();
    
    Class<?> type();
    
}
获取注解中的参数方法如下:


                Method aopMethod = methodSignature.getMethod();
                CacheUpdate param = aopMethod.getAnnotation(CacheUpdate.class);
                // 获取参数的类
                Class clazz = param.type();
                CacheKeys keys = param.key();
对于@around、@before和@after中value的值有个专业的名词:pointcut expression(切点表达式)

Aspectj的源码中是这样说明的:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Around {

    /**
     * The pointcut expression where to bind the advice
     */
    String value();
    
    /**
     * When compiling without debug info, or when interpreting pointcuts at runtime,
     * the names of any arguments used in the advice declaration are not available.
     * Under these circumstances only, it is necessary to provide the arg names in 
     * the annotation - these MUST duplicate the names used in the annotated method.
     * Format is a simple comma-separated list.
     */
    String argNames() default "";

}
pointcut expression的作用就是为了说明切点是什么,在哪,比如是某个注解、是某个方法或某个类中的所有方法等等。

接下来说明AOP是如何实现代码织入的,织入是在类加载前的环节,当某个类被加载时,如果发现有切面,这时会生成一个新的类,这个新的类会被动态地址增加一些JAVA的指令操作,然后加载这个新的类。这个织入的操作其实就像人为的修改class文件一样,如果对java虚拟机的汇编指令熟悉,完全可以手动修改,然而现在只是有专门的程序帮我们完成的这个操作而矣,这个专门的程序熟悉JAVA的指令集,它就是asm,而具体的要把代码加在什么位置,怎么加,则是由具体的上层代码指定,像@around、@before和@after。

ASM中有一个ClassReader和一个ClassWriter,见名就知其义了,前者是用来解析class文件的,而后者是用来写入class文件的,ASM主要的设计思想是Visitor访问者模式,与迭代器模式不同的是访问者模式的访问逻辑是由实现类来决定的,ASM的上层是ClassVisitor,而ClassWriter就是其的一个实现,还有其它的一些实现:

下面是我用ASM写的简单的代码动态生成的例子:

测试类,只有一个名为out的方法

public class Test {

    public void out(String data){
        
        System.out.println("method out : " + data);
        
    }

}
动态生成代码,先输出原字节码,分隔符下是新生成的代码

public class AsmTest {

    public static void main(String[] args) throws Exception {
        
        ClassReader cr = new ClassReader(Test.class.getName());
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
        
        System.out.println(new String(cw.toByteArray(),"utf-8"));
        
        cr.accept(new ClassAdapter(cw){
            
            @Override
            public MethodVisitor visitMethod(int access, String name, String desc,
                    String signature, String[] exceptions) {
                
                if("out".equals(name)){
                    
                    MethodVisitor visitor = cv.visitMethod(Opcodes.ACC_PUBLIC, "out", "(Ljava/lang/String;)V", null, null);
                    visitor.visitLdcInsn("Before execute");
                    visitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
                    visitor.visitEnd();
                    return visitor;
                }
                
                return cv.visitMethod(access, name, desc, signature, exceptions);
            }
            
        }, 0);
        System.out.println("---------分隔符---------");
        System.out.println(new String(cw.toByteArray(),"utf-8"));
    }
}
测试的结果如下:


如果想要了解ASM的,可以要多看看JVM和其指令集了,也就是JAVA的汇编

最后总结一下,其实AOP重要的是思想,至于如何实现AOP,可以有很多种方式,只是在众多方式中,利用ASM的JAVA字节码动态自动生成的方式可能性能是最好的。

目录
相关文章
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
64 1
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
22天前
|
XML Java 开发者
论面向方面的编程技术及其应用(AOP)
【11月更文挑战第2天】随着软件系统的规模和复杂度不断增加,传统的面向过程编程和面向对象编程(OOP)在应对横切关注点(如日志记录、事务管理、安全性检查等)时显得力不从心。面向方面的编程(Aspect-Oriented Programming,简称AOP)作为一种新的编程范式,通过将横切关注点与业务逻辑分离,提高了代码的可维护性、可重用性和可读性。本文首先概述了AOP的基本概念和技术原理,然后结合一个实际项目,详细阐述了在项目实践中使用AOP技术开发的具体步骤,最后分析了使用AOP的原因、开发过程中存在的问题及所使用的技术带来的实际应用效果。
49 5
|
2月前
|
Java
Java的aop是如何实现的?原理是什么?
Java的aop是如何实现的?原理是什么?
25 4
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
【9月更文挑战第9天】AOP(面向切面编程)通过分离横切关注点提高模块化程度,如日志记录、事务管理等。Micronaut AOP基于动态代理机制,在应用启动时为带有特定注解的类生成代理对象,实现在运行时拦截方法调用并执行额外逻辑。通过简单示例展示了如何在不修改 `CalculatorService` 类的情况下记录 `add` 方法的参数和结果,仅需添加 `@Loggable` 注解即可。这不仅提高了代码的可维护性和可扩展性,还降低了引入新错误的风险。
47 13
|
3月前
|
监控 安全 Java
|
3月前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。
|
4月前
|
监控 安全 Java
Java中的AOP编程实践与应用场景
Java中的AOP编程实践与应用场景
|
4月前
|
监控 Java 数据安全/隐私保护
Spring AOP实现原理及其在企业应用中的实际应用
Spring AOP实现原理及其在企业应用中的实际应用
|
4月前
|
XML 监控 Java
Java中的AOP编程:AspectJ与Spring AOP的应用
Java中的AOP编程:AspectJ与Spring AOP的应用