代理模式(Proxy Pattern)为其他对象提供一种代理以控制对这个对象的访问,属于结构型模式。
主要解决在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
想在访问一个类时做一些控制。
增加中间层
核心思想:
1.提供一个抽象的行为(抽象类或者接口)
2.代理类和被代理对象都实现抽象的行为
3.代理类拥有被代理对象的引用
4.访问代理类
核心角色:
Image接口:
/**
* <p>
* 图片接口
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public interface Image {
/**
* 显示方法
*/
void display();
}
具体的RealImage对象
/**
* <p>
* 具体实现类
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
代理对象ProxyImage
/**
* <p>
* 代理类,代理具体的RealImage对象,在访问RealImage对象时,通过代理类处理
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
}
}
在执行目标方法前后执行其他的业务逻辑
代理主题角色类ISubject
/**
* <p>
* 代理主题角色类
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public interface ISubject {
void request();
}
真实主题角色类RealSubject
/**
* <p>
* 真实主题角色类
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public class RealSubject implements ISubject{
@Override
public void request() {
System.out.println("real service is called.");
}
}
代理主题角色类ProxySubject
/**
* <p>
* 代理主题角色类
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public class ProxySubject implements ISubject {
private ISubject subject;
public ProxySubject(ISubject subject) {
this.subject = subject;
}
@Override
public void request() {
before();
subject.request();
after();
}
private void before() {
System.out.println("called request before.");
}
private void after() {
System.out.println("called request after.");
}
}
测试客户端
/**
* <p>
* 测试客户端
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public class ProxySubjectDemo {
public static void main(String[] args) {
ISubject subject = new ProxySubject(new RealSubject());
subject.request();
}
}
运行结果:
我们用一个媒婆例子来实现
public interface IPerson {
void findLove();
}
/**
* <p>
* 具体的媒婆
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-10-27
*/
public class JdkMeipo implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target){
this.target = target;
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target, args);
after();
return null;
}
private void after() {
System.out.println("双方同意,开始交往");
}
private void before() {
System.out.println("我是媒婆,已经收集到你的需求,开始物色");
}
}
/**
* <p>
*
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-10-27
*/
public class Zhangsan implements IPerson{
@Override
public void findLove() {
System.out.println("张三要求:肤白貌美大长腿");
}
}
/**
* <p>
* 测试客户端
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-10-27
*/
public class Test {
public static void main(String[] args) {
JdkMeipo jdkMeipo=new JdkMeipo();
Zhangsan zhangsan=(Zhangsan) jdkMeipo.getInstance(new Zhangsan());
zhangsan.findLove();
}
}
运行结果:
import java.lang.reflect.Method;
/**
* <p>
* Cglib的媒婆类
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-10-27
*/
public class CglibMeipo implements MethodInterceptor {
private IPerson target;
public Object getInstance(Class<?> clazz) throws Exception {
//相当于Proxy,代理的工具类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o, objects);
after();
return obj;
}
private void before(){
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after(){
System.out.println("OK的话,准备办事");
}
}
/**
* <p>
* 测试客户端
* </p>
*
* @author shiqi
* @version 1.0.0
* @createTime 2023-12-29
*/
public class CglibProxyTest {
public static void main(String[] args) throws Exception {
CglibMeipo cglibMeipo = new CglibMeipo();
Zhangsan zhangsan = (Zhangsan) cglibMeipo.getInstance(Zhangsan.class);
zhangsan.findLove();
}
}
CglibProxy和JdkProxy都是Java中用于实现代理模式的两种不同的方式。它们之间的主要区别在于代理的实现方式和对代理目标的要求。
基于继承 vs 基于接口:
CglibProxy使用的是基于继承的代理方式。它通过创建目标类的子类来实现代理。
JdkProxy使用的是基于接口的代理方式。它要求目标类必须实现一个接口,然后通过动态生成实现该接口的代理类。
代理类的生成方式:
CglibProxy通过字节码操作,在运行时动态生成目标类的子类,继承目标类,并重写需要代理的方法。
JdkProxy使用Java的动态代理机制,通过java.lang.reflect.Proxy和InvocationHandler接口来生成代理类,该代理类实现了目标接口,并将方法调用委托给InvocationHandler的实现。
性能:
由于CglibProxy是通过生成目标类的子类,因此在性能上可能会比JdkProxy略慢,尤其是对于目标类的方法调用。
JdkProxy相对来说更轻量,因为它是基于接口的代理,不需要生成子类。
应用场景:
CglibProxy适用于那些没有实现接口的类的代理,因为它是基于继承的。
JdkProxy适用于那些实现了接口的类的代理,且它更符合Java的设计哲学,推崇面向接口编程。