这里提供一个认识代理,以及这些,的一脉思路
我们从几个层面,来认识这些思路的实现。
从逻辑上理解。
所谓的代理,其实就是在代码层面,抽象出来一些公共要做的事情,然后可以省略出来。
从代理的实现方式来说,我们可以分为静态代理:
这里先做一个小的解释,背景说明。
在代码实现层面,所谓的静态代理,就是把原来的类,实例化成对象,然后再这个类的方法上面,下面,写更多的代码,做更多的事情。
上代码,给个demo:
静态代理实现接口代理示例
下面我将展示一个完整的静态代理模式示例,用于代理接口的实现。
1. 基础接口定义
java
// 1. 定义接口
public interface UserService {
void addUser(String username);
String getUser(int id);
void deleteUser(int id);
}
2. 真实实现类
java
// 2. 真实实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("真实操作:添加用户 " + username);
// 这里可以是实际的数据库操作
}
@Override
public String getUser(int id) {
System.out.println("真实操作:获取用户,ID = " + id);
return "用户" + id;
}
@Override
public void deleteUser(int id) {
System.out.println("真实操作:删除用户,ID = " + id);
}
}
3. 静态代理类
java
// 3. 静态代理类
public class UserServiceProxy implements UserService {
// 持有真实对象的引用
private UserService realService;
// 可以通过构造器注入真实对象
public UserServiceProxy(UserService realService) {
this.realService = realService;
}
@Override
public void addUser(String username) {
// 前置增强
System.out.println("【代理日志】开始执行 addUser 方法");
System.out.println("【参数校验】用户名: " + username);
try {
// 调用真实对象的方法
realService.addUser(username);
// 后置增强
System.out.println("【代理日志】addUser 方法执行成功");
} catch (Exception e) {
// 异常增强
System.out.println("【代理日志】addUser 方法执行异常: " + e.getMessage());
throw e;
} finally {
// 最终增强
System.out.println("【代理日志】addUser 方法执行结束\n");
}
}
@Override
public String getUser(int id) {
System.out.println("【代理日志】开始执行 getUser 方法");
System.out.println("【参数校验】用户ID: " + id);
if (id <= 0) {
System.out.println("【参数校验】ID必须大于0");
return null;
}
long startTime = System.currentTimeMillis();
String result = realService.getUser(id);
long endTime = System.currentTimeMillis();
System.out.println("【性能监控】getUser 方法执行耗时: " + (endTime - startTime) + "ms");
System.out.println("【代理日志】getUser 方法执行结束,返回值: " + result + "\n");
return result;
}
@Override
public void deleteUser(int id) {
System.out.println("【代理日志】开始执行 deleteUser 方法");
System.out.println("【权限校验】检查删除权限...");
// 模拟权限校验
if (id == 1) {
System.out.println("【权限校验】无权删除管理员用户");
return;
}
realService.deleteUser(id);
System.out.println("【代理日志】deleteUser 方法执行结束\n");
}
// 代理类可以有自己的额外方法
public void showProxyInfo() {
System.out.println("=== 代理信息 ===");
System.out.println("代理类: " + this.getClass().getName());
System.out.println("真实类: " + realService.getClass().getName());
System.out.println("================\n");
}
}
4. 测试类
java
// 4. 测试类
public class StaticProxyDemo {
public static void main(String[] args) {
System.out.println("======= 静态代理模式演示 =======\n");
// 创建真实对象
UserService realService = new UserServiceImpl();
// 创建代理对象,传入真实对象
UserServiceProxy proxy = new UserServiceProxy(realService);
// 显示代理信息
proxy.showProxyInfo();
// 通过代理对象调用方法
System.out.println("1. 测试 addUser 方法:");
proxy.addUser("张三");
System.out.println("2. 测试 getUser 方法:");
String user = proxy.getUser(1001);
System.out.println("获取到的用户: " + user);
System.out.println("3. 测试参数校验:");
proxy.getUser(-1);
System.out.println("4. 测试权限控制:");
proxy.deleteUser(1); // 尝试删除管理员
proxy.deleteUser(1001); // 删除普通用户
System.out.println("======= 演示结束 =======");
}
}
我们在来认识一下动态代理。
先做一个简单的说明。
所谓的动态代理,我们针对的对象,还是类。
他相比静态代理,实现的效果,都是对类的方法的信息的增加,但是实现方式不一样。
我们看一个demo的例子:
口语化解释:什么是动态代理?
想象这样一个场景:
你是一个明星,我是你的经纪人。有公司想找你拍广告,他们不会直接找你,而是先找我这个经纪人。
静态代理就是:
- 我是你专属的经纪人,只代理你一个人
- 如果又来了一个歌手要找经纪人,需要再专门雇一个经纪人
- 每个明星都要配一个专门的经纪人,成本很高
动态代理就是:
- 我是一个"经纪人公司"
- 你(明星)来了,我马上为你生成一个专属经纪人
- 歌手来了,我也马上生成一个专属经纪人
- 但我这个"经纪人公司"的核心处理逻辑是一样的:先谈价格、签合同、安排日程、收钱
- 我不用为每个明星提前写好经纪人方案,而是运行时根据需要动态生成
动态代理比静态代理好在哪里?
-
不用写重复代码:
- 静态代理:10个接口就要写10个代理类
- 动态代理:写1个处理器,就能代理所有接口
-
维护方便:
- 静态代理:接口加方法,所有代理类都要跟着改
- 动态代理:只需要改处理器逻辑,所有代理都生效
-
更加灵活:
- 可以运行时决定代理谁
- 可以动态添加功能
最简单的Demo实现
第一步:明星(接口)
java
// 明星会做的事
interface Star {
void sing(); // 唱歌
void act(); // 演戏
}
第二步:真实的明星
java
// 真实的周杰伦
class RealStar implements Star {
public void sing() {
System.out.println("周杰伦在唱《七里香》");
}
public void act() {
System.out.println("周杰伦在演《头文字D》");
}
}
第三步:经纪人公司(动态代理核心)
java
import java.lang.reflect.*;
// 经纪人公司 - 动态代理核心
public class BrokerCompany {
public static void main(String[] args) {
// 真实的明星
Star realStar = new RealStar();
// 动态创建经纪人(代理)
Star agent = (Star) Proxy.newProxyInstance(
realStar.getClass().getClassLoader(), // 用明星的类加载器
new Class[]{Star.class}, // 明星会的技能(接口)
new InvocationHandler() { // 统一的处理逻辑
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 演出前:谈价格、签合同
System.out.println("经纪人:先谈价格,签合同");
// 让明星真正演出
Object result = method.invoke(realStar, args);
// 演出后:收钱、结账
System.out.println("经纪人:演出结束,收钱结账");
return result;
}
}
);
// 现在找明星演出,实际上是通过经纪人
System.out.println("=== 找明星唱歌 ===");
agent.sing();
System.out.println("\n=== 找明星演戏 ===");
agent.act();
}
}
运行结果:
=== 找明星唱歌 ===
经纪人:先谈价格,签合同
周杰伦在唱《七里香》
经纪人:演出结束,收钱结账
=== 找明星演戏 ===
经纪人:先谈价格,签合同
周杰伦在演《头文字D》
经纪人:演出结束,收钱结账
关键理解点:
Proxy.newProxyInstance- 这个方法是"经纪人公司",能动态创建经纪人InvocationHandler- 这是经纪人的"工作流程模板"- 运行时生成 - 代码里没有
Star的代理类,是运行时生成的 - 统一处理 - 不管明星是唱歌还是演戏,经纪人的工作流程都一样
如果再来个新明星?
java
// 新明星:林俊杰
class AnotherStar implements Star {
public void sing() {
System.out.println("林俊杰在唱《江南》");
}
public void act() {
System.out.println("林俊杰在演音乐剧");
}
}
// 用同一个经纪人公司代理新明星
Star anotherAgent = (Star) Proxy.newProxyInstance(
anotherStar.getClass().getClassLoader(),
new Class[]{Star.class},
handler // 同样的处理逻辑!
);
这个是jdk的基于接口,实现的动态代理,是aop的底层实现。
我们在来看基于cglib的动态代理:
CGLIB动态代理Demo
一、CGLIB vs JDK动态代理对比
| 特性 | JDK动态代理 | CGLIB动态代理 |
|---|---|---|
| 代理对象 | 只能代理接口 | 可以代理普通类 |
| 原理 | 实现接口,继承Proxy | 继承目标类,生成子类 |
| 性能 | 反射调用较慢 | 方法调用较快(直接调用父类) |
| 依赖 | JDK自带 | 需要额外jar包 |
二、完整Demo实现
第一步:添加Maven依赖
xml
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
第二步:创建目标类(不需要接口!)
java
// 1. 目标类 - 注意:没有实现任何接口!
public class UserService {
// 普通方法
public void addUser(String name) {
System.out.println("真实操作:添加用户 " + name);
}
// final方法 - CGLIB无法代理
public final void finalMethod() {
System.out.println("这是一个final方法,不能被代理");
}
// private方法 - CGLIB无法代理
private void privateMethod() {
System.out.println("这是一个private方法");
}
// 有返回值的方法
public String getUser(int id) {
System.out.println("真实操作:查询用户 " + id);
return "用户" + id;
}
// 静态方法 - CGLIB无法代理
public static void staticMethod() {
System.out.println("这是一个静态方法");
}
}
第三步:创建方法拦截器(类似InvocationHandler)
java
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 2. 方法拦截器 - 核心类
public class CglibInterceptor implements MethodInterceptor {
// 目标对象
private Object target;
public CglibInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
System.out.println("【CGLIB代理】开始执行方法: " + methodName);
// 过滤掉final、static、private等方法
if ("finalMethod".equals(methodName) ||
"privateMethod".equals(methodName) ||
"staticMethod".equals(methodName)) {
System.out.println("【CGLIB代理】跳过无法代理的方法: " + methodName);
return method.invoke(target, args);
}
// 前置增强
System.out.println("【CGLIB代理】前置处理,参数: " + (args != null ? java.util.Arrays.toString(args) : "无"));
long startTime = System.currentTimeMillis();
// 关键区别:这里有两种调用方式
Object result = null;
// 方式1:使用MethodProxy(更快,推荐)
// 直接调用父类方法,避免反射
result = proxy.invokeSuper(obj, args);
// 方式2:使用反射(较慢)
// result = method.invoke(target, args);
long endTime = System.currentTimeMillis();
// 后置增强
System.out.println("【CGLIB代理】后置处理,返回值: " + result);
System.out.println("【CGLIB代理】方法耗时: " + (endTime - startTime) + "ms\n");
return result;
}
}
第四步:创建CGLIB代理工厂
java
import net.sf.cglib.proxy.Enhancer;
// 3. CGLIB代理工厂
public class CglibProxyFactory {
/**
* 创建代理对象
* @param targetClass 目标类
* @return 代理对象
*/
public static <T> T createProxy(Class<T> targetClass) {
// 创建增强器
Enhancer enhancer = new Enhancer();
// 设置父类(目标类)
enhancer.setSuperclass(targetClass);
// 设置回调(拦截器)
enhancer.setCallback(new CglibInterceptor(targetClass));
// 设置构造器策略 - 使用无参构造器
enhancer.setStrategy(null);
// 创建代理对象
return (T) enhancer.create();
}
/**
* 创建代理对象(带自定义拦截器)
*/
public static <T> T createProxy(Class<T> targetClass, MethodInterceptor interceptor) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(interceptor);
return (T) enhancer.create();
}
/**
* 创建代理对象(需要目标实例)
*/
public static <T> T createProxy(T target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibInterceptor(target));
return (T) enhancer.create();
}
}
第五步:测试CGLIB代理
java
// 4. 测试类
public class CglibDemo {
public static void main(String[] args) {
System.out.println("======= CGLIB动态代理演示 =======\n");
// 注意:我们没有创建UserService的实例!
// CGLIB会帮我们创建子类实例
System.out.println("1. 创建CGLIB代理对象");
UserService proxy = CglibProxyFactory.createProxy(UserService.class);
System.out.println("\n2. 查看代理对象信息");
System.out.println("代理对象类名: " + proxy.getClass().getName());
System.out.println("父类: " + proxy.getClass().getSuperclass().getName());
System.out.println("是否继承自UserService: " + UserService.class.isAssignableFrom(proxy.getClass()));
System.out.println("\n3. 调用普通方法");
proxy.addUser("张三");
System.out.println("\n4. 调用有返回值的方法");
String user = proxy.getUser(1001);
System.out.println("主程序收到: " + user);
System.out.println("\n5. 调用final方法(不会被代理增强)");
proxy.finalMethod();
System.out.println("\n6. 测试方法过滤");
try {
// 尝试调用private方法(会报错)
// proxy.privateMethod(); // 编译错误
// 尝试调用static方法
UserService.staticMethod(); // 正常调用,但不会被代理
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
}
System.out.println("\n7. 查看代理对象的实际类型");
System.out.println("生成的代理类名: " + proxy.getClass().getName());
System.out.println("方法列表:");
for (java.lang.reflect.Method method : proxy.getClass().getDeclaredMethods()) {
System.out.println(" - " + method.getName() +
" (来自: " + method.getDeclaringClass().getSimpleName() + ")");
}
}
}
第六步:深入了解CGLIB生成的类
java
// 5. 查看CGLIB生成的字节码
import net.sf.cglib.core.DebuggingClassWriter;
public class CglibDeepDive {
public static void main(String[] args) {
// 保存CGLIB生成的类文件到磁盘
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./cglib-classes");
// 创建代理
UserService proxy = CglibProxyFactory.createProxy(UserService.class);
// 调用方法
proxy.addUser("李四");
System.out.println("\n=== 生成的类文件已保存到 ./cglib-classes ===");
System.out.println("你可以用反编译工具查看这些文件:");
System.out.println("1. UserService$$EnhancerByCGLIB$$xxxxxxxx.class - 代理类");
System.out.println("2. UserService$$FastClassByCGLIB$$xxxxxxxx.class - 快速调用类");
System.out.println("3. CglibInterceptor$$FastClassByCGLIB$$xxxxxxxx.class");
}
}
第七步:查看生成的代理类(反编译结果)
java
// 这是CGLIB生成的代理类的伪代码(实际是字节码,这里用Java表示)
public class UserService$$EnhancerByCGLIB$$a1b2c3d4 extends UserService {
// 生成的字段
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$addUser$0$Method;
private static final MethodProxy CGLIB$addUser$0$Proxy;
static {
// 初始化Method和MethodProxy
CGLIB$addUser$0$Method = UserService.class.getMethod("addUser", String.class);
CGLIB$addUser$0$Proxy = MethodProxy.create(
UserService.class,
UserService$$EnhancerByCGLIB$$a1b2c3d4.class,
"addUser",
"(Ljava/lang/String;)V",
"CGLIB$addUser$0"
);
}
// 重写父类方法
public final void addUser(String name) {
MethodInterceptor interceptor = this.CGLIB$CALLBACK_0;
if (interceptor != null) {
// 调用拦截器
interceptor.intercept(this,
CGLIB$addUser$0$Method,
new Object[]{name},
CGLIB$addUser$0$Proxy);
} else {
// 直接调用父类
super.addUser(name);
}
}
// CGLIB生成的方法(用于快速调用)
public void CGLIB$addUser$0(String name) {
super.addUser(name); // 直接调用父类,没有增强!
}
// 重写其他方法...
public final String getUser(int id) {
// 类似实现...
}
}
第八步:性能对比测试
java
// 6. CGLIB vs JDK性能对比
public class ProxyPerformanceTest {
interface IUserService {
String getUser(int id);
}
static class UserServiceImpl implements IUserService {
public String getUser(int id) {
return "User" + id;
}
}
static class UserServiceConcrete {
public String getUser(int id) {
return "User" + id;
}
}
public static void main(String[] args) {
int iterations = 10_000_000;
System.out.println("性能对比测试 (迭代次数: " + iterations + ")");
// 1. 直接调用
UserServiceConcrete direct = new UserServiceConcrete();
long start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
direct.getUser(i);
}
System.out.println("直接调用耗时: " + (System.currentTimeMillis() - start) + "ms");
// 2. CGLIB代理调用
UserServiceConcrete cglibProxy = CglibProxyFactory.createProxy(UserServiceConcrete.class);
start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
cglibProxy.getUser(i);
}
System.out.println("CGLIB代理调用耗时: " + (System.currentTimeMillis() - start) + "ms");
// 3. JDK动态代理调用
IUserService jdkProxy = (IUserService) java.lang.reflect.Proxy.newProxyInstance(
ProxyPerformanceTest.class.getClassLoader(),
new Class[]{IUserService.class},
new java.lang.reflect.InvocationHandler() {
UserServiceImpl target = new UserServiceImpl();
public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}
);
start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
jdkProxy.getUser(i);
}
System.out.println("JDK代理调用耗时: " + (System.currentTimeMillis() - start) + "ms");
}
}
三、CGLIB关键特性总结
1. 继承方式
java
// CGLIB生成的代理类继承目标类
public class ProxyClass extends TargetClass {
// 重写所有非final方法
}
2. 方法调用优化
java
// 使用MethodProxy,比反射快
proxy.invokeSuper(obj, args); // 直接调用父类方法
// vs JDK的反射调用
method.invoke(target, args); // 反射调用,较慢
3. 限制
- 不能代理final方法
- 不能代理private方法
- 不能代理static方法
- 需要目标类有无参构造器
4. Spring中的使用
java
// Spring AOP的配置
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用CGLIB
// 或者
<aop:aspectj-autoproxy proxy-target-class="true"/>
四、运行结果示例
======= CGLIB动态代理演示 =======
1. 创建CGLIB代理对象
2. 查看代理对象信息
代理对象类名: UserService$$EnhancerByCGLIB$$12345678
父类: UserService
是否继承自UserService: true
3. 调用普通方法
【CGLIB代理】开始执行方法: addUser
【CGLIB代理】前置处理,参数: [张三]
真实操作:添加用户 张三
【CGLIB代理】后置处理,返回值: null
【CGLIB代理】方法耗时: 2ms
4. 调用有返回值的方法
【CGLIB代理】开始执行方法: getUser
【CGLIB代理】前置处理,参数: [1001]
真实操作:查询用户 1001
【CGLIB代理】后置处理,返回值: 用户1001
【CGLIB代理】方法耗时: 1ms
主程序收到: 用户1001
5. 调用final方法(不会被代理增强)
真实操作:这是一个final方法,不能被代理
这就是CGLIB动态代理的核心原理和实现方式!
看完这3个demo,我们可以理解一下,所谓的代理,就是在原来类的方法的基础上,给方法增加更多的能力和信息。作为一个新的类。也就是中间层和代理