目录
什么是代理模式?
代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。代理模式类似于生活中的中介。
代理模式分为静态代理和动态代理。
代理模式的三要素:
1、真实对象
2、代理对象
3、代理对象和真实对象都要实现的接口
静态使用场景--多线程
思考: 为什么开启一个新线程使用的是start()方法而不直接使用run()方法呢?
public class Demo01 {
public static void main(String[] args) {
Thread t1 = new Thread(new RImpl());
t1.start();
}
class RImpl implements Runnable{
@Override
public void run() {
System.out.println("RImpl的run方法");
}
}
接下来对源码分析
- Thread 源码的相关内容如下:
public class Thread implements Runnable {
public Thread(Runnable target) { // Thread t1 = new Thread(new RImpl());
this(null, target, "Thread-" + nextThreadNum(), 0);
}
public synchronized void start() {
start0();
}
private native void start0();
@Override
public void run() {
if (target != null) { //构造器中 : target = new RImpl()
target.run();
}
}
}
-
先看Thread类中的start()方法,下面是去除了多余部分的源码。实际上创建一个线程靠的是本地方法 start0(),它是c/c++写的涉及操作系统的方法。
public synchronized void start() { // t1.start();
start0();
//private native void start0(); 本地方法,由jvm调用,和操作系统相关,由它来创建一个线程
}
- 再看Thread类中的run方法:它实际上是在start0()创建新线程之后被调用的, target = new RImpl() , 因此实际上调用System.out.println("RImpl的run方法"); 的还是 RImpl的实例对象自己,这就是一个真实的对象。
- Thread t1 = new Thread(new RImpl()); 中 t1 就是一个代理对象,它实际上就是一个增强的作用。
@Override
public void run() {
if (target != null) {
target.run();
}
}
- 还需要注意的是:调用start0之后线程的状态是RUNNABLE,并不代表线程立马执行
静态代理优缺点:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
动态代理:
在动态代理中我们不需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。
案例:
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
@SuppressWarnings("all") // 压制警告
List obj = (List<String>) Proxy.newProxyInstance(
Demo.class.getClassLoader(),
new Class[]{List.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Object proxy ,不能使用,因为代理对象调用任何方法都会执行上面invoke,造成递归
//Object[] args 方法的参数
long start = System.currentTimeMillis();
if (method.getName().equals("remove")) {
System.out.println("发现remove方法,进行拦截");
return null; //remove方法的返回值是String ,所以返回值为null
}
Object ret = method.invoke(list, args);
long end = System.currentTimeMillis();
System.out.println(method.getName()+" " + (end - start)); //方法增强,输出程序运行的时间
return ret;
}
}
);
//代理对象调用方法,先把代理对象强转成ArrayList 否则无法调用方法
obj.add("刘备");
obj.add("张飞");
obj.add("关羽");
obj.add("刘备");
obj.remove(3);
System.out.println(list);
}
}
动态代理优缺点:
优点:相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。可以对某些功能进行拦截或者增强。
缺点:仅支持interface代理
应用场景:支付功能后的短信发送