静态代理&动态代理

时间:2022-02-09 15:41:21

 

代理设计在Java开发中使用较多的一种设计模式,所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。

先来看看静态代理

1 package com.proxy.inter;
2 
3 /**
4  * 定义Demo接口
5  */
6 public interface Demo {
7     public void save();
8 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.Demo;
 4 
 5 /**
 6  * DemoImpl实现Demo接口并覆写save()方法
 7  * 真实主题,执行具体业务
 8  */
 9 public class DemoImpl implements Demo {
10     public void save() {
11         System.out.println("调用save()方法");
12     }
13 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.Demo;
 4 /**
 5  * DemoImplProxy 也实现了Demo接口,并覆写了save()方法,增加了自己的业务 
 6  * 代理主题,负责其他业务的处理
 7  */
 8 public class DemoImplProxy implements Demo {
 9     Demo demoImpl = new DemoImpl();
10     
11     public void save() {
12         System.out.println("开始记录日志");
13         demoImpl.save();
14         System.out.println("开始结束日志");
15     }
16 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.Demo;
 4 
 5 /**
 6  * 开始记录日志
 7  * 调用save()方法
 8  * 开始结束日志
 9  */
10 public class Test {
11     public static void main(String[] args) {
12         Demo demoImplProxy = new DemoImplProxy();
13         
14         demoImplProxy.save();
15     }
16 }

你会发现每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类

所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类的支持

java.lang.reflect.InvocationHandler接口的定义如下:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

Object proxy:被代理的对象

Method method:要调用的方法

Object[] args:方法调用时所需要参数

java.lang.reflect.Proxy类的定义如下:

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

CLassLoader loader:类的加载器

Class<?> interfaces:得到全部的接口

InvocationHandler h:得到InvocationHandler接口的子类的实例

下面来看看动态代理的具体实现

1 package com.proxy.inter;
2 
3 /**
4  * 定义DemoFirst接口
5  */
6 public interface DemoFirst {
7     public void saveFirst();
8 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.DemoFirst;
 4 
 5 /**
 6  * DemoFirstImpl实现DemoFirst接口,覆写saveFirst()方法
 7  * 真实主题,负责执行具体业务 
 8  */
 9 public class DemoFirstImpl implements DemoFirst {
10 
11     @Override
12     public void saveFirst() {
13         System.out.println("调用saveFirst()方法");
14     }
15 
16 }
 1 package com.proxy.impl;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * InvocationHandlerImple实现InvocationHandler接口,覆写invoke()方法
 8  * 代理主题的业务写在invoke()方法中
 9  */
10 public class InvocationHandlerImpl implements InvocationHandler {
11 
12     private Object target;
13     
14     public InvocationHandlerImpl(Object target) {
15         this.target = target;
16     }
17     
18     @Override
19     public Object invoke(Object proxy, Method method, Object[] args)
20             throws Throwable {
21         System.out.println("target : " + target.getClass().getName());
22         System.out.println("proxy : " + proxy.getClass().getName());
23         System.out.println("method : " + method.getName());
24         System.out.println("args : " + args);
25         System.out.println("开始记录日志");
26         Object obj = method.invoke(target, args);
27         System.out.println("结束记录日志");
28         /*    
29          * System.out.println("obj : " + obj.getClass().getName());
30          * 本例中saveXXX方法没有返回值所以obj会报空指针异常
31          */
32         return obj;
33     }
34 }
 1 package com.proxy.impl;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 import com.proxy.inter.DemoFirst;
 6 /*import com.proxy.inter.DemoSecond;*/
 7 
 8 public class Test {
 9     public static void main(String[] args) {
10         DemoFirst first = new DemoFirstImpl();
11         /*DemoSecond second = new DemoSecondImpl();*/
12 
13         //取得代理对象
14         DemoFirst firstProxy = (DemoFirst) Proxy.newProxyInstance(first
15                 .getClass().getClassLoader(), first.getClass().getInterfaces(),
16                 new InvocationHandlerImpl(first));
17         //通过动态代理调用方法
18         firstProxy.saveFirst();
19 
20         /*DemoSecond secondProxy = (DemoSecond) Proxy.newProxyInstance(second
21                 .getClass().getClassLoader(), second.getClass().getInterfaces(), 
22                 new InvocationHandlerImpl(second));
23         secondProxy.saveSecond();*/
24     }
25 }

执行结果如图:

静态代理&动态代理

如果我们需要动态代理demoSecond对象,只需要像上面注释部分那样即可

执行结果如图:

静态代理&动态代理

我们会发现代理类Proxy会动态分配proxy对象,如图$Proxy0,$Proxy1...

动态代理的应用在很多地方都由体现,比如在开源框架Spring中的AOP(面向切面编程)...