大家可能会有这样的经历,想买某样国外商品,可自己又不能去国外,这时可能会找代购帮忙购买,你只需要将想买的东西告诉代购,由他去和国外商家购买,而你不需要直接和国外商家交流。类似的这种操作,在程序世界里,叫做代理模式
代理模式(Proxy Pattern):给某个对象提供一个代理,并且由代理对象控制对原对象的引用。代理模式是一种对象结构型模式
完成代理模式需要3个角色
抽象角色(Subject):声明了真实角色和代理角色的共同接口,客户端需要针对抽象角色进行编程
真实角色(RealSubject):定义了代理角色所代表的真实对象,实现了真实的业务
代理角色(Proxy):内部包含了对真实角色的引用,可以在引用的真实角色操作之前或之后进行其他操作,以达到增强的效果
代理模式可以根据代理类的创建时间分为静态代理和动态代理
代理类在程序运行前已经将代码编写在程序中,称为静态代理
代理类在程序运行时被创建,这种代理方式称为动态代理。在 java 中实现动态代理有两种方式,JDK 动态代理和 CGlib 动态代理
下面代码演示代理模式
静态代理
定义抽象角色
package com.design.structural.proxy.staticproxy;
/**
* 抽象角色
*/
public interface Subject {
void request();
}
定义真实角色
package com.design.structural.proxy.staticproxy;
/**
* 真实角色
*/
public class RealSubject implements Subject{
@Override
public void request() {
System.out.println("真实角色方法调用");
}
}
定义代理角色
package com.design.structural.proxy.staticproxy;
/**
* 代理角色
*/
public class Proxy implements Subject{
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
System.out.println("真实角色方法调用前操作");
subject.request();
System.out.println("真实角色方法调用后操作");
}
}
类图如下
测试调用
package com.design.structural.proxy.staticproxy;
/**
* 代理模式(静态代理)
*/
public class TestMain {
public static void main(String[] args) {
Subject subject = new RealSubject();
Proxy proxy = new Proxy(subject);
proxy.request();
}
}
结果如下
动态代理
jdk 动态代理
定义抽象角色
package com.design.structural.proxy.dynamicproxy.jdkproxy;
/**
* 抽象角色
*/
public interface Subject {
void proxyMethod();
}
定义真实角色
package com.design.structural.proxy.dynamicproxy.jdkproxy;
/**
* 真实角色
*/
public class RealSubject implements Subject{
@Override
public void proxyMethod() {
System.out.println("被代理的方法执行");
}
}
定义代理角色
package com.design.structural.proxy.dynamicproxy.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理角色
*/
public class JdkDynamicProxy implements InvocationHandler {
private Subject subject;
public JdkDynamicProxy(Subject subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("被代理的方法执行前操作");
Object obj = method.invoke(subject, args);
System.out.println("被代理的方法执行后操作");
return obj;
}
}
类图如下
测试调用
package com.design.structural.proxy.dynamicproxy.jdkproxy;
import java.lang.reflect.Proxy;
/**
* jdk动态代理
*/
public class TestMain {
public static void main(String[] args) {
Subject subject = (Subject) Proxy.newProxyInstance(
TestMain.class.getClassLoader(),
new Class[]{Subject.class},
new JdkDynamicProxy(new RealSubject()));
subject.proxyMethod();
}
}
结果如下图
cglib 动态代理
定义真实角色
package com.design.structural.proxy.dynamicproxy.cglibproxy;
/**
* 真实角色
*/
public class RealSubject {
public void proxyMethod(){
System.out.println("被代理的方法执行");
}
}
定义代理角色
package com.design.structural.proxy.dynamicproxy.cglibproxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 代理角色
*/
public class CglibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("被代理的方法执行前操作");
Object res = methodProxy.invokeSuper(obj, args);
System.out.println("被代理的方法执行后操作");
return res;
}
}
类图如下
测试调用
package com.design.structural.proxy.dynamicproxy.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
/**
* cglib动态代理
*/
public class TestMain {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new CglibDynamicProxy());
RealSubject realSubject = (RealSubject) enhancer.create();
realSubject.proxyMethod();
}
}
调用结果
如果读者想了解JDK 动态代理和 CGlib 动态代理的更多内容,可以参考下面两篇文章
JDK 动态代理:https://blog.csdn.net/wsjzzcbq/article/details/90116215
CGLIB 动态代理:https://blog.csdn.net/wsjzzcbq/article/details/90182495
代理模式总结:
优点:将代理对象与真实被调用的目标对象分离;降低系统耦合度;控制对一个对象的访问;增强目标对象
缺点:造成系统设计中类的数目增加;客户端和目标对象之间增加了代理对象,将导致请求处理速度变慢;增加系统复杂度
适用场景:需要控制一个对象的访问时;需要为一个对象提供额外的操作,以增强目标对象;