Today, by chance, I suddenly wanted to take a look at the dynamic proxy of JDK, because I knew a little about it before, and I just wanted to test its use. I wrote several interfaces and classes in a short time:
Interface class: UserService.java
package com.yixi.proxy; public interface UserService { public int save() ; public void update(int id); }
Implementation class: UserServiceImpl.java
package com.yixi.proxy; public class UserServiceImpl implements UserService { @Override public int save() { System.out.println("user save...."); return 1; } @Override public void update(int id) { System.out.println("update a user " + id); } }
Then I quickly wrote the InvocationHandler I wanted: the function of this is very simple. Record the start time and end time of method execution
TimeInvocationHandler.java
package com.yixi.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(proxy, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; } }
After all the preparations are done, of course we have to start writing tests!
Test.java
package com.yixi.proxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { 9 TimeInvocationHandler timeHandler = new TimeInvocationHandler(); UserService u = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler); u.update(2); u.save(); } }
Run it happily, but it does not give you face. The result is a screen-full exception:
startTime : 1352877835040 startTime : 1352877835040 startTime : 1352877835040 Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at $Proxy0.update(Unknown Source) at com.yixi.proxy.Test.main(Test.java:11) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.yixi.proxy.TimeInvocationHandler.invoke(TimeInvocationHandler.java:12) ... 2 more
com.yixi.proxy.TimeInvocationHandler.invoke( TimeInvocationHandler.java:12) The exception clearly tells that the problem is in line 12 of TimeInvocationHandle: that is,
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(proxy, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; }There is nothing wrong in the method! Because the invoke() method seems to provide all the parameters required by method.invoke(Object, Object[]), we will use it as a matter of course. If you really think that way, then you have fooled the JDK. It's a trap, let's look at the correct way of writing first. In case some students are not in the mood to read the following, at least give me the correct solution:
Modify TimeInvocationHandler.java
package com.yixi.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TimeInvocationHandler implements InvocationHandler { private Object o; public TimeInvocationHandler(Object o){ this.o = o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("startTime : " +System.currentTimeMillis()); Object obj = method.invoke(o, args); System.out.println("endTime : " +System.currentTimeMillis()); return obj; } }
Modify Test.java
package com.yixi.proxy; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { TimeInvocationHandler timeHandler = new TimeInvocationHandler(new UserServiceImpl()); UserService u = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), timeHandler); u.update(2); u.save(); } }
Now is the correct output result:
startTime : 1352879531334 update a user 2 endTime : 1352879531334 startTime : 1352879531334 user save.... endTime : 1352879531335
If you want to have less code, you can write an anonymous class directly:
package com.yixi.proxy;
import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
final UserServiceImpl usi = new UserServiceImpl();
UserService u = (UserService) Proxy.newProxyInstance(
new InvocationHandler() {
System.out.println("startTime : " +System. currentTimeMillis());
Object obj = method.invoke(usi, args);
System.out.println("endTime : " +System.currentTimeMillis());
return obj;
}
});
u.update(2); The first parameter is the target object passed in, so why does the Invoke method of invocationHandler need an Object proxy parameter? Let’s look down!
For the most important invoke method (in my opinion) let’s see what the JDK says:
invoke Object invoke(Object proxy, Method method, Object[] args) throws Throwable在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。 参数: proxy - 在其上调用方法的代理实例 method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。 args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
proxy - the proxy instance on which the method is called? What does this sentence mean? acting? method is the proxy method? Then shouldn't my method for executing the proxy be Object obj = method.invoke(proxy, args);? I didn't turn around at that time. I went to the discussion group and went to Google but couldn't find any inspiration. I thought I'd better look at the source code and maybe I could see something!
Open the source code of the Proxy class and find out what kind of construction method there is:
protected InvocationHandler h; protected Proxy(InvocationHandler h) { this.h = h; }
Use InvocationHandler as a parameter of the Proxy construction method.... So what does it use the InvocationHandler for? Is there any connection with the invoke() method in InvocationHandler?
My first thought is that Proxy will call the following statement internally:
h.invoke(this,methodName,args);Because you have to call the invoke method to execute the corresponding method.
Let’s take a look at this first
在这里你就会发现貌似有点感觉了:当u.update(2)时 àProxy就会调用 handler.invoke(proxyClass,update,2) à 也就是调用了proxyClass.update(2);
当u.save();时àProxy就会调用handler.invoke(proxyClass,save,null) à也就是调用了proxyClass.save();
当Test.java改成这样时:
public class Test { public static void main(String[] args) { final UserServiceImpl usi = new UserServiceImpl(); UserService u = (UserService) Proxy.newProxyInstance( usi.getClass().getClassLoader(), usi.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } }); u.update(2); u.save(); } }
注意这时候的匿名类的方法的返回的是null,运行一下就会发现:
Exception in thread "main" java.lang.NullPointerException at $Proxy0.save(Unknown Source) at com.yixi.proxy.Test.main(Test.java:17)
17行有空指针 也就是这里的u.save()方法有为null的元素 难道是u是空的? 不应该啊如果u是null的话那么u.update(2)在那里就会报空指针异常了,当我把17行注释掉以后异常没了说明u.update()能正常执行。那这到底是为什么呢?
其实这就是invoke方法返回null的缘故:
注意一下UserService类中的两个方法:
public interface UserService { public int save() ; public void update(int id); }Save()方法返回的是int型的 而update方法返回的是void型的;根据上面的猜测是 handler.invoke()是实现 proxyClass.update(2);的,invoke方法中的return方法的是相应的代理方法的返回值,
所以在invoke方法返回null的时候代理的update方法接收到返回值是null, 而它本来就是返回void 所以没有报异常, 而代理save必须返回int型的数值 我们这返回的还是null,JVM无法将null转化为int型 所以就报了异常了
这样解释就能解释通了,也能相对证明前面的猜测。
InvocationHandler中invoke方法中第一个参数proxy貌似只是为了让Proxy类能给自己的InvocationHandler对象的引用调用方法时能传入代理对象proxyClass的引用,来完成proxyClass需要完成的业务。
更多Java dynamic proxy implementation method of proxy mode相关文章请关注PHP中文网!

This article analyzes the top four JavaScript frameworks (React, Angular, Vue, Svelte) in 2025, comparing their performance, scalability, and future prospects. While all remain dominant due to strong communities and ecosystems, their relative popul

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa

Node.js 20 significantly enhances performance via V8 engine improvements, notably faster garbage collection and I/O. New features include better WebAssembly support and refined debugging tools, boosting developer productivity and application speed.

Iceberg, an open table format for large analytical datasets, improves data lake performance and scalability. It addresses limitations of Parquet/ORC through internal metadata management, enabling efficient schema evolution, time travel, concurrent w

This article addresses the CVE-2022-1471 vulnerability in SnakeYAML, a critical flaw allowing remote code execution. It details how upgrading Spring Boot applications to SnakeYAML 1.33 or later mitigates this risk, emphasizing that dependency updat

This article explores integrating functional programming into Java using lambda expressions, Streams API, method references, and Optional. It highlights benefits like improved code readability and maintainability through conciseness and immutability

The article discusses using Maven and Gradle for Java project management, build automation, and dependency resolution, comparing their approaches and optimization strategies.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

SublimeText3 Linux new version
SublimeText3 Linux latest version

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

WebStorm Mac version
Useful JavaScript development tools

SublimeText3 English version
Recommended: Win version, supports code prompts!
