代理模式
参考文档:http://c.biancheng.net/view/1359.html
代理模式是常用的结构型设计模式之一,它为对象的间接访问提供了一个解决方案,可以对对象的访问进行控制。
在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。
在软件设计中,使用代理模式的例子也很多,例如,要访问的远程对象比较大(如视频或大图像等),其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象,如某单位的内部数据库等。
代理模式的定义与特点
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
代理模式的主要优点有:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
其主要缺点是:
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;
代理模式的结构与实现
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。
1. 模式的结构
代理模式的主要角色如下。
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
代理模式可以分为静态代理,和动态代理
静态代理
1.生成代理类, 2代理关系与委托关系在运行前确定 由程序员创建或工具生成代理类的源码,再编译代理类。 所谓静态也就是在程序运行前就已经存在代理类的字节码文件, 代理类和委托类的关系在运行前就确定了
>>>静态代理demo
step1 委托类和为委托类接口
委托类接口
package java_basic.stu_design_mode.stu_proxy.static_proxy;
public interface Subject {
String say(String msg);
int calculate(int a,int b);
}
委托类
package java_basic.stu_design_mode.stu_proxy.static_proxy;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class SubjectImpl implements Subject {
private String name;
private String[] hobby;
public SubjectImpl() {
}
@Override
public String say(String msg) {
System.out.println("my name is "+name);
return msg;
}
@Override
public int calculate(int a, int b) {
System.out.println("my hobby is "+ JSON.toJSON(hobby).toString());
return a+b;
}
}
step2 代理类
package java_basic.stu_design_mode.stu_proxy.static_proxy;
public class SubjectProxy extends SubjectImpl {
Subject subject;
public SubjectProxy(Subject subject) {
this.subject = subject;
}
@Override
public String say(String msg) {
System.out.println("say before");
//super.say("");
String res = subject.say(msg);
System.out.println("say after");
return res;
}
@Override
public int calculate(int a, int b) {
System.out.println("calculate before");
int res = subject.calculate(a,b);
System.out.println("calculate after");
return res;
}
}
step3 测试类
package java_basic.stu_design_mode.stu_proxy.static_proxy;
import org.junit.Test;
public class Main {
@Test
public void method() {
Subject sb = new SubjectImpl("小明",new String[]{"book","eat","fishing"});
Subject sbpy = new SubjectProxy(sb);
sbpy.calculate(1,6);
sb.calculate(1,6);
}
}
>>>动态代理,jdK动态代理和cglib动态代理
1.基于JDK的动态代理就需要知道两个类:1.InvocationHandler(接口)、2.Proxy(类) 还要知道JDK是基于接口的动态代理。jdk动态代理,是系统本身就有的。
2.cglib动态代理则不需要接口。cglib动态代理需要引入第三方库。
>>jdk动态代理demo
>step1 委托类,和委托类接口(必须的)
委托类接口
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.jdk_dynamic_proxy;
public interface Subject {
String showMessage(String msg);
int getScore(int a,int b);
}
委托类
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.jdk_dynamic_proxy;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
//委托类 要求委托类必须有接口,可以有多个
public class SubjectImpl implements Subject {
private String name;
@Override
public String showMessage(String msg) {
System.out.println("执行showMessage方法");
return msg;
}
@Override
public int getScore(int a, int b) {
System.out.println("执行getScore方法");
return a+b;
}
public void otherMethod(){
System.out.println("执行otherMethod");
}
}
>step2 代理类,代理类需要实现InvocationhHandler,重写invok方法。
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.jdk_dynamic_proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//代理类
public class SubjectProxy implements InvocationHandler {
private Subject subject;
public SubjectProxy(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---执行前---");
Object res = method.invoke(subject,args);
System.out.println("---执行后---");
return res;
}
}
>step3 调用,通过委托类的对象调用,现在通过代理对象调用
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.jdk_dynamic_proxy;
import org.junit.Test;
import java.lang.reflect.Proxy;
public class JDKDynimic {
@Test
public void method() {
SubjectImpl subject = new SubjectImpl("小明");
SubjectProxy subjectProxy = new SubjectProxy(subject);
Subject proxy = ( Subject)Proxy.newProxyInstance(subjectProxy.getClass().getClassLoader(),
subject.getClass().getInterfaces(),subjectProxy );
//调用时需要委托类的接口,可以使多个
System.out.println(proxy.getScore(3,5));
System.out.println(proxy.showMessage("hello world"));
}
}
>>cglib动态代理demo
不需要委托类的接口了
>step1 引入cglib的jar包(若是maven搜一下坐标也行)
>step2 委托类
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.cglib_dynamic_proxy;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Subject {
private String name;
public String showMessage(String msg){
return msg;
}
public int calculate(int a,int b){
return a*b;
}
}
>step3 方法拦截器
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.cglib_dynamic_proxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class HandleInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("------执行前------");
Object res = methodProxy.invokeSuper(o,objects);
if(res!=null){
System.out.println(res);
}
System.out.println("------执行后------");
return res;
}
}
>step 4 调用
package java_basic.stu_design_mode.stu_proxy.dynamic_proxy.cglib_dynamic_proxy;
import net.sf.cglib.proxy.Enhancer;
import org.junit.Test;
public class Main {
@Test
public void method() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Subject.class);
enhancer.setCallback(new HandleInterceptor());
Subject subject = (Subject) enhancer.create(new Class[]{String.class},new Object[]{"小明"});
subject.getName();
// enhancer.create(String.class,new Object[]{});
}
}
Subject subject = (Subject) enhancer.create(new Class[]{String.class},new Object[]{"小明"});
中的new Class[]{String.class},new Object[]{"小明"}类似反射调用构造函数。