代理模式是一种结构型设计模式,它允许你提供一个代理对象,该对象可以控制对其他对象的访问。代理模式通过在代理对象和实际对象之间添加一个中间层,使得代理对象可以代表实际对象执行某些操作,从而实现对实际对象的间接访问。
代理模式的主要目的是在不改变原始对象的情况下,为其提供额外的功能、控制或保护。它可以在不直接访问实际对象的情况下,管理对象的创建、销毁、访问控制等。
代理模式涉及以下几个角色:
题目:假设你正在开发一个音乐播放器应用程序,你需要实现一个日志记录器,用于记录每次播放音乐的歌曲名称。使用代理模式来实现一个日志记录器,确保每次播放音乐时都能自动记录日志信息。
/**
* @author myf
* 抽象主题
*/
public interface MusicPlayer {
/**
* 播放
*
* @param songName
*/
void play(String songName);
}
/**
* @Author: myf
* @CreateTime: 2023-06-01 16:36
* @Description: AppleMusicPlayer 真实主题 苹果音乐播放器
*/
public class AppleMusicPlayer implements MusicPlayer {
@Override
public void play(String songName) {
System.out.println("苹果音乐播放器开始播放" + songName + "音乐");
}
}
/**
* @Author: myf
* @CreateTime: 2023-06-01 16:37
* @Description: AppleMusicPlayerProxy 代理 苹果音乐播放器代理类
*/
public class AppleMusicPlayerProxy implements MusicPlayer {
private static final Logger LOGGER = LoggerFactory.getLogger(AppleMusicPlayerProxy.class);
private AppleMusicPlayer appleMusicPlayer;
public AppleMusicPlayerProxy(AppleMusicPlayer appleMusicPlayer) {
this.appleMusicPlayer = appleMusicPlayer;
}
@Override
public void play(String songName) {
LOGGER.info("日志记录:苹果音乐播放器即将开始播放");
appleMusicPlayer.play(songName);
LOGGER.info("日志记录:苹果音乐播放器结束播放");
}
}
结果
public class ProxyClient {
public static void main(String[] args) {
AppleMusicPlayerProxy appleMusicPlayerProxy =
new AppleMusicPlayerProxy(new AppleMusicPlayer());
appleMusicPlayerProxy.play("七里香");
}
}
21:17:06.907 [main] INFO org.myf.designPattern.design.proxy.staticPattern.AppleMusicPlayerProxy - 日志记录:苹果音乐播放器即将开始播放
苹果音乐播放器开始播放七里香音乐
21:17:06.912 [main] INFO org.myf.designPattern.design.proxy.staticPattern.AppleMusicPlayerProxy - 日志记录:苹果音乐播放器结束播放
JDK 动态代理是在运行时期生成代理类的字节码。动态代理基于接口实现,通过反射和 InvocationHandler 接口来实现。在运行时,通过调用 Proxy.newProxyInstance 方法创建代理对象,传入被代理接口和调用处理器对象。当代理对象的方法被调用时,实际执行的是调用处理器的 invoke 方法,通过反射调用被代理对象的相应方法,并在前后添加额外的逻辑。
/**
* @Author: myf
* @CreateTime: 2023-06-01 16:40
* @Description: AppleMusicPlayerJdkProxy 基于jdk的苹果音乐播放器代理类
*/
public class AppleMusicPlayerJdkProxy implements InvocationHandler {
private static final Logger LOGGER =
LoggerFactory.getLogger(AppleMusicPlayerJdkProxy.class);
//传入被代理的对象也就是实际对象
private Object proxy;
//构造方法引入实际对象
public AppleMusicPlayerJdkProxy(Object proxy) {
this.proxy = proxy;
}
/**
*
* @param proxy jdk动态代理生成的代理对象
* @param method 我们所要调用的某个方法
* @param args 所要调用的方法的入参
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LOGGER.info("日志记录:苹果音乐播放器即将开始播放");
//传入实际对象,去执行实际对象的method,args是方法入参
method.invoke(this.proxy, args);
LOGGER.info("日志记录:苹果音乐播放器结束播放");
return null;
}
}
public class ProxyClient {
public static void main(String[] args) {
AppleMusicPlayerJdkProxy appleMusicPlayerJdkProxy = new
AppleMusicPlayerJdkProxy(new AppleMusicPlayer());
//ClassLoader对象,定义了由哪个类加载器来对生成的代理对象进行加载,
//Interface对象的数组,表示的是动态代理对象所要实现的接口
//InvocationHandler对象,表示的是动态代理对象在调用方法的时候,会关联到哪一个
//InvocationHandler对象上。
MusicPlayer musicPlayer = (MusicPlayer)
Proxy.newProxyInstance(MusicPlayer.class.getClassLoader(),
new Class[]{MusicPlayer.class}, appleMusicPlayerJdkProxy);
musicPlayer.play("暗香");
}
}
21:21:28.449 [main] INFO org.myf.designPattern.design.proxy.jdkPattern.AppleMusicPlayerJdkProxy - 日志记录:苹果音乐播放器即将开始播放
苹果音乐播放器开始播放暗香音乐
21:21:28.451 [main] INFO org.myf.designPattern.design.proxy.jdkPattern.AppleMusicPlayerJdkProxy - 日志记录:苹果音乐播放器结束播放
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
/**
* @Author: myf
* @CreateTime: 2023-06-01 17:17
* @Description: AppleMusicPlayerCglibProxy 基于cglib的苹果音乐播放器代理类
*/
public class AppleMusicPlayerCglibProxy implements MethodInterceptor {
private static final Logger LOGGER =
LoggerFactory.getLogger(AppleMusicPlayerCglibProxy.class);
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
//设置代理类的父类,即被代理的类
enhancer.setSuperclass(clazz);
//设置代理类的回调对象,即拦截器。
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
/**
* @param obj 代理对象即生成的代理类的实例
* @param method 被拦截的目标方法。
* @param args 目标方法的参数数组。
* @param proxy MethodProxy 对象,用于调用原始方法。
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
LOGGER.info("日志记录:苹果音乐播放器即将开始播放");
Object result = proxy.invokeSuper(obj, args);
LOGGER.info("日志记录:苹果音乐播放器结束播放");
return result;
}
}
public class ProxyClient {
public static void main(String[] args) {
AppleMusicPlayerCglibProxy appleMusicPlayerCglibProxy = new
AppleMusicPlayerCglibProxy();
AppleMusicPlayer cglibAppleMusicPlayer = (AppleMusicPlayer)
appleMusicPlayerCglibProxy.getProxy(AppleMusicPlayer.class);
cglibAppleMusicPlayer.play("花香");
}
}
21:39:22.930 [main] INFO org.myf.designPattern.design.proxy.cglibPattern.AppleMusicPlayerCglibProxy - 日志记录:苹果音乐播放器即将开始播放
苹果音乐播放器开始播放花香音乐
21:39:22.943 [main] INFO org.myf.designPattern.design.proxy.cglibPattern.AppleMusicPlayerCglibProxy - 日志记录:苹果音乐播放器结束播放