“动态代理、CGLIB 与 切面编程”的版本间差异

来自Wikioe
跳到导航 跳到搜索
第17行: 第17行:
== Java动态代理 ==
== Java动态代理 ==
* 参见:'''[http://wiki.eijux.com/%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%EF%BC%9A%E6%8E%A5%E5%8F%A3%E3%80%81lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%86%85%E9%83%A8%E7%B1%BB#.E5.86.85.E9.83.A8.E7.B1.BB JavaCore:接口(代理)]'''
* 参见:'''[http://wiki.eijux.com/%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%EF%BC%9A%E6%8E%A5%E5%8F%A3%E3%80%81lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%86%85%E9%83%A8%E7%B1%BB#.E5.86.85.E9.83.A8.E7.B1.BB JavaCore:接口(代理)]'''
=== invoke方法的自动调用 ===
Java中动态代理的实现,关键在于:“Proxy”、“InvocationHandler”的关联;<br/>
以实例分析:
# 抽象接口:
#: <syntaxhighlight lang="java" line highlight="">
//抽象角色(动态代理只能代理接口) 
public interface Subject { 
    public void request(); 
}
</syntaxhighlight>
# 抽象接口实现:
#: <syntaxhighlight lang="java" line highlight="">
//真实角色:实现了Subject的request()方法 
public class RealSubject implements Subject{ 
    public void request(){ 
        System.out.println("From real subject."); 
    } 
}
</syntaxhighlight>
# “InvocationHandler”接口的实现类:
#: <syntaxhighlight lang="java" line highlight="20">
//实现了InvocationHandler 
public class DynamicSubject implements InvocationHandler 
    private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象 
 
    public DynamicSubject() 
    { 
    } 
 
    public DynamicSubject(Object obj) 
    { 
        this.obj = obj; 
    } 
 
    //这个方法不是我们显示的去调用 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
    { 
        System.out.println("before calling " + method); 
 
        method.invoke(obj, args); 
 
        System.out.println("after calling " + method); 
 
        return null; 
    }
}
</syntaxhighlight>
#* “invoke”方法进行代理处理逻辑,并调用对应的接口方法;
#* 使用“method.invoke(obj, args);”,而'''不能使用“method.invoke(proxy, args); ”'''(后者将会导致死循环);
#** “obj”:类型为“RealSubject”(由下面测试类中,初始化“DynamicSubject”的参数而来):
#** “proxy”:就是代理实例“$Proxy0”:
#**:“method.invoke(proxy, args);”将会调用“$Proxy0”的method方法;
#**: 而“$Proxy0”的method方法,会执行“super.h.invoke(this, m3, null);”,即调用此处,从而调用陷入死循环;
# 测试类:
#: <syntaxhighlight lang="java" line highlight="5,6,34">
//客户端:生成代理实例,并调用了request()方法 
public class Client {
    public static void main(String[] args) throws Throwable{ 
 
        Subject rs = new RealSubject();//这里指定被代理类 
        InvocationHandler ds = new DynamicSubject(rs); 
        Class<?> cls = rs.getClass(); 
         
        //以下是一次性生成代理 
        Subject subject=(Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), ds); 
         
        //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口 
        System.out.println("subject的Class类是:"+subject.getClass().toString()); 
        System.out.println("subject的父类是:"+subject.getClass().getSuperclass()); 
        System.out.print("\n"+"subject实现的接口是:"); 
        Class<?>[] interfaces=subject.getClass().getInterfaces(); 
        for(Class<?> i:interfaces){ 
            System.out.print(i.getName()+", "); 
        } 
         
        System.out.print("\n"+"subject中的属性有:"); 
        Field[] field=subject.getClass().getDeclaredFields(); 
        for(Field f:field){ 
            System.out.print(f.getName()+", "); 
        } 
         
        System.out.print("\n"+"subject中的方法有:"); 
        Method[] method=subject.getClass().getDeclaredMethods(); 
        for(Method m:method){ 
            System.out.print(m.getName()+", "); 
        } 
       
        System.out.println("\n\n"+"运行结果为:");
        subject.request();
    }
}
</syntaxhighlight>
#: 运行结果如下:
#: <syntaxhighlight lang="java" line highlight="">
subject的Class类是:class com.sun.proxy.$Proxy0
subject的父类是:class java.lang.reflect.Proxy
subject实现的接口是:Test1.Subject,
subject中的属性有:m1, m2, m3, m0,
subject中的方法有:equals, toString, hashCode, request,
运行结果为:
before calling public abstract void Test1.Subject.request()
From real subject.
after calling public abstract void Test1.Subject.request()
</syntaxhighlight>
#* 如果初始化“DynamicSubject”时,传入参数不是“RealSubject”类型,则,DynamicSubject中的“method.invoke(obj, args); ”将不能执行:
#*: 错误信息:“'''object is not an instance of declaring class'''”
* “Proxy”的部分源码:
#: <syntaxhighlight lang="java" line highlight="">
class Proxy{ 
    InvocationHandler h=null; 
    protected Proxy(InvocationHandler h) { 
        this.h = h; 
    } 
    ... 
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
}
</syntaxhighlight>
#* Proxy 会生成一个“'''由loader加载'''”、“'''继承于Proxy'''”、“'''实现了interfaces等接口'''”的代理类“$Proxy0”;
#* Proxy 会将'''“InvocationHandler”实例保存在属性'''中;
#*
* 生成的“$Proxy0”:
*: <syntaxhighlight lang="java" line highlight="9,12,15,18,35,44,52,63">
public final class $Proxy0 extends Proxy implements Subject { 
    private static Method m1; 
    private static Method m0; 
    private static Method m3; 
    private static Method m2; 
 
    static { 
        try { 
            m1 = Class.forName("java.lang.Object").getMethod("equals", 
                    new Class[] { Class.forName("java.lang.Object") }); 
 
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", 
                    new Class[0]); 
 
            m3 = Class.forName("***.RealSubject").getMethod("request", 
                    new Class[0]); 
 
            m2 = Class.forName("java.lang.Object").getMethod("toString", 
                    new Class[0]); 
 
        } catch (NoSuchMethodException nosuchmethodexception) { 
            throw new NoSuchMethodError(nosuchmethodexception.getMessage()); 
        } catch (ClassNotFoundException classnotfoundexception) { 
            throw new NoClassDefFoundError(classnotfoundexception.getMessage()); 
        } 
    } //static 
 
    public $Proxy0(InvocationHandler invocationhandler) { 
        super(invocationhandler); 
    } 
 
    @Override 
    public final boolean equals(Object obj) { 
        try { 
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue(); 
        } catch (Throwable throwable) { 
            throw new UndeclaredThrowableException(throwable); 
        } 
    } 
 
    @Override 
    public final int hashCode() { 
        try { 
            return ((Integer) super.h.invoke(this, m0, null)).intValue(); 
        } catch (Throwable throwable) { 
            throw new UndeclaredThrowableException(throwable); 
        } 
    } 
 
    public final void request() { 
        try { 
            super.h.invoke(this, m3, null); 
            return; 
        } catch (Error e) { 
        } catch (Throwable throwable) { 
            throw new UndeclaredThrowableException(throwable); 
        } 
    } 
 
    @Override 
    public final String toString() { 
        try { 
            return (String) super.h.invoke(this, m2, null); 
        } catch (Throwable throwable) { 
            throw new UndeclaredThrowableException(throwable); 
        } 
    } 
</syntaxhighlight>
** 其中“m1”、“m0”、“m3”、“m2”是“Method”类型的字段,表示“$Proxy0”中方法所'''对应的原方法''';包括:
**# 继承于“Object”的“equals”(m1)、“hashCode”(m0)、“toString”(m2)
**# 实现“Subject”的“request”(m3);
** “$Proxy0”的方法实现:“'''super.h.invoke(this, m3, null);'''”:
**# 调用父类的“h”(“InvocationHandler”实例)的“invoke”方法;(“invoke”中进行代理处置,并调用原始方法)
**# 参数:“this”($Proxy0)、“m2”(原始方法)、“null”(方法参数)


== AspectJ ==
== AspectJ ==

2020年10月29日 (四) 04:48的版本


关于代理

代理,简单说就是:不直接操作对象,而使用代理对象来完成操作;

  • 通过代理对象,可以对原对象进行方法扩展;


代理又可以分为

  1. 静态代理:通过聚合、继承的方式生成代理对象;
    • 代理关系在编译时就确定了
  2. 动态代理:
    • 运行期动态生成代理对象;
    1. Java动态代理:(针对实现了接口的类)
    2. CGLIB:(针对没有实现接口的类)
    3. AspectJ:(springframework的aop基于此实现)

Java动态代理

invoke方法的自动调用

Java中动态代理的实现,关键在于:“Proxy”、“InvocationHandler”的关联;


以实例分析:

  1. 抽象接口:
    //抽象角色(动态代理只能代理接口)  
    public interface Subject {  
        public void request();  
    }
    
  2. 抽象接口实现:
    //真实角色:实现了Subject的request()方法  
    public class RealSubject implements Subject{  
        public void request(){  
            System.out.println("From real subject.");  
        }  
    }
    
  3. “InvocationHandler”接口的实现类:
    //实现了InvocationHandler  
    public class DynamicSubject implements InvocationHandler  
    {  
        private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象  
      
        public DynamicSubject()  
        {  
        }  
      
        public DynamicSubject(Object obj)  
        {  
            this.obj = obj;  
        }  
      
        //这个方法不是我们显示的去调用  
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
        {  
            System.out.println("before calling " + method);  
      
            method.invoke(obj, args);  
      
            System.out.println("after calling " + method);  
      
            return null;  
        }
    }
    
    • “invoke”方法进行代理处理逻辑,并调用对应的接口方法;
    • 使用“method.invoke(obj, args);”,而不能使用“method.invoke(proxy, args); ”(后者将会导致死循环);
      • “obj”:类型为“RealSubject”(由下面测试类中,初始化“DynamicSubject”的参数而来):
      • “proxy”:就是代理实例“$Proxy0”:
        “method.invoke(proxy, args);”将会调用“$Proxy0”的method方法;
        而“$Proxy0”的method方法,会执行“super.h.invoke(this, m3, null);”,即调用此处,从而调用陷入死循环;
  4. 测试类:
    //客户端:生成代理实例,并调用了request()方法  
    public class Client {
        public static void main(String[] args) throws Throwable{  
      
            Subject rs = new RealSubject();//这里指定被代理类  
            InvocationHandler ds = new DynamicSubject(rs);  
            Class<?> cls = rs.getClass();  
              
            //以下是一次性生成代理  
            Subject subject=(Subject) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), ds);  
              
            //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口  
            System.out.println("subject的Class类是:"+subject.getClass().toString());  
            System.out.println("subject的父类是:"+subject.getClass().getSuperclass());  
            System.out.print("\n"+"subject实现的接口是:");  
            Class<?>[] interfaces=subject.getClass().getInterfaces();  
            for(Class<?> i:interfaces){  
                System.out.print(i.getName()+", ");  
            }  
              
            System.out.print("\n"+"subject中的属性有:");  
            Field[] field=subject.getClass().getDeclaredFields();  
            for(Field f:field){  
                System.out.print(f.getName()+", ");  
            }  
              
            System.out.print("\n"+"subject中的方法有:");  
            Method[] method=subject.getClass().getDeclaredMethods();  
            for(Method m:method){  
                System.out.print(m.getName()+", ");  
            }  
            
            System.out.println("\n\n"+"运行结果为:");
            subject.request();
        } 
    }
    
    运行结果如下:
    subject的Class类是class com.sun.proxy.$Proxy0
    subject的父类是class java.lang.reflect.Proxy
    
    subject实现的接口是Test1.Subject, 
    subject中的属性有m1, m2, m3, m0, 
    subject中的方法有equals, toString, hashCode, request, 
    
    运行结果为
    before calling public abstract void Test1.Subject.request()
    From real subject.
    after calling public abstract void Test1.Subject.request()
    
    • 如果初始化“DynamicSubject”时,传入参数不是“RealSubject”类型,则,DynamicSubject中的“method.invoke(obj, args); ”将不能执行:
      错误信息:“object is not an instance of declaring class


  • “Proxy”的部分源码:
  1. class Proxy{  
        InvocationHandler h=null;  
        protected Proxy(InvocationHandler h) {  
            this.h = h;  
        }  
        ...  
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    }
    
    • Proxy 会生成一个“由loader加载”、“继承于Proxy”、“实现了interfaces等接口”的代理类“$Proxy0”;
    • Proxy 会将“InvocationHandler”实例保存在属性中;
  • 生成的“$Proxy0”:
    public final class $Proxy0 extends Proxy implements Subject {  
        private static Method m1;  
        private static Method m0;  
        private static Method m3;  
        private static Method m2;  
      
        static {  
            try {  
                m1 = Class.forName("java.lang.Object").getMethod("equals",  
                        new Class[] { Class.forName("java.lang.Object") });  
      
                m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                        new Class[0]);  
      
                m3 = Class.forName("***.RealSubject").getMethod("request",  
                        new Class[0]);  
      
                m2 = Class.forName("java.lang.Object").getMethod("toString",  
                        new Class[0]);  
      
            } catch (NoSuchMethodException nosuchmethodexception) {  
                throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
            } catch (ClassNotFoundException classnotfoundexception) {  
                throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
            }  
        } //static  
      
        public $Proxy0(InvocationHandler invocationhandler) {  
            super(invocationhandler);  
        }  
      
        @Override  
        public final boolean equals(Object obj) {  
            try {  
                return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
      
        @Override  
        public final int hashCode() {  
            try {  
                return ((Integer) super.h.invoke(this, m0, null)).intValue();  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
      
        public final void request() {  
            try {  
                super.h.invoke(this, m3, null);  
                return;  
            } catch (Error e) {  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
      
        @Override  
        public final String toString() {  
            try {  
                return (String) super.h.invoke(this, m2, null);  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
    }
    
    • 其中“m1”、“m0”、“m3”、“m2”是“Method”类型的字段,表示“$Proxy0”中方法所对应的原方法;包括:
      1. 继承于“Object”的“equals”(m1)、“hashCode”(m0)、“toString”(m2)
      2. 实现“Subject”的“request”(m3);
    • “$Proxy0”的方法实现:“super.h.invoke(this, m3, null);”:
      1. 调用父类的“h”(“InvocationHandler”实例)的“invoke”方法;(“invoke”中进行代理处置,并调用原始方法)
      2. 参数:“this”($Proxy0)、“m2”(原始方法)、“null”(方法参数)

AspectJ

CGLIB

CGLIB是一个功能强大,高性能的代码生成包。

  • 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制
  • CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。

原理

  1. 动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。
  2. 在子类中采用方法拦截的技术,拦截所有父类方法的调用,并织入横切逻辑。
  • 为没有实现接口的类提供代理,比于JDK动态代理(只能代理接口)更加强大;
  • 不能代理final方法;

CGLIB组成结构

CGLIB组成结构.png

CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。

  • 因为使用字节码技术生成代理类,所以CGLIB比java反射的JDK动态代理更快;
  • 关于“ASM”:
    • 除了CGLIB库外,脚本语言(如:“Groovy”、“BeanShell”)也使用ASM生成字节码;
    • ASM使用类似SAX的解析器来实现高性能;
    • (如果直接使用ASM,需要对Java字节码非常了解)

jar包

  • “cglib-nodep-2.2.jar”:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类.
  • “cglib-2.2.jar”:使用此jar包需要关联asm的jar包,否则运行时报错.

类库

CGLIB类库:

  • “net.sf.cglib.core”:底层字节码处理类,他们大部分与ASM有关系;
  • “net.sf.cglib.transform”:编译期或运行期类和类文件的转换;
  • “net.sf.cglib.proxy”:实现创建代理和方法拦截器的类;
  • “net.sf.cglib.reflect”:实现快速反射和C#风格代理的类;
  • “net.sf.cglib.util”:集合排序等工具类;
  • “net.sf.cglib.beans”:JavaBean相关的工具类;

常用的API

命令 说明 示例
Enhancer Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)
  • 作用类似Proxy类;但Enhancer既能够代理普通的class,也能够代理接口;(不能代理final方法)
  1. Enhancer.setSuperclass():设置父类型;
  2. Enhancer.create(Object…):创建增强对象;
  3. Enhancer.createClass():创建字节码(.class);
  4. setCallback():设置回调;
    • “InvocationHandler”可以作为回调,但必须防止死循环
      (invoke中调用的任何原代理类方法,均会重新代理到invoke方法中)
    • “MethodInterceptor”可以作为回调,且不会出现死循环


public class SampleClass {
    public void test(){
        System.out.println("hello world");
    }

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SampleClass.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("before method run...");
                Object result = proxy.invokeSuper(obj, args);
                System.out.println("after method run...");
                return result;
            }
        });
        SampleClass sample = (SampleClass) enhancer.create();
        sample.test();
    }
}

输出:

before method run...
hello world
after method run...


使用

  1. public class TargetObject {
        public String method1(String paramName) {
            return paramName;
        }
     
        public int method2(int count) {
            return count;
        }
     
        public int method3(int count) {
            return count;
        }
     
        @Override
        public String toString() {
            return "TargetObject []"+ getClass();
        }
    }