Java基础之静态代理和动态代理
一、静态代理
定义:
代理类与被代理类在编译期就已确定,代理类需要手动编写并实现与被代理类相同的接口
1.核心角色:
-
Subject(抽象主题):定义业务方法的接口
-
RealSubject(真实主题):实现接口的具体业务类
-
Proxy(代理类):实现相同接口,持有真实主题的引用
2.为什么需要静态代理?
在已经完成的代码中,我们需要对完成的业务进行增强。这时我们又不想改动代码,已经写好的业务代码所以这是我们需要静态代理。
3.代码:
package 静态代理;public interface UserService {public void FindName();
}
package 静态代理;public class UserServiceimpl implements UserService {@Overridepublic void FindName() {System.out.println("正在查找请稍等");}}
package 静态代理;public class Proxyclass implements UserService {private UserServiceimpl userserviceimpl=new UserServiceimpl();@Overridepublic void FindName() {System.out.println("支付完成");userserviceimpl.FindName();}}
package 静态代理;public class TestApp {public static void main(String[] args) {UserService userServie1=new UserServiceimpl();userServie1.FindName();System.out.println("*************************************");UserService userServie2=new Proxyclass();userServie2.FindName();}}
4.执行流程图
5.运行结果:
二、动态代理
在面向对象开发中,动态代理是一种强大的技术手段,它允许我们在运行时动态创建代理对象,实现对目标方法的增强和拦截。与静态代理相比,动态代理具有以下显著优势:
-
代码解耦:将核心业务逻辑与横切关注点(如日志、事务、权限控制)分离
-
灵活扩展:无需为每个目标类编写代理类,减少重复代码
-
运行时决策:代理逻辑可以根据运行时条件动态调整
1. 核心组件
-
java.lang.reflect.Proxy
:负责生成代理类 -
java.lang.reflect.InvocationHandler
:方法调用处理器接口
2. 实现步骤图解
[客户端] -> [代理对象] -> [InvocationHandler] -> [目标对象]
3. 代码实现解析
package jdk动态代理;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class UserServiceimpl_Proxy_Dynamic implements InvocationHandler {private Object object;public Object get (Object o ) {this.object=o;return Proxy.newProxyInstance(this.object.getClass().getClassLoader(), this.object.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {////对象proxy一般用不到,method是被代理对象的方法,args参数System.out.println("动态代理增强了方法");return method.invoke(this.object, args);//前面是外界获取的方法,args参数}
}
package 静态代理;import jdk动态代理.UserServiceimpl_Proxy_Dynamic;public class TestApp {public static void main(String[] args) {UserService userServie1=new UserServiceimpl();userServie1.FindName();System.out.println("*************************************");UserService userServie2=new Proxyclass();userServie2.FindName();System.out.println("下面是动态代理方法*****************************");UserServiceimpl_Proxy_Dynamic userServiceimpl_proxy_dynamic=new UserServiceimpl_Proxy_Dynamic();UserService userService=(UserService) userServiceimpl_proxy_dynamic.get(userServie1);userService.FindName();}}
4. 关键参数说明
参数 | 作用说明 |
---|---|
ClassLoader | 定义代理类的加载器,通常使用目标类的类加载器 |
Class<?>[] interfaces | 代理类要实现的接口列表,决定代理对象支持哪些方法 |
InvocationHandler | 方法调用处理器,所有代理方法调用都会路由到该接口的invoke方法 |
5.运行结果:
6.代理方案对比
特性 | 静态代理 | JDK动态代理 | CGLIB代理 |
---|---|---|---|
实现方式 | 手动编写代理类 | 接口代理 | 子类继承 |
编译期处理 | 需要 | 不需要 | 不需要 |
执行效率 | 高 | 中等(反射调用) | 较高(ASM生成字节码) |
目标类要求 | 无特殊要求 | 必须实现接口 | 不能是final类 |
方法拦截范围 | 显式实现的接口方法 | 接口方法 | 所有非final方法 |
7.实践建议
-
优先选择JDK动态代理:当目标类已实现接口时
-
合理使用缓存:对重复创建的代理对象进行缓存
-
异常处理:在invoke方法中妥善处理异常
-
组合使用:结合模板方法模式实现通用代理逻辑
-
性能监控:在关键路径上记录代理耗时