栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java动态代理

1 静态代理

1)接口

public interface person{
  void eat();
}

2)被代理类

public class child implements person{
	 void eat(){
	 	System.out.println("小孩吃饭");
	 }
}

3)代理类

public class proxyChild implements person{
	private child c1;
	public proxyChild (child  c1){
		this.c1 = c1;
	}
	void eat(){
		before();
	 	c1.eat();//child的eat函数
	 	after();
	 }
	 void before(){
	 	System.out.println("小孩吃饭前");
	 }
	  void after(){
	 	System.out.println("小孩吃饭后");
	 }
}

缺点:每个代理类只能代理一个类。

2 动态代理 2.1 JDK实现

      利用字节码重组技术,获取传入的被代理对象实现的接口interfaces,增强被代理对象功能的InvocationHandler,来动态生成新的代理类。

2.1.1 InvocationHandler
public class ProxyHandler implements InvocationHandler{
    private Object object;
    public ProxyHandler(Object object){
        this.object = object;
    }
    @Override
    //被代理类调用的函数最终会利用该函数来执行
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //增强逻辑
        System.out.println("Before invoke "  + method.getName());
         //原始child的eat函数
        method.invoke(object, args);
         //增强逻辑
        System.out.println("After invoke " + method.getName());
        return null;
        //可以根据method的名字来进行不同的增强逻辑
        //if("eat".equals(method.getName())){
          //System.out.println("增强1");
          //Object invoke = method.invoke(obj, args);
          //System.out.println("增强1");
      //}else{
       	  //System.out.println("增强2");
          //Object invoke = method.invoke(obj, args);
          //System.out.println("增强2");
      //}
    }
}
2.1.2 动态代理类
class DynamicProxy  {
   public static Object getInatance(Object obj) {
       Class[] interfaces = obj.getClass().getInterfaces();
       Object o = Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new myInvocationHandler(obj));
       //o就是返回的动态生成的代理类
       return o;
   }
}
2.1.3 调用
public class JDKProxy  {
    public static void main(String[] args) {
        UserService userService = (UserService) DynamicProxy.getInatance(new UserServiceImpl());
        userService.login(10);
        //会调用ProxyHandler里面的invoke方法
        userService.register(20);
    }
}
2.1.4 原理

1)动态生成对象

Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new myInvocationHandler(obj));
根据传入的类加载器,被代理类的所有接口,增强功能的类;利用字节码重组生成动态代理类

2)Proxy0:动态代理类。 简单示例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy implements person{
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);----------**传来的增强句柄**
    }
    
===========================代理类的调用函数=============================
    public final void eat() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
            //  super.h 就是传来的增强句柄
            // 增强句柄中的invoke中加上了增强逻辑的child的eat函数
            //由此可知,通过代理类来调用被代理类的函数,最终会调用InvocationHandler中的invoke函数来执行
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
=====================================================================

    
     public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("person").getMethod("eat", Class.forName("java.lang.String"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

2.2 CGlib的动态代理

      通过“继承”可以继承父类所有的公开方法,然后可以重写这些方法,在重写时对这些方法增强,这就是cglib的思想。

2.2.1 执行流程

1)被代理类

package com.jpeony.spring.proxy.cglib;
 
public class HelloService {
 
    public HelloService() {
        System.out.println("HelloService构造");
    }
 
    
    final public String sayOthers(String name) {
        System.out.println("HelloService:sayOthers>>"+name);
        return null;
    }
 
    public void sayHello() {
        System.out.println("HelloService:sayHello");
    }
}

2)方法拦截器:MethodInterceptor,代理类执行方法会执行这个方法,类似JDK中的InvocationHandler,不同的是JDK中的invoke利用反射机制调用被代理类的方法,而CGlib则是利用代理类继承的被代理类的方法来调用的(其中还利用fastClass机制,为每个方法分一个index,将index作为入参执行fastClass中的invoke方法),所以执行速度比较快。

package com.jpeony.spring.proxy.cglib;
 
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
import java.lang.reflect.Method;
 

public class MyMethodInterceptor implements MethodInterceptor{
 
    
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        //invokeSuper是调用父类的方法(被代理类)
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }
    
    public Object getInstance(Class clazz) throws Exception{
    //利用ASM框架生成代理类
		Enhance enhance = new Enhance();
		//传入被代理类
		enhance.setSuperclass(clazz);
		enhance.setCallback(this);
		return enhance.creat();
}
}
2.2.2 调用过程

1)代理类执行sayHello方法
2)调用方法拦截器的intercept(before–invokeSuper–after)
3)invokeSuper调用CGLIB$sayHello$0,该方法再调用被代理类的sayHello
invokeSuper通过调用被代理类的FastClass中的invoke方法来运行对应的方法的

2.2.3 fastClass机制

      CGlib通过继承被代理类生成代理类Class,此外还有另外两个文件,就是为代理类和被代理类生成的FastClass(不是和生成代理类时生成的,而是再第一次调用invoke或者invokeSuper时生成的缓存)。
1)被代理类的FastClass部分代码如下

public class HelloService$$FastClassByCGLIB$$8656ab6f extends FastClass {
    public HelloService$$FastClassByCGLIB$$8656ab6f(Class var1) {
        super(var1);
    }
=====================================================================
//getIndex方法会为代理类和被代理类的方法分类index,这样每个index会对应到具体方法,在调用时就可以快速找到对应方法
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -1488716497:
            if (var10000.equals("sayOthers(Ljava/lang/String;)Ljava/lang/String;")) {
                return 1;
            }
            break;
        }

        return -1;
    }
=====================================================================
//invokeSuper那里,实际上就是用fastClass对象调用的invoke方法,查找是case n,运行相应的方法
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        HelloService var10000 = (HelloService)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
=====================================================================            
                var10000.sayHello();
=====================================================================
                return null;
            case 1:
                return var10000.sayOthers((String)var3[0]);
            case 2:
                return new Boolean(var10000.equals(var3[0]));
            case 3:
                return var10000.toString();
            case 4:
                return new Integer(var10000.hashCode());
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }
    }
}
2.3 两者对比
  • JDK动态代理是实现了被代理对象的接口,CGlib是继承了被代理对象。
  • 两者都在运行期间生成字节码,JDK方式直接写Class字节码文件,CGlib则是通过ASM框架来写Class,实现更复杂,生成代理类的效率低
  • JDK方式是通过InvocationHandler中的invoke方法,而该方法再通过反射调用被代理类的方法;CGlib则通过FastClass机制来调用方法,故方法调用效率更高。

cglib生成代理类慢,方法执行速度略大于jdk,所以比较适合单例模式。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/572697.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号