动态代理解释-JDK,CGLIB,JAVASSIST,ASM

简介:

动态代理是指在运行时,动态生成代理类。代理类的字节码将在运行时生成并载入当前的ClassLoader.

         生成动态代理类的方法很多,如JDK自带的动态代理、CGLIBJavassist或者ASM库。

          JDK动态代理使用简单,它内置在JDK中,因此不需要引入第三方Jar包,但相对功能比较弱。CGLIBJavassist都是高级的字节码生成库,总体性能比JDK自带的动态代理好,而且功能十分强大。ASM是低级的字节码生成工具,使用ASM已经近乎在于使用Javabytecode编程,对开发人员要求较高,也是性能最好的一种动态代理生辰工具。但ASM的使用是在过于繁琐,而且性能也没有数量级的提升,与CGLIB等高级字节码生成工具相比,ASM程序的可维护性也较差。

 

JDK实现

1、步骤

 

1)通过实现InvocationHandler接口创建自己的调用处理器

2)通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类

3)通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型

4)通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入

 

2、创建代理

 

[java]  view plain  copy
 
  print ?
  1.  //InvocationHandlerImpl 实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发  
  2. //其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用  
  3. InvocationHandler handler = new InvocaitonHandlerImpl(..);  
  4.   
  5. //通过Proxy为包括Interface接口在内的一组接口动态创建代理类的对象  
  6. Class clazz = Proxy.getProxyClass(classLoader,new Class[]{Interface.class,...});  
  7.   
  8. //通过反射从生成的类对象获得构造函数对象  
  9.        Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});  
  10.   
  11. //通过构造函数对象创建动态代理类实例  
  12. Interface Proxy = (Interface)constructor.newInstance(new Object[]{handler});  
  13.   
  14. //Proxy类的静态方法newProxyInstance对上面具体步骤的后三步做了封装,简化了动态代理对象的获取过程。  
  15. //InvocationHandlerImpl实现了InvocaitonHandler接口,并能实现方法调用从代理类到委托类的分派转发  
  16. InvocaitonHandler handler = new InvocationHandlerImpl(..);  
  17. //通过Proxy直接创建动态代理类实例  
  18.   
  19. nterface proxy = (Interface)Proxy.newProxyInstance(classLoader,new Class[]{Interface.class},handler);  

 

 

3、代码

 

[java]  view plain  copy
 
  print ?
  1. /** 
  2.  * 接口 
  3.  * @author Emily 
  4.  * 
  5.  */  
  6. public interface IDBQuery {  
  7.   
  8.     String request();  
  9. }  
  10.   
  11. /** 
  12.  * 真实的实现类,具体的目标对象 
  13.  * @author Emily 
  14.  * 
  15.  */  
  16. public class DBQuery implements IDBQuery {  
  17.   
  18.       
  19.     public DBQuery(){  
  20.         try {  
  21.             Thread.sleep(1000); //可能包含数据库连接等耗时操作  
  22.         } catch (InterruptedException e) {  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26.       
  27.     @Override  
  28.     public String request() {  
  29.           
  30.         return "request string";  
  31.     }  
  32.   
  33. }  
  34.   
  35. /** 
  36.  * JDK动态代理的实现类 
  37.  * @author Emily 
  38.  * 
  39.  */  
  40. public class JdkDbQueryHandler implements InvocationHandler{  
  41.   
  42.     IDBQuery real = null//主题接口  
  43.   
  44.     /** 
  45.      * 生成Handler 
  46.      */  
  47.     @Override  
  48.     public Object invoke(Object proxy, Method method, Object[] args)  
  49.             throws Throwable {  
  50.         if(real == null)  
  51.             real = new DBQuery(); //如果是第一次调用,则生成真实对象  
  52.         return real.request();  //使用真实主题完成实际的操作  
  53.     }  
  54.       
  55.     /** 
  56.      * 利用Handler生成动态代理对象 
  57.      * @return 
  58.      */  
  59.     public static IDBQuery createJdkProxy(){  
  60.           
  61.         //根据指定的类加载器和接口以及截获器,返回代理类的一个实例对象  
  62.         //ClassLoader loader :指定被代理对象的类加载器  
  63.         //Class[] Interfaces :指定被代理对象所以事项的接口  
  64.         //InvocationHandler h :指定需要调用的InvocationHandler对象  
  65.         IDBQuery jdkProxy = (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IDBQuery.class}, new JdkDbQueryHandler());  
  66.         return jdkProxy;  
  67.     }  
  68.       
  69.       
  70. }  

执行过程:


       如图,目标对象的方法调用被Proxy拦截,在InvocationHandler中的回调方法中通过反射调用,这种动态代理的方法实现了对类的方法的运行时修改。

        JDK动态代理有个缺点,那就是不能对类进行代理,只能对接口进行代理,如果我们的类没有实现任何接口,那么就不能使用这种方式进行动态代理(因为$Proxy()这个类集成了Proxy,Java的集成不允许出现多个父类)。准确的说这不应该是缺点,一个良好的系统,每个类都应该有一个接口与之对应。针对接口编程。

 

CGLIB实现

 

[java]  view plain  copy
 
  print ?
  1. package com.ltt.dynamic;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.Enhancer;  
  6. import net.sf.cglib.proxy.MethodInterceptor;  
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. /** 
  10.  * CGLIB动态代理 
  11.  * @author Emily 
  12.  * 
  13.  */  
  14. public class CglibDbQueryInterceptor implements MethodInterceptor{  
  15.     IDBQuery real = null;  
  16.   
  17.     /** 
  18.      * 处理代理逻辑的切入类 
  19.      */  
  20.     @Override  
  21.     public Object intercept(Object arg0, Method arg1, Object[] arg2,  
  22.             MethodProxy arg3) throws Throwable {  
  23.         if (real == null) {    //代理类 的内部逻辑  
  24.             real = new DBQuery();  
  25.             return real.request();  
  26.         }  
  27.         return null;  
  28.     }  
  29.       
  30.     /** 
  31.      * 生成动态代理 
  32.      * @return 
  33.      */  
  34.     public static IDBQuery createCglibProxy(){  
  35.         Enhancer enhancer = new Enhancer();  
  36.         //指定切入器,定义代理类逻辑  
  37.         enhancer.setCallback(new CglibDbQueryInterceptor());  
  38.         //指定实现的接口  
  39.         enhancer.setInterfaces(new Class[]{IDBQuery.class});  
  40.           
  41.         IDBQuery cglibProxy = (IDBQuery) enhancer.create();  
  42.         return cglibProxy;  
  43.     }  
  44.       
  45.   
  46. }  



 

Javassist实现

       一种是使用代理工厂创建,另一种通过使用动态代码创建。使用代理工厂创建时,方法与CGLIB类似,也需要实现一个用于代理逻辑处理的Handler:例如createJavassistDynProxy();使用动态代码创建,生成字节码,这种方式可以非常灵活,甚至可以在运行时生成业务逻辑,如createJavassistBytecodeDynamicProxy()方法。

 

[java]  view plain  copy
 
  print ?
  1. /** 
  2.  * Javassist动态代理 
  3.  * @author Emily 
  4.  * 
  5.  */  
  6. public class JavassistDynDbQueryHandler implements MethodHandler{  
  7.   
  8.     IDBQuery real = null;  
  9.   
  10.     /* 
  11.      * (non-Javadoc) 实现用于代理逻辑处理的Handler 
  12.      * @see javassist.util.proxy.MethodHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.reflect.Method, java.lang.Object[]) 
  13.      */  
  14.     @Override  
  15.     public Object invoke(Object arg0, Method arg1, Method arg2, Object[] arg3)  
  16.             throws Throwable {  
  17.         if (real == null)   
  18.             real = new DBQuery();  
  19.             return real.request();  
  20.           
  21.     }  
  22.       
  23.     /** 
  24.      * 创建动态代理 
  25.      * @return 
  26.      * @throws Exception 
  27.      */  
  28.     public static IDBQuery createJavassistDynProxy() throws Exception{  
  29.         ProxyFactory proxyFactory = new ProxyFactory();  
  30.         proxyFactory.setInterfaces(new Class[]{IDBQuery.class});  //指定接口  
  31.         Class proxyClass = proxyFactory.createClass();  
  32.         IDBQuery javassistProxy = (IDBQuery) proxyClass.newInstance(); //设置Handler处理器  
  33.         ((ProxyObject) javassistProxy).setHandler(new JavassistDynDbQueryHandler());  
  34.         return javassistProxy;  
  35.     }  
  36.       
  37.     /** 
  38.      * 运行时生成业务逻辑 
  39.      * @return 
  40.      * @throws Exception 
  41.      */  
  42.     public static IDBQuery createJavassistBytecodeDynamicProxy() throws Exception{  
  43.         ClassPool mPool = new ClassPool(true);  
  44.         //定义类名  
  45.         CtClass mCtc = mPool.makeClass(IDBQuery.class.getName() + "JavaassistBytecodeProxy");  
  46.         //需要实现接口  
  47.         mCtc.addInterface(mPool.get(IDBQuery.class.getName()));  
  48.         //添加构造函数  
  49.         mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));  
  50.           
  51.         //添加类的字段信息,使用动态Java代码  
  52.         mCtc.addField(CtField.make("public" + IDBQuery.class.getName() + "real;", mCtc));  
  53.         String dbQueryname = DBQuery.class.getName();  
  54.         //添加方法,这里使用动态Java代码指定内部逻辑  
  55.         mCtc.addMethod(CtNewMethod.make("public String request() { if(real==null) real = new " +dbQueryname+"(); return real.request();}", mCtc));  
  56.           
  57.         //基于以上信息,生成动态类  
  58.         Class pc = mCtc.toClass();  
  59.         //生成动态类的实例  
  60.         IDBQuery bytecodeProxy = (IDBQuery) pc.newInstance();  
  61.         return bytecodeProxy;  
  62.     }  
  63.       
  64. }  


      三种动态代理:JDK动态代理创建速度优于CGLIB动态代理,但是在函数的调用性能上远不如CGLIBJavassist。故CGLIB和Javassist整体性能上比JDK动态代理好。

 

性能比较:

 

[html]  view plain  copy
 
  print ?
  1. Create JDK Proxy: 13 ms    
  2. Create CGLIB Proxy: 217 ms    
  3. Create JAVAASSIST Proxy: 99 ms    
  4. Create JAVAASSIST Bytecode Proxy: 168 ms    
  5. ================    
  6. Run JDK Proxy: 2224 ms, 634,022 t/s    
  7. Run CGLIB Proxy: 1123 ms, 1,255,623 t/s    
  8. Run JAVAASSIST Proxy: 3212 ms, 438,999 t/s    
  9. Run JAVAASSIST Bytecode Proxy: 206 ms, 6,844,977 t/s     
  10. ----------------    
  11. Run JDK Proxy: 2169 ms, 650,099 t/s    
  12. Run CGLIB Proxy: 1059 ms, 1,331,506 t/s    
  13. Run JAVAASSIST Proxy: 3328 ms, 423,697 t/s    
  14. Run JAVAASSIST Bytecode Proxy: 202 ms, 6,980,521 t/s     
  15. ----------------    
  16. Run JDK Proxy: 2174 ms, 648,604 t/s    
  17. Run CGLIB Proxy: 1032 ms, 1,366,342 t/s    
  18. Run JAVAASSIST Proxy: 3119 ms, 452,088 t/s    
  19. Run JAVAASSIST Bytecode Proxy: 207 ms, 6,811,910 t/s    
  20. ----------------    

 

 

Javassist字节码最快,CGLIB次之,是JDK的两倍。

      它们都是通过字节码生成来实现动态代理的。只不过是它们生成的字节码不一样,像JDK,CGLIB都考虑了很多因素,以及继承或包装了自己的一些类,所以生成的字节码非常大,而我们很多时候用不上这些,手工生成的字节码非常小(Javassist是手工生成的字节码),所以速度快。

       另外,ASM也是手工生成的字节码,速度也很快,但是它没有一个数量级,通常情况下选用Javassist生成字节码的方式。

 

        另外,从严格意义上将Aspectj不能算动态代理,应该是静态代理,因为它采用的是编译器植入。用aspectj,需要写相应的xml,定义切面,织入点等,然后由aspectj的编译器来编译出新的字节码文件,这明显是静态代理。

 

下面附上jdk proxy内幕

 

Java代码   收藏代码
  1. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  
  2.            throws IllegalArgumentException {  
  3.        //InvocationHandler不能为空,因为对代理对象的所有方法调用实际上都会委托到InvocationHandler的invoke方法,  
  4.        //这个我们后面通过查看产生的代理类的源代码便会一目了然  
  5.        if (h == null) {  
  6.            throw new NullPointerException();  
  7.        }  
  8.   
  9.        //这个是核心的地方,通过提供的ClassLoader和interface列表来产生代理类,具体的实现可以参考getProxyClass这个方法的实现,  
  10.        //真正的工作是由sun.misc.ProxyGenerator这个类来完成的,可以google查看具体的逻辑.在我们的程序中通过设置  
  11.        //System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")可以查看产生的类文件  
  12.        Class cl = getProxyClass(loader, interfaces);  
  13.   
  14.        //因为代理类继承了Proxy类.而Proxy中定义了构造函数protected Proxy(InvocationHandler h),所以可以反射得到Constructer实例  
  15.        //创建代理对象  
  16.        try {  
  17.            Constructor cons = cl.getConstructor(constructorParams);  
  18.            return (Object) cons.newInstance(new Object[] { h });  
  19.        } catch (NoSuchMethodException e) {  
  20.            throw new InternalError(e.toString());  
  21.        } catch (IllegalAccessException e) {  
  22.            throw new InternalError(e.toString());  
  23.        } catch (InstantiationException e) {  
  24.            throw new InternalError(e.toString());  
  25.        } catch (InvocationTargetException e) {  
  26.            throw new InternalError(e.toString());  
  27.        }  
  28.    }  

 

Java代码   收藏代码
  1. public interface Subject {  
  2.     void pub(String key, String content);  
  3.   
  4.     String sub(String key);  
  5. }  
  6.   
  7.   
  8. public class SimpleSubject implements Subject {  
  9.     private Map<String, String> msg = new ConcurrentHashMap<String, String>();  
  10.   
  11.     public void pub(String key, String content) {  
  12.         System.out.println("pub msg: key is " + key + ", content is " + content);  
  13.         msg.put(key, content);  
  14.     }  
  15.   
  16.     public String sub(String key) {  
  17.         if (msg.containsKey(key)) {  
  18.             String ret = msg.get(key);  
  19.             System.out.println("sub msg: key is " + key + ", result is " + ret);  
  20.             return ret;  
  21.         }  
  22.   
  23.         return null;  
  24.     }  
  25.   
  26. }  
  27.   
  28.   
  29. public class SubjectProxyFactory {  
  30.     //TODO: cache   
  31.     public static Subject getSubject(final Subject realSubject) {  
  32.         return (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), new Class[] { Subject.class },  
  33.                 new InvocationHandler() {  
  34.   
  35.                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  36.                         System.out.println("\naction before method invocation....");  
  37.                         Object retVal = method.invoke(realSubject, args);  
  38.                         System.out.println("action after method invocation....\n");  
  39.                         return retVal;  
  40.                     }  
  41.                 });  
  42.     }  
  43. }  
  44.   
  45.   
  46. public class Demo {  
  47.     public static void main(String[] args) {  
  48.         //设置此系统属性,以查看代理类文件  
  49.         System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles""true");  
  50.           
  51.         //创建真实对象  
  52.         Subject subj = new SimpleSubject();  
  53.         subj.pub("name""kevin.fan");  
  54.         subj.sub("name");  
  55.           
  56.         //创建代理对象  
  57.         Subject proxy = SubjectProxyFactory.getSubject(subj);  
  58.         proxy.pub("hobby""r&b music");  
  59.         proxy.sub("name");  
  60.     }  
  61. }  

 

Result代码   收藏代码
  1. pub msg: key is name, content is kevin.fan  
  2. sub msg: key is name, result is kevin.fan  
  3.   
  4. action before method invocation....  
  5. pub msg: key is hobby, content is r&b music  
  6. action after method invocation....  
  7.   
  8. action before method invocation....  
  9. sub msg: key is name, result is kevin.fan  
  10. action after method invocation….  

 

Java代码   收藏代码
  1. //这里很清楚了,代理类继承了Proxy类,并且实现了Proxy.newProxyInstance这个方法中传入的接口  
  2. public final class $Proxy0 extends Proxy  
  3.   implements Subject  
  4. {  
  5.     
  6.   //这些方法在下面的static init block中进行初始化  
  7.   private static Method m4;  
  8.   private static Method m1;  
  9.   private static Method m3;  
  10.   private static Method m0;  
  11.   private static Method m2;  
  12.     
  13.   static  
  14.   {  
  15.     try  
  16.     {  
  17.       m4 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("sub"new Class[] { Class.forName("java.lang.String") });  
  18.       m1 = Class.forName("java.lang.Object").getMethod("equals"new Class[] { Class.forName("java.lang.Object") });  
  19.       m3 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("pub"new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });  
  20.       m0 = Class.forName("java.lang.Object").getMethod("hashCode"new Class[0]);  
  21.       m2 = Class.forName("java.lang.Object").getMethod("toString"new Class[0]);  
  22.       return;  
  23.     }  
  24.     catch (NoSuchMethodException localNoSuchMethodException)  
  25.     {  
  26.       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());  
  27.     }  
  28.     catch (ClassNotFoundException localClassNotFoundException)  
  29.     {  
  30.       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());  
  31.     }  
  32.   }  
  33.   
  34.   //构造函数,接收一个 InvocationHandler作为参数,这就是为什么Proxy.newProxyInstance方法里可以  
  35.   //通过InvocationHandler实例作为参数来反射获取Constructer实例   
  36.   public $Proxy0(paramInvocationHandler)  
  37.     throws   
  38.   {  
  39.     super(paramInvocationHandler);  
  40.   }  
  41.   
  42.   //下面通过这个来看下代理对象中方法是怎样调用的  
  43.   public final String sub(String paramString)  
  44.     throws   
  45.   {  
  46.     try  
  47.     {  
  48.        //全部是通过调用InvocationHandler的invoke方法,传入对应的方法和参数  
  49.       return (String)this.h.invoke(this, m4, new Object[] { paramString });  
  50.     }  
  51.     catch (Error|RuntimeException localError)  
  52.     {  
  53.       throw localError;  
  54.     }  
  55.     catch (Throwable localThrowable)  
  56.     {  
  57.       throw new UndeclaredThrowableException(localThrowable);  
  58.     }  
  59.   }  
  60.   
  61.   public final boolean equals(Object paramObject)  
  62.     throws   
  63.   {  
  64.     try  
  65.     {  
  66.       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();  
  67.     }  
  68.     catch (Error|RuntimeException localError)  
  69.     {  
  70.       throw localError;  
  71.     }  
  72.     catch (Throwable localThrowable)  
  73.     {  
  74.       throw new UndeclaredThrowableException(localThrowable);  
  75.     }  
  76.   }  
  77.   
  78.   public final void pub(String paramString1, String paramString2)  
  79.     throws   
  80.   {  
  81.     try  
  82.     {  
  83.       this.h.invoke(this, m3, new Object[] { paramString1, paramString2 });  
  84.       return;  
  85.     }  
  86.     catch (Error|RuntimeException localError)  
  87.     {  
  88.       throw localError;  
  89.     }  
  90.     catch (Throwable localThrowable)  
  91.     {  
  92.       throw new UndeclaredThrowableException(localThrowable);  
  93.     }  
  94.   }  
  95.   
  96.   public final int hashCode()  
  97.     throws   
  98.   {  
  99.     try  
  100.     {  
  101.       return ((Integer)this.h.invoke(this, m0, null)).intValue();  
  102.     }  
  103.     catch (Error|RuntimeException localError)  
  104.     {  
  105.       throw localError;  
  106.     }  
  107.     catch (Throwable localThrowable)  
  108.     {  
  109.       throw new UndeclaredThrowableException(localThrowable);  
  110.     }  
  111.   }  
  112.   
  113.   public final String toString()  
  114.     throws   
  115.   {  
  116.     try  
  117.     {  
  118.       return (String)this.h.invoke(this, m2, null);  
  119.     }  
  120.     catch (Error|RuntimeException localError)  
  121.     {  
  122.       throw localError;  
  123.     }  
  124.     catch (Throwable localThrowable)  
  125.     {  
  126.       throw new UndeclaredThrowableException(localThrowable);  
  127.     }  
  128.   }  
  129.   
  130. }  

 

Spring AOP里最重要的两个概念是增强(Advice)和切面(Advisor),增强是织入到目标类连接点上的一段程序代码,切面决定要给什么类的什么方法实施增强。是怎么做到对特定方法实施增强的呢?对invoke方法中的method#name进行判断。

Java代码   收藏代码
  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  2.                         System.out.println("\naction before method invocation....");  
  3.                         Object retVal = method.invoke(realSubject, args);  
  4.                         System.out.println("action after method invocation....\n");  
  5.                         return retVal;  
  6.                     }  

    Spring提供了ProxyFactoryBean创建代理,及利用BeanPostProcessor实现自动创建代理。

 

    Spring是在运行期利用JDK或CGLib创建代理,我们还可以在类加载期间通过字节码编辑的技术,将切面织入到目标类中,这种织入方式称为LTW(Load Time Weaving)。Spring为LTW的过程提供了细粒度的控制,它支持在单个ClassLoader范围内实施类文件转换,且配置更为简单。

 

附小知识:

Ref ref = new RefImpl(); 
System.out.println(ref.getClass().getSimpleName()); //RefImpl类型 
ref.f(); //调用接口方法 
// ref.g(); //向上转型后实现类添加的方法不能调用 
if(ref instanceof RefImpl){ 
RefImpl ref1 = (RefImpl)ref; //类型识别后转型 
ref1.g("zhouyang"); 
// ref1.w(); //私有方法不能访问 



原文链接:[http://wely.iteye.com/blog/2277881]

相关文章
|
4月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
1月前
|
安全 Java 开发者
AOP中的JDK动态代理与CGLIB动态代理:深度解析与实战模拟
【11月更文挑战第21天】面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它通过将横切关注点(cross-cutting concerns)与业务逻辑分离,以提高代码的可维护性和可重用性。在Java开发中,AOP的实现离不开动态代理技术,其中JDK动态代理和CGLIB动态代理是两种常用的方式。本文将从背景、历史、功能点、业务场景、底层逻辑等多个维度,深度解析这两种代理方式的区别,并通过Java示例进行模拟和比较。
54 4
|
2月前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
36 0
[Java]静态代理与动态代理(基于JDK1.8)
|
2月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
26 1
|
4月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
299 0
|
4月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
207 0
|
7月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
354 2
|
2月前
|
存储 Oracle 关系型数据库
数据库数据恢复—Oracle ASM磁盘组故障数据恢复案例
Oracle数据库数据恢复环境&故障: Oracle ASM磁盘组由4块磁盘组成。Oracle ASM磁盘组掉线 ,ASM实例不能mount。 Oracle数据库故障分析&恢复方案: 数据库数据恢复工程师对组成ASM磁盘组的磁盘进行分析。对ASM元数据进行分析发现ASM存储元数据损坏,导致磁盘组无法挂载。
|
7月前
|
存储 Oracle 关系型数据库
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
oracle数据库ASM磁盘组掉线,ASM实例不能挂载。数据库管理员尝试修复数据库,但是没有成功。
【数据库数据恢复】Oracle数据库ASM磁盘组掉线的数据恢复案例
|
SQL Oracle 关系型数据库
Oracle ASM磁盘和磁盘组的常用SQL语句
Oracle ASM磁盘和磁盘组的常用SQL语句
289 0