一、静态代理
什么是代理
比如你要租房子,但是你没有时间去看房子,就把租房子的事情交给了女朋友的闺蜜来处理,然后你女朋友的闺蜜帮你租了一个两室一厅,开始了你们的故事。。。。
比如你想吃蛋炒饭,但是你不喜欢做饭,所以你把女朋友送去了新东方,学了几年厨师,然后你开始了永无休止的蛋炒饭生活。。。
比如你想买自由女神手里的冰激淋,但是她不卖给你,你就把钱给了太上老君,太上老君帮你去买自由女神的冰激淋。。。
总结下来就是你想要结果,但是不想参与过程,那么就可以使用代理模式,将这个具体过程委托给某一个角色,你只关注结果即可。
静态代理演示
先定义一个接口,描述下要做什么事情:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public interface Work {
/**
* 写代码
*/
void coding();
}
然后,描述一个真正能够做这个事情的角色:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public final class JavaWork implements Work{
@Override
public void coding() {
System.out.println("Java coding.....");
}
}
然后,描述一个不想干这个事情,但是有能力让别人干的角色:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public final class LeaderWork implements Work{
private JavaWork javaWork;
public LeaderWork(JavaWork work){
this.javaWork = work;
}
@Override
public void coding() {
javaWork.coding();
}
}
最后,通过一个简单的示例,看一下具体代理的过程:
public class SimpleStatic {
public static void main(String[] args) {
// 这是一个Java程序员
JavaWork javaWork = new JavaWork();
// 这是项目经理
LeaderWork leaderWork = new LeaderWork(javaWork);
// 公司安排项目经理实现一个Hello world,但是项目经理不会写,把coding的工作安排给了javaWork这个程序员
leaderWork.coding();
}
}
到这里,相信静态代理的大概玩法基本已经清晰了。
静态代理的优缺点
知道了静态代理是怎么回事以后,接下来探讨下静态代理为什么叫静态,有什么优劣?
优点一、可以隐藏具体实现细节
优点二、通过代理可以聚合复杂的内部实现
优点三、提高逻辑复用程度
缺点一、高耦合,接口变动会波及所有实现类
缺点二、如果Work
这个接口内部抽象方法特别多,代理的行为就会变的越来越重
缺点三、代理内部的关系维护很难实现动态切换,所以叫静态代理
二、动态代理
什么是动态代理
所谓的动态代理,实际上和静态代理大同小异,搞清楚动态
体现在什么环节就可以了。
那么,动态代理所描述的动态体现在哪里呢?主要体现在代理关系的维护上。
动态代理演示
首先,搞一个接口,描述下做什么事情:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public interface Work {
/**
* 写代码
*/
void coding();
}
然后,描述个能够做这个事情的角色:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public final class JavaWork implements Work{
@Override
public void coding() {
System.out.println("Java coding.....");
}
}
最后,搞一个能够动态分配工作的角色:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public final class WorkHandler implements InvocationHandler {
private Object target;
public WorkHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}
/**
* 售前团队
*/
private void before() {
System.out.println("工作没有被代理之前,售前先和你聊聊");
}
/**
* 售后团队
*/
private void after() {
System.out.println("工作被代理以后,售后和你聊聊");
}
}
接下来,准备一段测试代码:
/**
* @author zhangjian
* @version 1.0.0
* @date 2021/11/16
* @since 1.0.0
*/
public class SimpleDynamic {
public static void main(String[] args) {
// 找到一个程序员
JavaWork javaWork = new JavaWork();
// 找到这个程序员的领导
ClassLoader classLoader = javaWork.getClass().getClassLoader();
// 分析一下这个程序员都会什么开发语言
Class[] interfaces = javaWork.getClass().getInterfaces();
// 针对这个程序员制定一个工作流程
WorkHandler workHandler = new WorkHandler(javaWork);
// 制定工作计划,并按照工作流程分派给程序员
Work work = (Work) Proxy.newProxyInstance(classLoader, interfaces, workHandler);
// 程序员开始执行工作计划
work.coding();
}
}
补充内容
第一、在上述演示代码中,一些Java类做了final标记。final除了能够阻断类的继承关系以外,还有一个特别值得关注的问题就是能够规避类间关系检测,在类加载环节有提速的效果。
第二、在WorkHandler
中,我增加了before()
和after()
两个方法,用于模拟演示前置处理器和后置处理器,它不属于动态代理的内容。但是在动态代理中,经常这么玩。
第三、上文描述的动态代理实际上是基于JDK进行实现的,除此之外基于CGLIB的动态代理也是出镜频率很高的一种实现方式。