代理模式的理解(以静态代理为例)
代理模式可以看作对目标类的包装,1. 目标实例作为代理实例的属性(即绑定),2. 代理类的接口和目标类的接口是对接的(比如目标类实现了代理类的接口),3. 其次代理类可以实现额外的功能。
- 案例:创建多线程中,Thread类就是代理类,它不但使用了执行了当前实例的功能,而且做了线程管理等扩展。作为开发者,我们不需要操心如何管理线程等细节,就可以实现多线程执行。
静态代理的缺点:代理类和被代理类都在编译期间被确定下来,不利于程序的进一步扩展,比如被代理类越多就需要越多的代理类。
动态代理特点:在运行期才确定代理类和被代理类,并且一个代理类就可以完成全部的代理工作。(通过反射实现,解决静态代理的缺点)
下图中。在编译阶段,通用代码的逻辑实现是确定的,而部分逻辑实现是不确定的,当运行阶段时,我们才确定逻辑实现。
代码
需求:在排序任务中,具体使用什么排序方法是随机的,但是其他代码部分是通用的。
下面代码放置于包 com.xj.java下,执行SortTask.java文件。 SortTask.java是使用动态代理实现的任务逻辑代码 , Sort.java是具体排序方法的实现,Util.java是通用代码的实现。
整体逻辑是,我希望在排序任务的处理中,通用代码是固定的,但是排序的核心算法是动态选择的。 核心代码块即class ProxyFactory
和class MyInvocationHandler implements InvocationHandler
,因为它们解决了两个实现动态代理的关键问题(见下SortTask.java)。
Sort.javaSortTask.javaUtil.java
SortTask.java
要想实现动态代理,注意下面解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。class ProxyFactory
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。class MyInvocationHandler implements InvocationHandler
package com.xj.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Random;
/**
* @author jia
* @create 2021-12-22 2:49 下午
*
* 要想实现动态代理,需要解决的问题?
* 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
* 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
*/
public class SortTask {
public static void main(String[] args) {
// 随机选择排序的方法
Sort proxyInstance = null;
int t = new Random().nextInt(2);
switch (t) {
case 0:
proxyInstance = (Sort)ProxyFactory.getProxyInstance(new QuickSort());
case 1:
proxyInstance = (Sort)ProxyFactory.getProxyInstance(new MergeSort());
}
// 执行排序任务
proxyInstance.sort();
}
}
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){// obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
// 当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
class MyInvocationHandler implements InvocationHandler {
private Object obj;
public void bind(Object obj){
this.obj = obj;
} // 赋值被代理类的实例
// 当执行"代理类的对象.方法a"时,就会自动的调用如下的方法:invoke() 解决问题二
// 本质是通过反射来调用被代理类的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Util util = new Util(); // 在AOP设计模式中,可以额外执行一些通用方法
util.method1();
// 核心处理过程
Object returnValue = method.invoke(obj,args);
util.method2();
//返回invoke()的返回值。
return returnValue;
}
}
这是排序任务的通用方法1 执行归并排序 这是排序任务的通用方法2
Sort.java
package com.xj.java;
/**
* @author jia
* @create 2021-12-22 3:09 下午
*/
public interface Sort {
public void sort();
}
class QuickSort implements Sort {
@Override
public void sort(){
System.out.println("执行快速排序");
}
}
class MergeSort implements Sort{
@Override
public void sort(){
System.out.println("执行归并排序");
}
}
Util.java
package com.xj.java;
/**
* @author jia
* @create 2021-12-22 2:51 下午
*/
public class Util {
public void method1(){
System.out.println("这是排序任务的通用方法1");
}
public void method2(){
System.out.println("这是排序任务的通用方法2");
}
}