反射机制
Reflect、语言机制
在程序运行时期,能够通过一些手段,获取到类的信息(类名,方法,字段,构造器等),java动态代理底层就是靠的这个机制
回调方法
Callback、控制反转
方法内部执行步骤已经规定,缺省的逻辑 由 回调函数 根据实际需求补全
Java的回调函数三要素:
1.回调接口:声明要回调的方法 2.回调接口实现类:可用 匿名内部类(一个回调方法) 或者 用lambda表达式(多个回调方法)省略 3.回调触发者:传回调接口的实现类(谁会用到这段回调),方法内部规调用步骤
// 回调接口public interface Callback { void invoke1(); void invoke2();}
// 回调接口实现public class CallbackImpl implements Callback{ @Override public void invoke1() { System.out.println("待补全方法1"); }
@Override public void invoke2() { System.out.println("待补全方法2"); }}
// 回调触发者public class CallbackHandler { //需要回调方法 public void invoke(Callback callback){ System.out.println("---------------------------"); System.out.println("额外逻辑1...");
callback.invoke1(); //回调方法
System.out.println("额外逻辑2..."); System.out.println("额外逻辑3...");
callback.invoke2(); //回调方法 System.out.println("---------------------------"); }}
// 测试public class Test { public static void main(String[] args) { // 调用函数 CallbackHandler callbackHandler = new CallbackHandler(); // 传入接口的实现类 callbackHandler.invoke(new CallbackImpl()); }}结果
------------------------------业务逻辑1...待补全方法1业务逻辑2...业务逻辑3...待补全方法2------------------------------代理模式
Proxy Pattern、设计模式
代理对象 替代 真实对象 处理请求 ,把“非核心逻辑”从真实对象中剥离出来,由代理统一处理

例如
客户(发出请求) → 找房中介(代理) → 房东(真实对象)
- 房东提供房子
- 房东让中介处理其他操作、服务(带人看房,拟定合同),增强服务体验
- 客户执行操作找中介就行
功能
控制访问:不让用户直接接触核心业务,保护安全
功能增强:你想给现有功能“加料”但不改原有代码
简化业务:真实对象只关注核心业务,可能会和其他对象类似的功能,统一提取出来交给代理去做
静态代理
编译前写死的代码(硬编码)
动态代理
运行时生成、基于反射实现、
Java Proxy
Java代理:接口实现

手动静态代理
只能代理一个接口的多个实现类,接口只规定核心业务方法。 实现类、静态代理类 继承 同一个接口 代理类重写方法 调用 实现类重写方法 并附加其他功能
[!tip] 思考 如果把target类型设计为最顶层接口,通过把多个接口重新组合为一个接口,则不符合规范,其余实现类必须实现与自己无关的抽象方法。并且上层是调用不了下层的特有方法,用强转会写的太死,脱离了代理思想。
// 接口public interface UserService { void addUser(String name);}// 实现类public class UserServiceImpl implements UserService{ @Override public void addUser(String name) { System.out.println("添加用户 " + name + " 成功"); }}// 实现类代理public class UserServiceProxy implements UserService{ private UserService target; public UserServiceProxy(UserService target) { this.target = target; } @Override public void addUser(String name) { System.out.println("代理:[权限检查]");// 前置额外逻辑
target.addUser(name); //UserService真实对象的核心业务逻辑
System.out.println("代理:[日志上传]");// 后置额外逻辑 }}// 调用public class ProxyTest { public static void main(String[] args) { UserService proxy = new UserServiceProxy(new UserServiceImpl()); proxy.addUser("张三"); }}/* 结果 代理:[权限检查] 添加用户 张三 成功 代理:[日志上传]*/JDK动态代理
反射、回调方法
coder手动创建的静态代理(麻烦) -> JVM用反射动态生成的静态代理(方便)
因为静态代理要获取实现类接口,所以JVM要知道你用的什么接口;
因为是动态生成的,所以里面的步骤控制权要转让给编写代码的人,就要用回调方法(invoke())。
以上是我对动态代理的核心理解,其本质就是由jvm创造的静态代理
实现流程图
Proxy 动态代理类
// Proxypublic static Object newProxyInstance( ClassLoader loader, // 用target类加载器 Class<?>[] interfaces, // 用target的接口:硬性规定只能代理接口 InvocationHandler h // 传入回调实现类: 要求重写回调方法,用于承载“方法调用时的统一处理逻辑”。)InvotationHandler 动态代理的回调接口
Interface InvotationHandler{ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;}自定义的工具类 ProxyUtil 封装写好的回调方法invoke
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; } } ); }}JDK动态生成的代理类(大致长这样)
// 发现没有,和静态代理一样的,区别只有不是写死的,JDK动态生成的// 即是代理,也是CallbackInvoker类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 h public $Proxy0(InvocationHandler h) { super(h); }
@Override public 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); } }}AOP
Aspect-Oriented Programming、面向切面编程、编程范式
将一些对象需要的类似功能提取出来组织,通过动态代理实现,和代理模式概念一致。区别在于将通用增强逻辑以声明式方式集中管理,实现对业务代码的非侵入式横切增强。故是代理模式的上层
总结
回调 (IOC基本方法)
补齐 外部规定模板方法的 缺失逻辑/行为
静态代理 (复用性 ↑)
手写的代理类和实现类继承同一组接口,在代理类同名方法 调用 实现类同名方法 + 通用增强逻辑
动态代理 (复用性 ↑)
运行时生成代理类,代理类同名方法由回调、反射实现(自己写)
AOP (扩展性 ↑)
动态代理 + 以声明式方式将通用增强逻辑集中管理,实现对业务代码的非侵入式横切增强
(有些实现类用增强逻辑A,有些用增强逻辑B,程序员进行调配、选择、简化开发)
对 面向接口 有了更深理解,重要程度不亚于C指针;
剖析时 加强了对匿名内部类、lambda进一步理解(语法糖);
引出 编程范式、设计思想、接口的default方法、钩子和回调区别、还需继续学习
部分信息可能已经过时