JDK与CGlib动态代理(实例说明JDK动态代理执行过程)

 1.什么是动态代理


所谓代理模式,就是指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。这种模式有什么用呢?它可以在原对象的基础上增强原对象的功能,比如在原对象调用一个方法的前后进行日志、事务操作等。Spring AOP就使用了代理模式。
而动态代理模式就是指在程序运行期间根据需要动态地创建代理类及其实例来完成具体的功能。动态代理主要分为JDK动态代理和CGlib动态代理两大类,本文主要对JDK动态代理进行探讨。
 

2.JDK动态代理实例


建立项目如下:
 1.ICalculatorService接口源码:

public interface ICalculatorService {

	int add(int a,int b);
	
	int sub(int a,int b);
	
	int mul(int a,int b);
	
	int div(int a,int b);
}

2.CalculatorService实现类源码:

public class CalculatorService implements ICalculatorService {

	@Override
	public int add(int a, int b) {
		int result = a+b;
		return result;
	}

	@Override
	public int sub(int a, int b) {
		int result = a-b;
		return result;
	}

	@Override
	public int mul(int a, int b) {
		int result = a*b;
		return result;
	}

	@Override
	public int div(int a, int b) {
		int result = a/b;
		return result;
	}
}

3.ProxyFactory动态代理类源码:

public class ProxyFactory {//动态(程序运行时实现和目标类相同接口的java类)代理()

	public static Object get(CalculatorService calculatorService) {
		return Proxy.newProxyInstance(calculatorService.getClass().getClassLoader(), new Class[] {ICalculatorService.class}, new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通过重写InvocationHandler()类中的invoke方法,来设定动态代理类需要在被代理类的基础上添加哪些功能
				System.out.println(method.getDeclaringClass().getName());
				String name = method.getName();
				System.out.println(calculatorService.getClass().getName()+":The "+name+" method begins.");
				System.out.println(calculatorService.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
				Object result = method.invoke(calculatorService, args);//被代理类的目标方法
                //这里虽然calculatorService是接口的实现类,但其实是多态,呈现的是被代理类中的方法
				System.out.println(calculatorService.getClass().getName()+":Result of the "+name+" method:"+result);
				System.out.println(calculatorService.getClass().getName()+":The "+name+" method ends.");
				return result;
			}
		});//产生一个动态class类,
	}

4.Test测试类源码:

public static void main(String[] args) {
	System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    //生成动态类的编译文件,以便进行进一步分析
	ICalculatorService calculatorService = (ICalculatorService) new ProxyFactory().get(new CalculatorService());//获取代理对象
	int result = calculatorService.add(1, 1);//调用代理对象进行测试
	System.out.println("-->"+result);
}

我们由main方法一步步分析:

第一行:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

这一行其实是生成了一个动态类的编译文件,我们可以在com.sun.proxy文件夹中找到,对其进行反编译后得到了动态类的实例化对象(由于main方法中只讨论了add方法,为方便理解,在此将实例化对象中的其他部分删去):

import com.jd.calculator.ICalculatorService;
import java.lang.reflect.*;

public final class $Proxy0 extends Proxy
    implements ICalculatorService
{

    public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }

    

    public final int add(int i, int j)
    {
        try
        {
            return ((Integer)super.h.invoke(this, m3, new Object[] {
                Integer.valueOf(i), Integer.valueOf(j)
            })).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    
    private static Method m3;
   

    static 
    {
        try
        {
            
            m3 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("add", new Class[] {
                Integer.TYPE, Integer.TYPE
            });
           
        catch(NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch(ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

第二行:(同时也是最重要的一行)

ICalculatorService calculatorService = (ICalculatorService) new ProxyFactory().get(new CalculatorService());

这一行调用了ProxyFactory()中的get方法,其实就是由Proxy的newProxyInstance方法获得了动态代理类。

接下来进入Proxy中的newProxyInstance方法进行进一步分析:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

其实这么多代码中只有这几行是对我们理解起来有帮助的:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});

 

 分别为: 

  • 第一行告诉了我们这个方法的三个参数。

1.指定类的类加载器(这里我们其实使用了ProxyFactory的类加载器,事实上用什么无所谓)

2.代理类需要实现的接口(这里我们传入了被代理类实现的接口,这样生成的代理类和被代理类就实现了相同的接口)(注:代理类和被代理类实现的接口必须相同)

3.invocation handler,用来处理方法的调用。这里传入我们自己实现的handler,即ProxyFactory中的那个内部类

  • 第二行意味着创建了一个动态代理类
  • 第三行意味着得到了代理类对象的构造方法,这个构造方法的参数由constructorParams指定,而参数constructorParames为常量值:private static final Class<?>[] constructorParams = { InvocationHandler.class }
  • 第四行意味着通过刚才获得的构造方法创建了一个代理类的对象,这里的参数就使用了我们自己实现的handler

调用了构造方法,就意味着使用了刚才我们的得到的代理类对象的构造方法:

public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }

佐证了构造方法是使用我们自己实现的handler作为参数的这一事实。

接下来回到main方法看第三行:

int result = calculatorService.add(1, 1);

这里调用了刚刚创建的代理类对象,观察相关源码:

public final int add(int i, int j)
    {
        try
        {
            return ((Integer)super.h.invoke(this, m3, new Object[] {
                Integer.valueOf(i), Integer.valueOf(j)
            })).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    
    private static Method m3;
   

    static 
    {
        try
        {
            
            m3 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("add", new Class[] {
                Integer.TYPE, Integer.TYPE
            });
//try后面的部分于理解意义不大,故略去

 return ((Integer)super.h.invoke(this, m3, new Object[] {
                Integer.valueOf(i), Integer.valueOf(j)
            })).intValue();

知道这里其实调用了我们定义的handler的invoke方法。三个对象分别是这个实现类对象自己,m3对应的被代理类的方法以及计算所需参数。其中的Integer和.intValue()等都是数据类型转换相关内容,于理解并无影响。

因此最后可以获得结果:

 3.CGlib动态代理

CGlib的动态代理方法如下:(接口与被代理类与上例相同)

public class Test {
	
	private static Callback callback = new MethodInterceptor() {
		@Override
		public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
			String name = method.getName();
			System.out.println(obj.getClass().getName()+":The "+name+" method begins.");
			System.out.println(obj.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
			Object result = proxy.invokeSuper(obj, args);//目标方法
			System.out.println(obj.getClass().getName()+":Result of the "+name+" method:"+result);
			System.out.println(obj.getClass().getName()+":The "+name+" method ends.");
			return result;
		}
	};
	
	private static Object get() {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(CalculatorService.class);
		enhancer.setCallback(callback);
		return enhancer.create();//创建动态类对象
	}
	
	
	public static void main(String[] args) {
		ICalculatorService calculatorService = (ICalculatorService)get();//获取代理对象
		int result = calculatorService.add(1, 1);
		System.out.println("-->"+result);
	}
}

4.JDK动态代理与CGlib动态代理的区别

1.JDK动态代理基于接口实现,所以实现JDK动态代理,必须先定义接口;CGLib动态代理基于类实现;
2.JDK动态代理机制是委托机制,委托hanlder调用原始实现类方法,被代理类和代理类是兄弟关系;CGLib则使用继承机制,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值