import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
UserManager target = new UserManagerImpl();
UserManager proxy = (UserManager) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new UserManagerProxy(target));
proxy.addUser();
}
}
interface UserManager {
public void addUser();
}
class UserManagerImpl implements UserManager {
@Override
public void addUser() {
System.out.println("add user...");
}
}
class UserManagerProxy implements InvocationHandler {
private UserManager target;
public UserManagerProxy(UserManager target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("check privilege " + proxy);
method.invoke(target, args);
return null;
}
}
在执行代理处理类的System.out.println("check privilege " + proxy);时候,出现了java.lang.StackOverflowError错误。原因可以初步定位在proxy的toString方法上。
但是调试后发现proxy属于$Proxy0类,而$Proxy0这个Class是运行时生成的类,网上有一个牛人贴出了$Proxy0的源码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements UserManager {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("cn.edu.jlu.proxy.UserManager").getMethod("addUser",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
.booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public void addUser() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
可以看到,调用toString方法的时候,调用了h的invoke方法,而h就是InvocationHandler的实例,所以是递归调用,所以就会出现上述所说的java.lang.StackOverflowError错误。
这里顺便说一下简单编写java动态代理的过程:
1.定义一个接口I
2.编写该接口I的实现类Impl
3.编写InvocationHandler接口的实现类H,构造H类对象的时候可以把要代理的对象target传入,target完成实际的动作。在里面的invoke方法里编写自己想实现的逻辑,然后再调用实际要完成的动作就可以。
4.调用Proxy.newProxyInstance方法,传递的三个参数分别是代理类的类加载器(可以用Impl实例的getClass().getClassLoader())
、代理类要实现的接口列表(可以用Impl实例getClass().getInterfaces())、InvocationHandler实现类的实例。
这样就生成了$Proxy0类的对象,由于$Proxy0类实现了I接口,所以可以将对象强制转型成I。
再说一下Proxy.newProxyInstance方法的实际过程:
1.使用传入的InvocationHandler实例参数将Proxy类的h实例初始化,注意,如果传入空对象的话,会抛出空指针错误,即h不能为空。
2.运行时生成代理Class,即$Proxy0
3.利用上面动态生成的$Proxy0类,构造出该类的对象,并返回。
分享到:
相关推荐
通过上述分析,我们可以看出JDK动态代理是一种非常强大且灵活的技术,它不仅可以帮助我们解决实际开发中遇到的问题,还能够提高代码的可维护性和可扩展性。理解其工作原理对于深入学习Java编程有着重要意义。
下面是一个简单的示例,演示了如何使用JDK动态代理为一个接口创建代理对象,并在方法调用前后添加日志记录功能。 ```java /** * 业务接口 */ public interface IHello { void hello(String name); } /** * ...
然而,如果目标类的方法很多,CGLIB可能会更高效,因为它只需创建一次子类,而JDK动态代理每次调用都需要通过InvocationHandler。在内存占用上,两者差别不大,但CGLIB生成的代理类可能略微增加内存负担。 在工具...
JDK动态代理,全称为Java Dynamic Proxy,是Java标准库提供的一种强大且灵活的机制,允许我们在运行时创建代理类来实现指定的接口。这种机制主要用于实现AOP(面向切面编程)或为已有接口提供额外的功能,如日志、...
Proxy 类是 JDK 中的动态代理类,是动态代理的核心类,其作用类似于代理模式中的代理。Proxy 类中包含的全是静态的方法和成员变量,这是一个纯粹的工具类,因此其源代码中含有一个私有的构造器,在某种意义上可以看...
3. **不同类,不同方法的代理**:在描述中提到的“不同类,不同方法的代理”意味着JDK动态代理可以为任何实现了相同接口的类创建代理,而不仅仅是单一类。这得益于`InvocationHandler`的灵活性,它可以处理任何接口...
在 JDK 动态代理中,我们可以使用 InvocationHandler 来处理方法的调用。InvocationHandler 是一个接口,它定义了 invoke 方法,该方法将被代理对象的方法调用转发到 InvocationHandler 的 invoke 方法中。在 invoke...
JDK动态代理是Java编程中一个非常重要的特性,它允许我们在运行时创建具有特定接口的代理类实例。这种技术在很多场景下都非常有用,比如在AOP(面向切面编程)中实现方法拦截、日志记录、事务管理等。下面我们将深入...
标题 "JDK动态代理在EJB3(包括WebService)中的应用" 暗示了本文将探讨Java开发中的一种重要技术——JDK动态代理,以及它如何在企业级JavaBean (EJB) 3.x版本及其相关的Web服务实现中发挥作用。EJB3是Java EE平台的...
总的来说,JDK动态代理是Spring AOP实现的基础,它允许我们在运行时动态创建代理对象,实现对方法调用的拦截和增强。Spring AOP则在此基础上提供了更高级的抽象,让我们可以方便地定义和管理切面,从而实现更灵活的...
- `MethodInterceptor`接口类似于JDK动态代理中的`InvocationHandler`,但它的拦截逻辑更为灵活,可以在`intercept()`方法中控制目标方法的调用。 3. **FastClass和MethodProxy** - CGLIB通过`FastClass`和`...
在Java中,我们可以使用JDK的动态代理或者Spring AOP来实现代理模式。 JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。Proxy类是生成代理对象的工厂,而...
在Java编程中,动态代理是一种强大的技术,它允许我们在运行时创建对象的代理,以便在调用实际方法之前或之后执行额外的操作。JDK动态代理和CGlib动态代理是Java中实现这一目标的两种主要方式。 ### JDK动态代理 ...
在Java编程中,动态代理是一种强大的技术,它允许我们在运行时创建对象的代理,这些代理对象可以在调用实际方法之前和之后执行额外的操作。这种机制主要用于实现AOP(面向切面编程)和事件监听等功能。在本文中,...
在Java中,动态代理是一种在运行时创建代理类的能力,它允许我们为一组接口创建代理对象,这些代理对象可以拦截并处理方法调用。核心接口是`java.lang.reflect.InvocationHandler`,它定义了处理方法调用的逻辑;另...
Java JDK 动态代理是一种强大的特性,它允许我们在运行时创建代理对象,这些代理对象可以扩展或增强已存在的接口实现。动态代理在处理AOP(面向切面编程)场景、事件监听、性能监控等方面有着广泛的应用。下面我们将...
- **CGLIB代理**适用于目标类没有接口或者不希望修改原有接口的情况,其性能通常优于JDK代理,因为它是基于字节码生成的子类,而JDK代理需要反射调用接口方法。 在实际开发中,如Spring AOP框架就同时支持JDK和...
在Java开发中,JDK的动态代理是一种非常重要的技术,它允许我们在运行时创建具有特定接口的代理类实例,从而实现代理对象对目标对象的方法调用进行拦截和增强。这篇博客将对JDK的动态代理进行深入的总结,探讨其原理...
Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建对象的代理,从而实现对原对象的一些额外操作或扩展功能。JDK动态代理和CGLIB代理是两种常用的实现方式。 首先,我们来看看JDK动态代理。JDK动态...
在Java编程中,JDK动态代理是一种非常实用的技术,它允许我们在运行时创建代理类来增强或拦截原有类的方法调用。在这个“jdk动态代理 + 拦截器实现小例”中,我们将探讨如何利用Java的InvocationHandler接口和Proxy...