代理模式是一种常用的设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理模式就像是一个中间人,客户端通过代理来间接访问目标对象,可以在不修改目标对象的基础上,对目标对象的功能进行增强或扩展。代理模式主要分为静态代理和动态代理,本文将详细探讨这两种代理模式。
本文目录
- 一、静态代理
- 1. 代码实现
- 2. 优缺点
- 二、动态代理
- 1. JDK动态代理实现
- 2. CGLIB动态代理
一、静态代理
静态代理是指在编译时就已经确定代理类和目标类的关系。代理类和目标类都需要实现相同的接口,代理类中持有目标类的引用,在代理类的方法中调用目标类的相应方法,并可以在调用前后添加额外的逻辑。
1. 代码实现
// 定义接口
interface UserService {
void addUser();
void deleteUser();
}
// 实现类
class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
// 静态代理类
class UserServiceProxy implements UserService {
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void addUser() {
System.out.println("添加用户前的日志记录");
target.addUser();
System.out.println("添加用户后的日志记录");
}
@Override
public void deleteUser() {
System.out.println("删除用户前的日志记录");
target.deleteUser();
System.out.println("删除用户后的日志记录");
}
}
public class StaticProxy {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = new UserServiceProxy(target);
proxy.addUser();
System.out.println("-------------------");
proxy.deleteUser();
}
}
在代理类的方法中,调用
目标对象的方法前后
添加了日志记录的逻辑
2. 优缺点
- 优点:实现简单,易于理解,在编译时就可以确定代理关系,性能相对较高。
- 缺点:代理类和目标类必须实现相同的接口,当接口方法发生变化时,代理类和目标类都需要修改。而且如果需要代理多个不同的目标类,就需要为每个目标类创建一个对应的代理类,代码会变得冗余。
二、动态代理
动态代理是指在运行时动态生成代理类,而不需要在编译时就确定代理类的代码。Java提供了两种实现动态代理的方式:JDK 动态代理和 CGLIB 动态代理。
1. JDK动态代理实现
JDK 动态代理是基于接口的动态代理,它使用 java.lang.reflect.Proxy
类和 java.lang.reflect.InvocationHandler
接口来实现。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface UserService {
void addUser();
void deleteUser();
}
class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
// 自定义InvocationHandler
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + " 方法调用前的日志记录");
Object result = method.invoke(target, args);
System.out.println(method.getName() + " 方法调用后的日志记录");
return result;
}
}
public class JdkDynamicProxy {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(target);
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.addUser();
System.out.println("-------------------");
proxy.deleteUser();
}
}
这种方式不需要为每个目标类创建代理类,只需要实现
InvocationHandler
接口,就可以为多个目标类提供代理服务。只能代理实现了接口的类,不能代理没有实现接口的类。
2. CGLIB动态代理
CGLIB 动态代理是基于继承的动态代理,可以代理没有实现接口的类。CGLIB是一个强大的、高性能的代码生成库,通过继承目标类来生成代理类。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 目标类
class UserService {
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
}
}
// 自定义MethodInterceptor
class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method.getName() + " 方法调用前的日志记录");
Object result = proxy.invokeSuper(obj, args);
System.out.println(method.getName() + " 方法调用后的日志记录");
return result;
}
}
public class CglibDynamicProxy {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new MyMethodInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.addUser();
System.out.println("-------------------");
proxy.deleteUser();
}
}
可以代理没有实现接口的类,灵活性更高,但是由于是基于继承实现的,所以不能代理 final
类和 final
方法。
← 上一篇 Java进阶——常用类及常用方法详解 |
记得点赞、关注、收藏哦!
| 下一篇 Java进阶——数组超详细整理 → |