专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 学习攻略 Java学习 Java动态代理原理

Java动态代理原理

更新时间:2022-05-06 10:25:00 来源:动力节点 浏览955次

动力节点小编来告诉大家Java动态代理原理是什么。Java动态代理机制的出现,给Java开发者带来了不必手工编写代理类,只需指定一组接口和委托类对象,就可以动态获取代理类。代理类负责将所有的方法调用分配给委托对象进行反射执行,在分派执行的过程中,开发者还可以根据需要调整委托类对象及其功能,这是一个非常灵活灵活的代理框架。现在让我们开始学习动态代理。

动态代理简述在java动态代理机制中,有两个重要的类或接口,一个是InvocationHandler(Interface)、另一个是Proxy(Class)。

InvocationHandler(interface)说明:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每个动态代理类都必须实现 InvocationHandler 这个接口,并且代理类的每个实例都关联一个处理程序,当我们通过代理对象调用一种方式时,对该方法的调用会转发到 InvocationHandler 这个接口的 invoke 方法来进行调用. 我们来看看 InvocationHandler 做这个接口的唯一方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

该方法接受三个参数并返回一个 Object 类型,它们的含义如下:

proxy: 指我们所代表的真实对象 method: 指我们要调用真实对象的方法 Method object args: 指在真实对象上调用方法时接受的参数 Back to Object真实对象方法的返回类型,以上内容将在下面的例子中进一步理解。

the value to return from the method invocation on the proxy instance.

Proxy(Class)说明:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

Proxy 此类用于动态创建代理对象。我们经常使用 newProxyInstance 这个方法:

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

参数理解:

// One ClassLoader object , Defined by which ClassLoader Object to load the generated proxy object 
loader - the class loader to define the proxy class 
// One Interface An array of objects , What is the set of interfaces that I'm going to provide to the object that I need to proxy 
interfaces - the list of interfaces for the proxy class to implement 
// One InvocationHandler object , Represents when my dynamic proxy object is calling a method , Which one does it relate to InvocationHandler On the object 
h - the invocation handler to dispatch method invocations to

返回结果的理解:代理对象的一个​​实例

a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces

普通Java代理我们创建一个Java项目用于测试和理解动态代理,项目结构如下:

1.我们定义一个接口Interface,添加两个方法。

package com.huhx.proxy;
public interface Interface {
void getMyName();
String getNameById(String id);
}

2.定义一个实现上述接口的真实类,RealObject:

package com.huhx.proxy;
public class RealObject implements Interface {
@Override
public void getMyName() {
System.out.println("my name is huhx");
}
@Override
public String getNameById(String id) {
System.out.println("argument id: " + id);
return "huhx";
}./* Welcome to join java communication Q Your appearance :909038429 Blow water and chat together
}

3.... 和 、 定义一个代理对象,它也实现了上面的接口接口:

package com.huhx.proxy;
public class SimpleProxy implements Interface {
private Interface proxied;
public SimpleProxy(Interface proxied) {
this.proxied = proxied;
}
@Override
public void getMyName() {
System.out.println("proxy getmyname");
proxied.getMyName();
}
@Override
public String getNameById(String id) {
System.out.println("proxy getnamebyid");
return proxied.getNameById(id);
}
}

4.SimpleMain在Main方法中,测试上述结果:

package com.huhx.proxy;
public class SimpleMain {
private static void consume(Interface iface) {
iface.getMyName();
String name = iface.getNameById("1");
System.out.println("name: " + name);
}
public static void main(String[] args) {
consume(new RealObject());
System.out.println("========================================================");
consume(new SimpleProxy(new RealObject()));
}
}

5.... 和 、 运行结果如下:

my name is huhx
argument id: 1
name: huhx
========================================================
proxy getmyname
my name is huhx
proxy getnamebyid
argument id: 1
name: huhx

Java动态代理完成了上面简单的Java代理,现在我们开始学习Java动态代理,它比代理的思想更进了一步,因为它可以动态创建代理并动态处理对代理方法的调用。在动态代理上进行的所有调用都被重定向到单个调用处理程序,它的工作是揭示调用的类型并确定相应的对策。下面我们通过案例加深对Java动态代理的理解:

1.创建一个继承 InvocationHandler 的处理器:DynamicProxyHandler

package com.huhx.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
System.out.println("dynamic proxy handler constuctor: " + proxied.getClass());
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("dynamic proxy name: " + proxy.getClass());
System.out.println("method: " + method.getName());
System.out.println("args: " + Arrays.toString(args));
Object invokeObject = method.invoke(proxied, args);
if (invokeObject != null) {
System.out.println("invoke object: " + invokeObject.getClass());
} else {
System.out.println("invoke object is null");
}
return invokeObject;
}
}

2.我们写一个测试Main方法,DynamicProxyMain:

package com.huhx.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.huhx.proxy.Interface;
import com.huhx.proxy.RealObject;
public class DynamicProxyMain {
public static void consumer(Interface iface) {
iface.getMyName();
String name = iface.getNameById("1");
System.out.println("name: " + name);
}
public static void main(String[] args) throws Exception, SecurityException, Throwable {
RealObject realObject = new RealObject();
consumer(realObject);
System.out.println("==============================");
// A dynamic proxy 
ClassLoader classLoader = Interface.class.getClassLoader();
Class<?>[] interfaces = new Class[] { Interface.class };
InvocationHandler handler = new DynamicProxyHandler(realObject);
Interface proxy = (Interface) Proxy.newProxyInstance(classLoader, interfaces, handler);
System.out.println("in dynamicproxyMain proxy: " + proxy.getClass());
consumer(proxy);
}./* Welcome to join java communication Q Your appearance :909038429 Blow water and chat together
}

3. ... 和 、 运行结果如下:

my name is huhx
argument id: 1
name: huhx
==============================
dynamic proxy handler constuctor: class com.huhx.proxy.RealObject
in dynamicproxyMain proxy: class com.sun.proxy.$Proxy0
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getMyName
args: null
my name is huhx
invoke object is null
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getNameById
args: [1]
argument id: 1
invoke object: class java.lang.String
name: huhx

从以上输出,我们可以得出以下结论:

与代理对象InvocationHandler相关联,只有当代理对象调用一个方法时,才进行invoke方法invoke 的三个参数的理解:对象代理是代理的对象,方法方法是真实对象调用的方法class , Object[] args 是真实对象中调用方法的参数

Java动态代理的原理

1.动态代理的关键代码是Proxy.newProxyInstance(classLoader, interfaces, handler),我们跟进源码看看:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
// handler Can't be empty 
if (h == null) {
throw new NullPointerException();
}
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.
*/
// adopt loader And interface , Get a proxy Class object 
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
// Create an instance of the proxy object 
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}

2.我们来看newInstance方法的源码:

private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString());
}
}
}

3....和、 当我们通过代理对象调用一种方式时,对该方法的调用转发 InvocationHandler 这个接口的 invoke 方法进行调用。体现这句话的代码,在源码中没有找到,所以在测试类的main方法中添加如下代码:

if (proxy instanceof Proxy) {
InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy);
invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null);
System.out.println("--------------------------------------");
}

这段代码的输出如下,而且,在上面,调用代理对象getMyName的方法输出是一样的,不知道!jvm 是否按此方式判断到底:

dynamic proxy handler constuctor: class com.huhx.proxy.RealObject
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getMyName
args: null
my name is huhx
invoke object is null

通过上述介绍,相信大家对Java动态代理原理已经有所了解,大家如果想了解更多相关知识,不妨来关注一下动力节点的Java在线学习,里面还有更丰富的知识等着大家去学习,希望对大家能够有所帮助哦。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>