上文(设计模式-享元模式):https://blog.csdn.net/qq_16498553/article/details/106588851
背景
代理模式是什么?
代理模式可以干嘛?
源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
实现代码
静态代理
结果
JDK动态代理:
实现代码
结果
引入java包
实现代码
结果
最后
日常生活中,有非常多的代办、代处理,比如代找货源、代租房、代记、代办证件等,代办人就是这个代理的对象,通过代理人来达到办理的目的或结果,并且得到一样的结果。就比如:你想喝多了,回家找一个滴滴代驾,把车开到目的地,一样实现到达的结果是一样。
代理模式(Proxy Pattern)也叫委托模式,属于结构型模式,为其他对象提供一种代理以控制对这个对象的访问。代理分为静态代理,和动态代理。
静态代理:预先指定了代理与被代理都的关系,比如:一开始就知道代驾的是哪位师傅,男或女?
动态代理:待运行时才确定代理对象,并且代理对象是动态的;比如:等到代驾师傅到后才知道,原来是个女的,开车技术还蛮娴熟...
角色:
Subject(抽象主题角色):定义目标对象和代理对象的共同接口,这样可以在任何使用具体目标对象的地方使用代理对角。
Proxy(代理主题角色):也叫委托类,代理类。实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象。
RealSubject(真实主题角色):也称为委托角色或者被代理角色。定义了代理对象所代表的目标对象。
代理模式为对象提供一个代理的替色(代办)来控制这个对象的访问;
优点:
高拓展:修改代理角色不影响使用者,对于用户来说,代理对象是透明的。
隔离、低耦合:直接面对用户的是代理角色,所以起到一个很好的隔离作用,并且降低了与用户的耦合度,很好的遵循了:迪米特法则和隔离原则;
缺点:
增加代码复杂度:添加了代理,代码的复杂度相对来说更加复杂了;
处理速度变慢:由代理角色处理,所以导致流程增加了代理角色,增加了系统实现的复杂度。
个人理解:如代驾,喝高了,由于不想被交警拉去面壁思过(非直接面对)...,找一个司机帮你代驾,静态代理就是一开始就是确定的师傅;而动态代理,等到师傅来的时候你才知道是谁,男或女。
手动生成源代码,再对其进行编译。程序运行前.class文件就已经存在了。
/**
* @Auther: csh
* @Date: 2020/6/2 11:35
* @Description:抽象车(subject)
*/
public interface ICar {
//开车
void drive();
}
/**
* @Auther: csh
* @Date: 2020/6/2 11:36
* @Description:宝马车(RealSubject)
*/
public class BMWCar implements ICar {
//开车人名称
private String name;
public BMWCar(String name) {
this.name = name;
}
@Override
public void drive() {
System.out.println("驾驶宝马的人:"+name);
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 11:38
* @Description:代驾(Proxy)
*/
public class CarProxy implements ICar {
//宝马
private BMWCar bmwCar;
//代驾名称
private String proxyName;
public CarProxy(String proxyName) {
this.proxyName = proxyName;
}
@Override
public void drive() {
if(null==bmwCar){
bmwCar = new BMWCar(proxyName);
}
bmwCar.drive();
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 11:39
* @Description:代驾列子(静态代理)
*/
public class Client {
public static void main(String[] args) {
ICar car =new CarProxy("滴滴代驾");
car.drive();
}
}
驾驶宝马的人:滴滴代驾
(jdk动态代理只针对代理接口,并且类中必须要有一个接口,而不能针对这个类进行代理)
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
此方法的参数含义如下
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表当前执行方法传入的实参
返回值:表示当前执行方法的返回值
/**
* @Auther: csh
* @Date: 2020/6/2 11:35
* @Description:抽象车(subject)
*/
public interface ICar {
//开车
void drive();
}
/**
* @Auther: csh
* @Date: 2020/6/2 11:36
* @Description:宝马车(RealSubject)
*/
public class BMWCar implements ICar {
//开车人名称
private String name;
public BMWCar(String name) {
this.name = name;
}
@Override
public void drive() {
System.out.println("驾驶宝马的人:"+name);
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 16:22
* @Description:代理(Proxy)
*/
public class ProHandler implements InvocationHandler {
Object obj = null;
public ProHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是代理,正在驾驶");
Object invoke = method.invoke(obj, args);
System.out.println("到达目的地");
return invoke;
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 16:25
* @Description:jdk动态代理
*/
public class Client {
public static void main(String[] args) {
//代驾
BMWCar car = new BMWCar("滴滴代驾");
InvocationHandler proHandler = new ProHandler(car);
ICar bmwCar = (ICar) Proxy.newProxyInstance(BMWCar.class.getClassLoader(), BMWCar.class.getInterfaces(), proHandler);
bmwCar.drive();
}
}
我是代理,正在驾驶
驾驶宝马的人:滴滴代驾
到达目的地
CGLIB动态代理:
CGLIB即可以针对接口动态代理,又可以针对该类进行代理,并且在运行期间动态扩展类或接口,它的底层使用的是java字节码操作框架ASM实现。
CGLIB缺点:对于final方法,无法进行代理。
cglib
cglib-nodep
3.3.0
test
/**
* @Auther: csh
* @Date: 2020/6/2 11:35
* @Description:抽象车(subject)
*/
public interface ICar {
//开车
void drive();
}
/**
* @Auther: csh
* @Date: 2020/6/2 11:36
* @Description:宝马车(RealSubject)
*/
public class BMWCar implements ICar {
//开车人名称
private String name;
public BMWCar() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void drive() {
System.out.println("驾驶宝马的人:"+name);
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 17:31
* @Description:CGLIB拦截器
* 在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口
*/
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("被拦截");
Object invoke = methodProxy.invokeSuper(o, objects);
return invoke;
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 17:35
* @Description:代理工厂
*/
public class ProxyFacotory {
public static Object getcglibProxy(Object target){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibProxy());
Object targetProxy = enhancer.create();
return targetProxy;
}
}
/**
* @Auther: csh
* @Date: 2020/6/2 17:37
* @Description:cglib动态代理
* 区别于jdk代理在于
* 1.CGLIB可代理类,可JDK代理只能代理方法
* 2.CGLIB可以运行时动态增加类或方法,而JDK代理不能;
* 3.CGLIB不能代理final的方法,并且比JDK代理快;
*/
public class Client {
public static void main(String[] args) {
BMWCar car = (BMWCar)ProxyFacotory.getcglibProxy(new BMWCar());
car.setName("滴滴代驾");
car.drive();
}
}
被拦截
被拦截
驾驶宝马的人:滴滴代驾
代理模式,在各大开源项目中用得非常广泛,比如Spring AOP ,IOC ,当然代理模式的优秀主要在于,通过代理角色,可以隔离开内部信息,通过代理角色来达到想要的结果,并且很好的屏蔽了内部对外暴露的风险,很好的降低了系统的耦合度。