
介绍
之前的动态代理篇幅写的不好,所以重写了一下(Java实现),作为个人的复习3。同时这一章承上启下,承接反射篇章,引出AOP思想和Spring AOP
了解AOP的前置知识(本人目前只了解Java AOP)
- 回调函数
- 静态代理
- 反射
- jdk动态代理
回调方法 CallBack
将核心代码交给使用者编写
A想使用B设计的代码,其中的大部分功能符合A需求,但是A仍不满足,如果代码是写死的话,A还要重构一下并自己封装,冗余而不方便。
假设B的代码将A想重写的部分抽离出去,其余部分做一个框架,A就只需要写核心的代码即可,非常方便。所以被抽离的部分就是回调函数!
想要实现这个思想,各个语言各有不同的方法(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(){
@Override
public void callBackMethod(){
System.out.println("Hello I'm Oddpalmer");
}
});
}
/*
写死的代码
回调方法: Hello I'm Oddpalmer
写死的代码
*/
只需要编写一个继承callback的类,并重写方法即可传入Caller实现回调,it’s simple
静态代理 Static Proxy
代理就是将非核心代码剥离出去,只关注对象本身的核心
非核心代码在AOP中称为通知(Advice)
以明星和经纪人为例:对接、签约….,这些工作经纪人做就行,明星只需要唱歌、演戏….即可,这里经纪人就作了代理的工作,并且经纪人可以去为多个明星服务。
Java实现代理的步骤
- 代理和被代理对象类继承同一个接口
- 代理的方法调用对象的同名方法

依旧是面向接口编程
1.接口
public interface UserService {
void addUser(String name);
}
2.实现类
public class UserServiceImpl implements UserService{
@Override
public void addUser(String name) {
System.out.println("添加用户 " + name + " 成功");
}
}
3.实现类代理
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("代理:[日志上传]");// 后置额外逻辑
}
}
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本文不作讨论)
不了解反射的可以看博主的这篇文档 待重构todo
jvm生成的一个动态代理类大致长这样,发现没有,和静态代理一样的,区别只是动态生成的(里面涉及了一个回调,我们稍后再讲),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 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);
}
}
}
如何生成一个动态代理类?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生成了动态代理类$ProxyXXX
- main调用代理类UserServiceProxy的addUser(),会通过重写的回调方法调用被代理对象本身的addUser()

引出Spring AOP
面向切面AOP的思想很简单,将一个对象的核心代码抽离出来,使得开发者更注重核心代码而非其他的冗余代码(通知)。动态代理就是实现这一思想的利器
Spring AOP就很好的帮我们省去了写ProxyUtil类的过程….
文章摘自:https://www.cnblogs.com/oddpalmer/p/19931115
