更新时间:2022-05-06 10:25:00 来源:极悦 浏览1058次
极悦小编来告诉大家Java动态代理原理是什么。Java动态代理机制的出现,给Java开发者带来了不必手工编写代理类,只需指定一组接口和委托类对象,就可以动态获取代理类。代理类负责将所有的方法调用分配给委托对象进行反射执行,在分派执行的过程中,开发者还可以根据需要调整委托类对象及其功能,这是一个非常灵活灵活的代理框架。现在让我们开始学习动态代理。
动态代理简述在java动态代理机制中,有两个重要的类或接口,一个是InvocationHandler(Interface)、另一个是Proxy(Class)。
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 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 是真实对象中调用方法的参数
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极悦在线学习,里面还有更丰富的知识等着大家去学习,希望对大家能够有所帮助哦。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习