Java动态代理
引言
因为在学习Spring AOP,其中用到了Java动态代理机制,所以好好把动态代理模式梳理了一遍。如有疑问或问题,欢迎在评论区探讨~
代理设计模式
-
原理:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
-
静态代理弊端:只能一个代理类实现一个接口,如果接口中的还有未实现的方法时,代理类也要必须实现。同时会产生大量重复的代码。
-
动态代理:通过反射机制实现动态代理(利用java.lang.reflect.InvocationHandler与java.lang.reflect.Proxy),抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理。
-
结构示意图:
代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。
Java 动态代理相关API
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface InvocationHandler:调用处理器接口,该接口中仅定义了一个invoke方法,用于集中处理在动态代理类实例上的方法调用,通常在该方法中实现对实现类的代理访问。
//该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
public object invoke(Object obj,Method method, Object[] args)
每次生成动态代理类实例时都需要指定一个实现了该接口的调用处理器对象。
(2)Proxy:该类即为动态代理类,提供了一组静态方法来为一组接口动态地生成代理类及其实例。
// Proxy的静态方法
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的 动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器 创建一个动态代理对象
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)
代理机制
动态代理步骤:
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
- 创建被代理的类以及接口
- 通过Proxy的静态方法newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
- 通过代理实现类的方法
实例:
-
需要动态代理的接口
interface Human{ String getBelief(); void eat(String food); }
-
被代理类
class SuperMan implements Human{ @Override public String getBelief() { return "I believe I can fly!"; } @Override public void eat(String food) { System.out.println("我喜欢吃" + food); } }
-
根据被代理类,动态的创建一个代理类及其对象
class ProxyFactory{ //调用此方法,返回一个代理类的对象。 public static Object getProxyInstance(Object obj){//obj:被代理类的对象 MyInvocationHandler handler = new MyInvocationHandler(); handler.bind(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler); } }
-
代理类的对象调用方法a时,动态调用被代理类的同名方法
class MyInvocationHandler implements InvocationHandler{ private Object obj;//需要使用被代理类的对象进行赋值,使用方法或构造器 public void bind(Object obj){ this.obj = obj; } //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke() //将被代理类要执行的方法a的功能就声明在invoke()中 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法(创建代理类对象时传参handler) //obj:被代理类的对象 Object returnValue = method.invoke(obj,args); //上述方法的返回值就作为当前类中的invoke()的返回值。 return returnValue; } }
-
测试
public class ProxyTest { public static void main(String[] args) { SuperMan superMan = new SuperMan(); //proxyInstance:代理类的对象 Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan); //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法 String belief = proxyInstance.getBelief(); System.out.println(belief); proxyInstance.eat("四川麻辣烫"); } }