好记忆不如烂笔头,能记下点东西,就记下点,有时间拿出来看看,也会发觉不一样的感受.
在Java开发中,代理和动态代理是非常重要的概念,下面我将从实现核心代码、设计思路与实现逻辑、业务场景应用以及替代方案等方面对其进行详细解说。
代理与动态代理的概念
-
代理:指通过代理类来间接访问目标对象,代理类通常与目标对象实现相同的接口,可以在调用目标方法前后添加额外的逻辑,实现对目标对象的控制和增强。
-
动态代理:在运行时动态生成代理类的代理方式,具有更高的灵活性和扩展性,能够在不修改目标类代码的情况下,对目标类的方法进行增强或拦截。
JDK自带代理与动态代理的实现核心代码
-
静态代理:需要手动创建代理类,并实现与目标类相同的接口,在代理类中控制对目标类方法的访问。例如,业务接口为
BusinessService
,实现类为BusinessServiceImpl
,代理类BusinessServiceProxy
实现相同接口,并在方法中调用目标类方法,添加额外逻辑。 -
JDK动态代理:
-
核心类是
java.lang.reflect.Proxy
,用于动态生成代理类实例。 -
核心接口是
java.lang.reflect.InvocationHandler
,定义了代理类的通用方法,通过实现该接口可以定义代理行为。
-
JDK动态代理的设计思路与实现逻辑
-
设计思路:
-
面向接口编程,目标类和代理类实现相同接口,代理类控制对目标类方法的访问。
-
动态生成代理类,增强程序的灵活性和可扩展性。
-
将通用逻辑抽象到代理类中,在多个目标类间复用,实现代码复用和模块化设计。
-
-
实现逻辑:
-
调用
Proxy.newProxyInstance()
方法创建动态代理类实例,需指定类加载器、目标类实现的接口及InvocationHandler
实例。 -
在
InvocationHandler
的invoke()
方法中定义代理逻辑,如权限验证、日志记录等,再调用目标方法。 -
当调用代理类方法时,会调用
invoke()
方法,执行代理逻辑和目标方法。
-
业务场景中的应用
-
权限控制:在访问关键业务方法前,通过代理进行权限验证,确保用户有权限执行操作。
-
日志记录:在调用业务方法前后,添加日志记录逻辑,记录方法执行时间、参数及结果,方便问题追踪和分析。
-
事务管理:在调用数据库操作方法时,通过代理控制事务的开启、提交或回滚,确保数据完整性和一致性。
-
性能监控:在业务方法执行前后,添加性能监控逻辑,记录方法执行时间,分析系统性能瓶颈。
JDK动态代理的替代方案
-
CGLIB动态代理:
-
基于第三方库CGLIB,通过字节码技术动态生成目标类的子类作为代理类,无需目标类实现接口,适用性广。
-
性能较高,适合对性能敏感的场景,但生成子类可能带来一定风险,如破坏封装性。
-
-
JDK代理与CGLIB代理的结合:
-
先尝试使用JDK代理,若目标类未实现接口,则自动切换到CGLIB代理,兼顾灵活性和性能。
-
-
其他代理框架:Spring AOP等代理框架也提供了丰富的代理功能,可根据项目需求选择合适的框架。
代码呈现
-
静态代理:
-
// 接口 public interface UserService { void saveUser(String username); } // 真实实现类 public class UserServiceImpl implements UserService { @Override public void saveUser(String username) { System.out.println("保存用户: " + username); } } // 静态代理类 public class UserServiceProxy implements UserService { private UserService target; public UserServiceProxy(UserService target) { this.target = target; } @Override public void saveUser(String username) { System.out.println("前置处理..."); target.saveUser(username); System.out.println("后置处理..."); } } // 使用示例 public class Main { public static void main(String[] args) { UserService realService = new UserServiceImpl(); UserService proxy = new UserServiceProxy(realService); proxy.saveUser("张三"); } }
-
-
JDK动态代理:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkDynamicProxy {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理前置处理");
Object result = method.invoke(realService, args);
System.out.println("JDK动态代理后置处理");
return result;
}
}
);
proxy.saveUser("李四");
}
}
区别:
-
静态代理:简单但不够灵活
-
JDK动态代理:需要接口,性能较好