Java AOP的实现机制

Spring——AOP原理及流程详解 基于5.3.9 版本的Spring源码,对AOP原理及流程详解,AOP是在Bean生成流程中什么位置介入处理的?各个通知方法又是怎么组装的?AOP真的只是动态代理这么简单吗? 阅读详情

申明:本文转载:http://www.iteye.com/topic/1116696


1 AOP各种的实现

AOP就是面向切面编程,我们可以从几个层面来实现AOP。

在编译器修改源代码,在运行期字节码加载前修改字节码或字节码加载后动态创建代理类的字节码,以下是各种实现机制的比较。 

 

类别

机制

原理

优点

缺点

静态AOP

静态织入

在编译期,切面直接以字节码的形式编译到目标字节码文件中。

对系统无性能影响。

灵活性不够。

动态AOP

动态代理

在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。

相对于静态AOP更加灵活。

切入的关注点需要实现接口。对系统有一点性能影响。

动态字节码生成

在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。

没有接口也可以织入。

扩展类的实例方法为final时,则无法进行织入。

自定义类加载器

在运行期,目标加载前,将切面逻辑加到目标字节码里。

可以对绝大部分类进行织入。

代码中如果使用了其他类加载器,则这些类将不会被织入。

字节码转换

在运行期,所有类加载器加载字节码前,前进行拦截。

可以对所有类进行织入。

 



2 AOP里的公民 

  • Joinpoint:拦截点,如某个业务方法。
  • Pointcut:Joinpoint的表达式,表示拦截哪些方法。一个Pointcut对应多个Joinpoint。
  • Advice:  要切入的逻辑。
  • Before Advice 在方法前切入。
  • After Advice 在方法后切入,抛出异常时也会切入。
  • After Returning Advice 在方法返回后切入,抛出异常则不会切入。
  • After Throwing Advice 在方法抛出异常时切入。
  • Around Advice 在方法执行前后切入,可以中断或忽略原有流程的执行。 
  • 公民之间的关系 

    织入器通过在切面中定义pointcut来搜索目标(被代理类)的JoinPoint(切入点),然后把要切入的逻辑(Advice)织入到目标对象里,生成代理类。 

3 AOP的实现机制 
  本章节将详细介绍AOP有各种实现机制。


3.1 动态代理 
  Java在JDK1.3后引入的动态代理机制,使我们可以在运行期动态的创建代理类。使用动态代理实现AOP需要有四个角色:被代理的类,被代理类的接口,织入器,和InvocationHandler,而织入器使用接口反射机制生成一个代理类,然后在这个代理类中织入代码。被代理的类是AOP里所说的目标,InvocationHandler是切面,它包含了Advice和Pointcut。 


3.1.1 使用动态代理 
  那如何使用动态代理来实现AOP。下面的例子演示在方法执行前织入一段记录日志的代码,其中Business是代理类,LogInvocationHandler是记录日志的切面,IBusiness, IBusiness2是代理类的接口,Proxy.newProxyInstance是织入器。 
清单一:动态代理的演示

Java代码   收藏代码
  1. public static void main(String[] args) {   
  2.     //需要代理的接口,被代理类实现的多个接口都必须在这里定义   
  3.     Class[] proxyInterface = new Class[] { IBusiness.class, IBusiness2.class };   
  4.     //构建AOP的Advice,这里需要传入业务类的实例   
  5.     LogInvocationHandler handler = new LogInvocationHandler(new Business());   
  6.     //生成代理类的字节码加载器   
  7.     ClassLoader classLoader = DynamicProxyDemo.class.getClassLoader();   
  8.     //织入器,织入代码并生成代理类   
  9.     IBusiness2 proxyBusiness = (IBusiness2) Proxy.newProxyInstance(classLoader, proxyInterface, handler);   
  10.     //使用代理类的实例来调用方法。   
  11.     proxyBusiness.doSomeThing2();   
  12.     ((IBusiness) proxyBusiness).doSomeThing();   
  13. }   
  14.   
  15. /**  
  16. * 打印日志的切面  
  17. */   
  18. public static class LogInvocationHandler implements InvocationHandler {   
  19.   
  20.     private Object target; //目标对象   
  21.   
  22.     LogInvocationHandler(Object target) {   
  23.         this.target = target;   
  24.     }   
  25.   
  26.     @Override   
  27.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   
  28.         //执行原有逻辑   
  29.         Object rev = method.invoke(target, args);   
  30.         //执行织入的日志,你可以控制哪些方法执行切入逻辑   
  31.         if (method.getName().equals("doSomeThing2")) {   
  32.             System.out.println("记录日志");   
  33.         }   
  34.         return rev;   
  35.     }   
  36. }   
  37.   
  38. 接口IBusiness和IBusiness2定义省略。   

 

   业务类,需要代理的类。

Java代码   收藏代码
  1. public class Business implements IBusiness, IBusiness2 {   
  2.   
  3.     @Override   
  4.     public boolean doSomeThing() {   
  5.         System.out.println("执行业务逻辑");   
  6.         return true;   
  7.     }   
  8.   
  9.     @Override   
  10.     public void doSomeThing2() {   
  11.         System.out.println("执行业务逻辑2");   
  12.     }   
  13.   
  14. }   

 

   输出

Java代码   收藏代码
  1. 执行业务逻辑2   
  2. 记录日志   
  3. 执行业务逻辑   

 

  可以看到“记录日志”的逻辑切入到Business类的doSomeThing方法前了。


 

3.1.2 动态代理原理 
    本节将结合动态代理的源代码讲解其实现原理。动态代理的核心其实就是代理对象的生成,即Proxy.newProxyInstance(classLoader, proxyInterface, handler)。让我们进入newProxyInstance方法观摩下,核心代码其实就三行。 
清单二:生成代理类

Java代码   收藏代码
  1. //获取代理类   
  2. Class cl = getProxyClass(loader, interfaces);   
  3. //获取带有InvocationHandler参数的构造方法   
  4. Constructor cons = cl.getConstructor(constructorParams);   
  5. //把handler传入构造方法生成实例   
  6. return (Object) cons.newInstance(new Object[] { h });     

 

    其中getProxyClass(loader, interfaces)方法用于获取代理类,它主要做了三件事情:在当前类加载器的缓存里搜索是否有代理类,没有则生成代理类并缓存在本地JVM里。清单三:查找代理类。

Java代码   收藏代码
  1.  // 缓存的key使用接口名称生成的List   
  2. Object key = Arrays.asList(interfaceNames);   
  3. synchronized (cache) {   
  4.     do {   
  5. Object value = cache.get(key);   
  6.          // 缓存里保存了代理类的引用   
  7. if (value instanceof Reference) {   
  8.     proxyClass = (Class) ((Reference) value).get();   
  9. }   
  10. if (proxyClass != null) {   
  11. // 代理类已经存在则返回   
  12.     return proxyClass;   
  13. } else if (value == pendingGenerationMarker) {   
  14.     // 如果代理类正在产生,则等待   
  15.     try {   
  16. cache.wait();   
  17.     } catch (InterruptedException e) {   
  18.     }   
  19.     continue;   
  20. } else {   
  21.     //没有代理类,则标记代理准备生成   
  22.     cache.put(key, pendingGenerationMarker);   
  23.     break;   
  24. }   
  25.     } while (true);   
  26. }   

  

代理类的生成主要是以下这两行代码。 清单四:生成并加载代理类

 

Java代码   收藏代码
  1. //生成代理类的字节码文件并保存到硬盘中(默认不保存到硬盘)   
  2. proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);   
  3. //使用类加载器将字节码加载到内存中   
  4. proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);   

 

  ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用JD-GUI这样的反编译软件打开jre\lib\rt.jar来一探究竟,以下是其核心代码的分析。 
清单五:代理类的生成过程

Java代码   收藏代码
  1. //添加接口中定义的方法,此时方法体为空   
  2. for (int i = 0; i < this.interfaces.length; i++) {   
  3.   localObject1 = this.interfaces[i].getMethods();   
  4.   for (int k = 0; k < localObject1.length; k++) {   
  5.      addProxyMethod(localObject1[k], this.interfaces[i]);   
  6.   }   
  7. }   
  8.   
  9. //添加一个带有InvocationHandler的构造方法   
  10. MethodInfo localMethodInfo = new MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1);   
  11.   
  12. //循环生成方法体代码(省略)   
  13. //方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略)   
  14. this.cp.getInterfaceMethodRef("InvocationHandler", "invoke", "Object; Method; Object;")   
  15.   
  16. //将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。   
  17. localFileOutputStream = new FileOutputStream(ProxyGenerator.access$000(this.val$name) + ".class");   
  18. localFileOutputStream.write(this.val$classFile);   

 

  那么通过以上分析,我们可以推出动态代理为我们生成了一个这样的代理类。把方法doSomeThing的方法体修改为调用LogInvocationHandler的invoke方法。 
清单六:生成的代理类源码

 

Java代码   收藏代码
  1. public class ProxyBusiness implements IBusiness, IBusiness2 {   
  2.   
  3. private LogInvocationHandler h;   
  4.   
  5. @Override   
  6. public void doSomeThing2() {   
  7.     try {   
  8.         Method m = (h.target).getClass().getMethod("doSomeThing", null);   
  9.         h.invoke(this, m, null);   
  10.     } catch (Throwable e) {   
  11.         // 异常处理(略)   
  12.     }   
  13. }   
  14.   
  15. @Override   
  16. public boolean doSomeThing() {   
  17.     try {   
  18.        Method m = (h.target).getClass().getMethod("doSomeThing2", null);   
  19.        return (Boolean) h.invoke(this, m, null);   
  20.     } catch (Throwable e) {   
  21.         // 异常处理(略)   
  22.     }   
  23.     return false;   
  24. }   
  25.   
  26. public ProxyBusiness(LogInvocationHandler h) {   
  27.     this.h = h;   
  28. }   
  29.   
  30. //测试用   
  31. public static void main(String[] args) {   
  32.     //构建AOP的Advice   
  33.     LogInvocationHandler handler = new LogInvocationHandler(new Business());   
  34.     new ProxyBusiness(handler).doSomeThing();   
  35.     new ProxyBusiness(handler).doSomeThing2();   
  36. }   
  37. }   

 

3.1.3 小结 
    从前两节的分析我们可以看出,动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,经过测试大概每个代理类比静态代理多出10几毫秒的消耗。其次使用反射大量生成类文件可能引起Full GC造成性能影响,因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,可以将持久代设置大一些,减少Full GC次数。 

3.2 动态字节码生成 
   使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。


    本节介绍如何使用Cglib来实现动态字节码技术。Cglib是一个强大的,高性能的Code生成类库,它可以在运行期间扩展Java类和实现Java接口,它封装了Asm,所以使用Cglib前需要引入Asm的jar。 清单七:使用CGLib实现AOP

Java代码   收藏代码
  1. public static void main(String[] args) {   
  2.         byteCodeGe();   
  3.     }   
  4.   
  5.     public static void byteCodeGe() {   
  6.         //创建一个织入器   
  7.         Enhancer enhancer = new Enhancer();   
  8.         //设置父类   
  9.         enhancer.setSuperclass(Business.class);   
  10.         //设置需要织入的逻辑   
  11.         enhancer.setCallback(new LogIntercept());   
  12.         //使用织入器创建子类   
  13.         IBusiness2 newBusiness = (IBusiness2) enhancer.create();   
  14.         newBusiness.doSomeThing2();   
  15.     }   
  16.   
  17.     /**  
  18.      * 记录日志  
  19.      */   
  20.     public static class LogIntercept implements MethodInterceptor {   
  21.   
  22.         @Override   
  23.         public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {   
  24.             //执行原有逻辑,注意这里是invokeSuper   
  25.             Object rev = proxy.invokeSuper(target, args);   
  26.             //执行织入的日志   
  27.             if (method.getName().equals("doSomeThing2")) {   
  28.                 System.out.println("记录日志");   
  29.             }   
  30.             return rev;   
  31.         }   
  32.     }   

 

 

3.3 自定义类加载器 
   如果我们实现了一个自定义类加载器,在类加载到JVM之前直接修改某些类的方法,并将切入逻辑织入到这个方法里,然后将修改后的字节码文件交给虚拟机运行,那岂不是更直接。

 



Javassist是一个编辑字节码的框架,可以让你很简单地操作字节码。它可以在运行期定义或修改Class。使用Javassist实现AOP的原理是在字节码加载前直接修改需要切入的方法。这比使用Cglib实现AOP更加高效,并且没太多限制,实现原理如下图: 






    我们使用系统类加载器启动我们自定义的类加载器,在这个类加载器里加一个类加载监听器,监听器发现目标类被加载时就织入切入逻辑,咱们再看看使用Javassist实现AOP的代码: 
清单八:启动自定义的类加载器

Java代码   收藏代码
  1. //获取存放CtClass的容器ClassPool   
  2. ClassPool cp = ClassPool.getDefault();   
  3. //创建一个类加载器   
  4. Loader cl = new Loader();   
  5. //增加一个转换器   
  6. cl.addTranslator(cp, new MyTranslator());   
  7. //启动MyTranslator的main函数   
  8. cl.run("jsvassist.JavassistAopDemo$MyTranslator", args);   

 清单九:类加载监听器

Java代码   收藏代码
  1. public static class MyTranslator implements Translator {   
  2.   
  3.         public void start(ClassPool pool) throws NotFoundException, CannotCompileException {   
  4.         }   
  5.   
  6.         /* *  
  7.          * 类装载到JVM前进行代码织入  
  8.          */   
  9.         public void onLoad(ClassPool pool, String classname) {   
  10.             if (!"model$Business".equals(classname)) {   
  11.                 return;   
  12.             }   
  13.             //通过获取类文件   
  14.             try {   
  15.                 CtClass  cc = pool.get(classname);   
  16.                 //获得指定方法名的方法   
  17.                 CtMethod m = cc.getDeclaredMethod("doSomeThing");   
  18.                 //在方法执行前插入代码   
  19.                 m.insertBefore("{ System.out.println(\"记录日志\"); }");   
  20.             } catch (NotFoundException e) {   
  21.             } catch (CannotCompileException e) {   
  22.             }   
  23.         }   
  24.   
  25.         public static void main(String[] args) {   
  26.             Business b = new Business();   
  27.             b.doSomeThing2();   
  28.             b.doSomeThing();   
  29.         }   
  30.     }   

 输出: 

Java代码   收藏代码
  1. 执行业务逻辑2   
  2. 记录日志   
  3. 执行业务逻辑  

  
    其中Bussiness类在本文的清单一中定义。看起来是不是特别简单,CtClass是一个class文件的抽象描述。咱们也可以使用insertAfter()在方法的末尾插入代码,使用insertAt()在指定行插入代码。 

3.3.1 小结 
    从本节中可知,使用自定义的类加载器实现AOP在性能上要优于动态代理和Cglib,因为它不会产生新类,但是它仍然存在一个问题,就是如果其他的类加载器来加载类的话,这些类将不会被拦截。 

3.4 字节码转换 
    自定义的类加载器实现AOP只能拦截自己加载的字节码,那么有没有一种方式能够监控所有类加载器加载字节码呢?有,使用Instrumentation,它是 Java 5 提供的新特性,使用 Instrumentation,开发者可以构建一个字节码转换器,在字节码加载前进行转换。本节使用Instrumentation和javassist来实现AOP。 

3.4.1 构建字节码转换器 
    首先需要创建字节码转换器,该转换器负责拦截Business类,并在Business类的doSomeThing方法前使用javassist加入记录日志的代码。

Java代码   收藏代码
  1. public class MyClassFileTransformer implements ClassFileTransformer {   
  2.   
  3.     /**  
  4.      * 字节码加载到虚拟机前会进入这个方法  
  5.      */   
  6.     @Override   
  7.     public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,   
  8.                             ProtectionDomain protectionDomain, byte[] classfileBuffer)   
  9.             throws IllegalClassFormatException {   
  10.         System.out.println(className);   
  11.         //如果加载Business类才拦截   
  12.         if (!"model/Business".equals(className)) {   
  13.             return null;   
  14.         }   
  15.   
  16.         //javassist的包名是用点分割的,需要转换下   
  17.         if (className.indexOf("/") != -1) {   
  18.             className = className.replaceAll("/", ".");   
  19.         }   
  20.         try {   
  21.             //通过包名获取类文件   
  22.             CtClass cc = ClassPool.getDefault().get(className);   
  23.             //获得指定方法名的方法   
  24.             CtMethod m = cc.getDeclaredMethod("doSomeThing");   
  25.             //在方法执行前插入代码   
  26.             m.insertBefore("{ System.out.println(\"记录日志\"); }");   
  27.             return cc.toBytecode();   
  28.         } catch (NotFoundException e) {   
  29.         } catch (CannotCompileException e) {   
  30.         } catch (IOException e) {   
  31.             //忽略异常处理   
  32.         }   
  33.         return null;   
  34. }   

 

3.4.2 注册转换器 
    使用premain函数注册字节码转换器,该方法在main函数之前执行。

Java代码   收藏代码
  1. public class MyClassFileTransformer implements ClassFileTransformer {   
  2.     public static void premain(String options, Instrumentation ins) {   
  3.         //注册我自己的字节码转换器   
  4.         ins.addTransformer(new MyClassFileTransformer());   
  5. }   
  6. }   

 

3.4.3 配置和执行 
    需要告诉JVM在启动main函数之前,需要先执行premain函数。首先需要将premain函数所在的类打成jar包。并修改该jar包里的META-INF\MANIFEST.MF 文件。 

Java代码   收藏代码
  1. Manifest-Version: 1.0   
  2. Premain-Class: bci. MyClassFileTransformer  

     然后在JVM的启动参数里加上。-javaagent:D:\java\projects\opencometProject\Aop\lib\aop.jar 

             3.4.4 输出

    执行main函数,你会发现切入的代码无侵入性的织入进去了。

Java代码   收藏代码
  1. public static void main(String[] args) {   
  2.    new Business().doSomeThing();   
  3.    new Business().doSomeThing2();   
  4. }   
  5.    

   输出

Java代码   收藏代码
  1. model/Business   
  2. sun/misc/Cleaner   
  3. java/lang/Enum   
  4. model/IBusiness   
  5. model/IBusiness2   
  6. 记录日志   
  7. 执行业务逻辑   
  8. 执行业务逻辑2   
  9. java/lang/Shutdown   
  10. java/lang/Shutdown$Lock   

  

 从输出中可以看到系统类加载器加载的类也经过了这里。

 

4 AOP实战 
说了这么多理论,那AOP到底能做什么呢? AOP能做的事情非常多。

  • 性能监控,在方法调用前后记录调用时间,方法执行太长或超时报警。
  • 缓存代理,缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
  • 软件破解,使用AOP修改软件的验证类的判断逻辑。
  • 记录日志,在方法执行前后记录系统日志。
  • 工作流系统,工作流系统需要将业务代码和流程引擎代码混合在一起执行,那么我们可以使用AOP将其分离,并动态挂接业务。
  • 权限验证,方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉。 

4.1 Spring的AOP 
    Spring默认采取的动态代理机制实现AOP,当动态代理不可用时(代理类无接口)会使用CGlib机制。但Spring的AOP有一定的缺点,第一个只能对方法进行切入,不能对接口,字段,静态代码块进行切入(切入接口的某个方法,则该接口下所有实现类的该方法将被切入)。第二个同类中的互相调用方法将不会使用代理类。因为要使用代理类必须从Spring容器中获取Bean。第三个性能不是最好的,从3.3章节我们得知使用自定义类加载器,性能要优于动态代理和CGlib。 
可以获取代理类

Java代码   收藏代码
  1. public IMsgFilterService getThis()   
  2. {   
  3.         return (IMsgFilterService) AopContext.currentProxy();   
  4. }   
  5.   
  6. public boolean evaluateMsg () {   
  7.    // 执行此方法将织入切入逻辑   
  8. return getThis().evaluateMsg(String message);   
  9. }   
  10.   
  11. @MethodInvokeTimesMonitor("KEY_FILTER_NUM")   
  12. public boolean evaluateMsg(String message) {   

 不能获取代理类

Java代码   收藏代码
  1. public boolean evaluateMsg () {   
  2.    // 执行此方法将不会织入切入逻辑   
  3. return evaluateMsg(String message);   
  4. }   
  5.   
  6. @MethodInvokeTimesMonitor("KEY_FILTER_NUM")   
  7. public boolean evaluateMsg(String message) {   
Java-重试机制怎么实现,自定义注解+AOP 在 Java 中实现重试机制有多种方法,可以根据具体需求选择合适的方式。以下是一些常见的实现。创建一个 AOP 切面类,用于拦截带有 @Retryable 注解的方法,并实现重试逻辑。Spring Retry:适用于使用 Spring 框架的项目,提供了丰富的配置选项。Spring Retry 是一个强大的库,提供了丰富的重试机制配置。创建一个自定义注解 @Retryable,用于标记需要重试的方法。这是最基础的重试方式,通过一个简单的循环来实现。简洁:通过注解标记需要重试的方法,代码更加简洁。 阅读详情

相关推荐

aop的四种实现方式

aop的四种实现方式代码示例,包括javassist cglib instrument dynamicproxy四种,里面都有注释。

AOP的实现机制

附件中有本文的源代码和Pdf版。本文写的很长的原因,是不希望大家学习AOP时到处找资料,大家有时间可以按照本文动手实践下,相信会有非常大的收获的,有什么问题互相交流,有问必答! 1 AOP各种的实现     AOP就是面向切面编程,我们可以从几个层面来实现AOP。 在编译器修改源代码,在运行期字节码加载前修改字节码或字节码加载后动态创建代理类的字节码,以下是各种实现机制的比较。    ...

执着之道 741

Transformers在自动驾驶领域的应用(High-level like in scene)

Transformers uses global attention mechanism to capture long-range interaction information. Two core modules in Transformers are Self-Attention and Cross-Attention, which defined asAttn(Q,K,V)=softmax(QK⊤dk)VSelfAttn(X)=Attn(WQX,WKX,WVX)CrossAttn(X,Y)=Attn

qq_39337332的博客 1776

关于AOP的实现原理

什么是AOP,AOP即面向切面编程,和OOP(面向对象编程)类似,也是一种编程思想。AOP采取横向抽取机制(动态代理),取代了传统纵向继承机制的重要性代码,其应用主要体现在事务处理,日志管理、权限控制、异常处理等方面。主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少业务代码的侵入,增强代码的可读性和可维护性。简单的来说,AOP的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。AOP就是代理模式的典型应用。

m0_56065322的博客 4868

从零搭建企业级AI网关:基于LiteLLM的安全防护体系设计

本文详细介绍了如何从零搭建企业级AI网关,基于LiteLLM构建全面的安全防护体系。内容涵盖分层防御架构、敏感数据处理、合规性配置与审计追踪,以及生产环境部署策略,助力企业安全高效地集成LLM技术,确保数据安全和合规性。

qq_27496129的博客 1291

解锁RK3588视觉潜能:RGA硬件加速库实战指南

本文深入探讨了如何利用RK3588芯片内置的RGA硬件加速库,解决视觉应用中图像预处理的性能瓶颈。通过实战指南,详细介绍了RGA库在YUV转RGB、图像缩放等核心操作上的应用,相比CPU软处理可大幅降低延迟与CPU占用,从而充分释放RK3588的NPU算力,构建高效的AI视觉预处理流水线。

zeta9的博客 669

AOP的四种实现方式

AOP实现方式

d1451545368的博客 2046

[VT虚拟化驱动]利用EPT实现无痕HOOK

本章利用讲EPT无痕HOOK

吾无法无天的博客 1万+

[转]AOP及其Java实现机制

1引言传统的编程技术,采用分解的方式将一个软件系统划分为相对较小的、易于分析、理解的模块,如果这些模块仍难以分析、理解,则迭代的将其分解为更小的模块,直到这些模块可以容易的分析、理解、设计与编码。通过对这些模块进行分析,设计,然后使用相应的编程语言实现这些模块,再以编程语言所定义的方式将这些模块组装起来,形成最终的软件系统。例如,面向过程编程中,将系统分解为完成单一功能的函数,并通过函数之间的调用

[乖的无聊]--JustSosO 1万+

不加行也能填满:用 ABAP BDC 驯服 Table Control 滚动录制缺陷,批量维护供应商银行账户

摘要 本文探讨了在SAP ECC/S4HANA系统中处理供应商主数据时,Table Control控件带来的批量导入挑战。文章指出,银行账户维护界面中Table Control的滚动动作难以被录制工具捕捉,导致批量导入数据时仅能填充前5行。解决方案是通过BDC_OKCODE显式触发翻页(如=P+),并配合行号拼接(如(01)~(05))将数据写入不可见行。文中提供了完整的ABAP程序示例,展示了如何读取外部文件、动态生成BDCDATA、处理表格翻页逻辑,最终通过CALL TRANSACTION执行XK01事

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 272

超临界二氧化碳再热再压缩布雷顿循环建模与先进控制

超临界二氧化碳布雷顿循环建模与先进控制研究 本文研究了超临界二氧化碳再热再压缩布雷顿循环系统的建模与控制。通过MATLAB/Simscape构建了包含压缩机、透平、回热器等关键组件的动态模型,并设计了基于模型预测控制(MPC)和自抗扰控制(ADRC)的多层控制策略。系统采用转速控制的压缩机、阀门开度控制的透平,以及可变热源加热器,实现了全动态分析。研究结果表明,MPC与ADRC混合控制方案相较于传统PID控制,功率超调降低至0.9%,效率波动控制在±0.08%,扰动恢复时间缩短至12秒。

AI的内部世界的博客 342

Java平台上的AOP实现机制

Java平台上的AOP实现机制 动态代理(Dynamic Proxy)机制,在运行期间动态的为相应接口生成对应的代理对象。SpringAop默认情况下采用这种机制来实现AOP机能。缺点:相对于编译后的静态类的执行,性能上可能略逊一筹。 动态字节码增强,通过ASM或者CGLIB等java工具库,在程序运行期间,动态构建字节码的class文件。在这样的技术前提下,我们可以为需要织入横切逻辑的模块类在...

weixin_30525825的博客 105

第一章:Profibus DP通信简介

PROFIBUS (Process Fieldbus)的缩写,是一种国际化的、开放的、不依赖于设备生产商的现场总线标准。它广泛应用于制造业自动化、流程工业自动化和楼宇、交通、电力等其他工业自动化领域。串行现场总线主要用来连接数字现场设备或中、低功能的系统,如传感器、执行机构、变送器、可编程序控制器(PLC)、数控装置(NC)、编程设备、本地人机接口等。

qq_22560021的博客 4895

AOP及其Java实现机制

[转]AOP及其Java实现机制 1引言传统的编程技术,采用分解的方式将一个软件系统划分为相对较小的、易于分析、理解的模块,如果这些模块仍难以分析、理解,则迭代的将其分解为更小的模块,直到这些模块可以容易的分析、理解、设计与编码。通过对这些模块进行分析,设计,然后使用相应的编程语言实现这些模块,再以编程语言所定义的方式将这些模块组装起来,形成最终的软件系统。例如,面向过程编程中,将...

weixin_30369041的博客 97

ABAP CDS HAVING 全解析:聚合之后的精准过滤、最佳实践与可运行示例

摘要: 本文针对具备ABAP与CDS基础的开发者,详解HAVING在ABAP CDS中的核心用法。HAVING专用于过滤GROUP BY后的聚合结果(如SUM、COUNT),与WHERE的分工明确:前者处理聚合值,后者过滤原始记录。通过销售额阈值、质量分析、财务对账三类典型场景,结合性能优化建议(如优先使用WHERE索引过滤),说明实际应用。文中提供经典CDS View与View Entity两种实现代码,并附Open SQL消费示例,帮助开发者快速落地。常见误区(如聚合条件误写至WHERE)与规避方法亦被

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 221

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

利用Java的反射与代理机制实现AOP

在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP。 一.AOP概述        AOP(Aspect Oriented Programing),即面向切面编程,它主要用于日志记录、性能统计、安全控制、事务处理、异常处理等方面。它的主要意图就要将日志记录,性能统计,安全控制、事务

好习惯要坚持下去 3280

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

JAVA中的动态代理机制实现AOP

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33749131的博客 100

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Spring系列之Java代理机制实现AOP

【回顾】     在之前的学习中,我们对Spring框架有了一个宏观认识,并且深入分析学习了它的核心内容IOC。从这篇博客,将开始对其另一个重要思想的实现展开学习,那就是AOP。     【前言】     AOP的意思是面向切面编程,英文全称是Aspect Oriented Programming,它是开发人员可以更好地将本不应该耦合在一起的功能分离开。     【内容】         一.认识

Dream it Possible 1045

【Java】利用Java的反射与代理机制实现AOP

  原文出处:http://publish.itpub.net/j/2007-10-17/200710170923968.shtml 在上一篇文章中,我们讲述了利用Java的反射机制中实现Spring中的IOC,在本文中,我们将更进一步,讲述用Java的反射和动态代理机制来实现Spring的AOP。      一.AOP概述       AOP(Aspect Oriented Progra

850

Java中的AOP代理:基于CGLIB的子类代理如何通过FastClass机制实现调用

理解 CGLIB 代理和 FastClass 的原理,有助于更好地理解 Spring AOP 的底层实现,并在需要优化性能时做出更明智的选择。动态代理允许我们在运行时创建代理对象,这些代理对象可以拦截对目标对象的调用,并在调用前后添加额外的行为(例如日志记录、事务管理)。当我们调用代理对象的方法时,实际上调用的是子类重写后的方法,从而实现 AOP 的功能。好的,我们开始今天的讲座:Java AOP 中基于 CGLIB 的子类代理以及 FastClass 机制的实现原理。

weixin_41455464的博客 459

java中的动态代理机制实现AOP

从JDK1.3以后,Java提供了动态代理的机制。动态代理是一种强大的语言结构,可以为一个或多个接口创建代理对像而不需要预先用于一个接口的实现类。Java中的动态代理机制可以方便地用于实现AOP。    考虑如下情形:当需要为多个不具有继承层次的对象引入同一个公共行为的时候,例如记录日志,安全检查等等。如果考虑用OOP的思想进行设计,需要为每一个对象实现相同功能的记录日志或者安全检查的方法,

Petric_Hwang的专栏 742

Java 动态代理(AOP实现机制)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33961829的博客 206
上一篇: Unity3d压缩文件
下一篇: OpcenCV+VS2015
spring_shower
博客等级 码龄12年 12粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值