从回调认识动态代理 (Java)

发布时间:2026/6/30 5:18:48
从回调认识动态代理 (Java) 想要实现这个思想各个语言各有不同的方法(noob的猜测)Java要实现回调函数就要利用其重要的面向接口(Interface)思想1.回调接口public interface CallBack {public void callBackMethod();}2.调用类public class Caller {public void call(CallBack callBack) {System.out.println(写死的代码);callBack.callBackMethod();System.out.println(写死的代码);}}3.重写回调方法,为了方便使用匿名内部类public static void main(){Caller caller new Caller();caller.call(new CallBack(){Overridepublic void callBackMethod(){System.out.println(Hello Im Oddpalmer);}});}/*写死的代码回调方法: Hello Im Oddpalmer写死的代码*/只需要编写一个继承callback的类并重写方法即可传入Caller实现回调its simple静态代理 Static Proxy代理就是将非核心代码剥离出去只关注对象本身的核心非核心代码在AOP中称为通知(Advice)以明星和经纪人为例对接、签约....这些工作经纪人做就行明星只需要唱歌、演戏....即可这里经纪人就作了代理的工作并且经纪人可以去为多个明星服务。Java实现代理的步骤代理和被代理对象类继承同一个接口代理的方法调用对象的同名方法依旧是面向接口编程1.接口public interface UserService {void addUser(String name);}2.实现类public class UserServiceImpl implements UserService{Overridepublic void addUser(String name) {System.out.println(添加用户 name 成功);}}3.实现类代理public class UserServiceProxy implements UserService{private UserService target;public UserServiceProxy(UserService target) {this.target target;}Overridepublic void addUser(String name) {System.out.println(代理[权限检查]);// 前置额外逻辑target.addUser(name); //UserService真实对象的核心业务逻辑System.out.println(代理[日志上传]);// 后置额外逻辑}}4.Main// 调用public class ProxyTest {public static void main(String[] args) {UserService proxy new UserServiceProxy(new UserServiceImpl());proxy.addUser(张三);}}/* 结果代理[权限检查]添加用户 张三 成功代理[日志上传]*/虽然静态代理能在一定程度上帮我们减少代码冗余但是不难发现只有继承了UserService接口的类才可以被代理。如果我还有OrderService、ProductService也需要权限检查或者日志上传就需要多个静态代理才可以实现局促而不优雅这就引出了我们的动态代理。动态代理 Dynamic Proxy我们已经知道静态代理与被代理对象的类会继承同一个接口。那么Java实现动态代理也要知道创造的代理类要继承什么接口从而和被代理对象在接口上保持一致所以就要依赖Java反射机制以获取运行时类的接口信息和方法然后由JVM在内存中动态创造多个静态代理类实现代理(也称作JDK动态代理用接口实现。cglib本文不作讨论)不了解反射的可以看博主的这篇文档 待重构todojvm生成的一个动态代理类大致长这样发现没有和静态代理一样的区别只是动态生成的(里面涉及了一个回调我们稍后再讲)DeepSeek给出的代码public final class $Proxy0 extends Proxy implements UserService {private static Method m_addUser;static {try {m_addUser UserService.class.getMethod(addUser, String.class);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}// 父类 Proxy 已经持有 InvocationHandler hpublic $Proxy0(InvocationHandler h) {super(h);}Overridepublic void addUser(String name) {try {// invoactionHandler.invoke(), 所有接口方法 → 回调调用者h.invoke(this, m_addUser, new Object[]{name});} catch (RuntimeException | Error e) {throw e;} catch (Throwable t) {throw new UndeclaredThrowableException(t);}}}如何生成一个动态代理类Java给我们设计了java.lang.reflect.Proxy类其中的newProxyInstance()的三个参数 就是关键...public static Object newProxyInstance(ClassLoader loader, // 用target类加载器Class?[] interfaces, // 用target的接口硬性规定只能代理接口InvocationHandler h // 传入回调实现类: 要求重写回调方法用于承载“方法调用时的统一处理逻辑”。)参数1涉及的底层我还理解不了参数2很明显是通过反射获取某个类的接口参数3就是我们上文提到的回调接口参数如下Interface InvotationHandler{public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;}创造代理对象的步骤调用newProxyInstance()将被代理对象的实例作为参数传入重写invocationHandler回调接口的invoke()实际开发中动态代理可以再封装成一个工具类不用每次代理都去newProxyInstance()简化代码public class ProxyUtil {SuppressWarnings(unchecked)public static T T createProxy(T target) {return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {Override// InvokeHandler接口定义的回调方法,控制权在程序员手里public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println([权限检测]);// 前置 额外逻辑Object o method.invoke(target, args);// 反射包下invoke 调用真实对象方法System.out.println([日志记录]);// 后置 额外逻辑return o;}});}}当你调用了ProxyUtil后UserService userServiceProxy new ProxyUtil().createProxy(new UserServiceImple());userServiceProxy.addUser(oddpalmer);/*[权限检测]添加 oddpalmer 成功[日志记录]*/程序执行顺序jvm生成了动态代理类$ProxyXXXmain调用代理类UserServiceProxy的addUser(),会通过重写的回调方法调用被代理对象本身的addUser()