代理模式之动静态代理
静态代理
通过代理对象,去控制对真实对象的访问
例如: 经纪人, 租房的中介
代理模式的作用: 可以通过代理对象去控制真实对象中的方法,代理对象就可以具备调用真实对象的所有方法的调用控制权
我们就可以在调用方法之前做一些前置处理,之后做一些后置处理
举例:
租房: 1.看安居客app
2.到处走走看看
3.谈价钱…
中介来处理
存在真实对象的引用
1.看安居客app
2.到处走走看看
3.谈价钱…
4.过来交钱
5.后续合作
这些方法设计成为接口
为什么称为静态代理?
这里的代理对象由我们自己来实现的,而JDK中提供了一个类Proxy类能够动态地帮助我们创建代理对象或者代理类
Proxy.getProxyClass(loader, interfaces) 动态获取代理类
Proxy.newProxyInstance(loader, interfaces, h) 动态获取代理对象
举例代码如下
public class StaticProxyDemo {
public static void main(String[] args) {
// 创建真实对象
IStar ldh = new LdhStar();
IStar zbz = new ZbzStart();
// 创建静态代理对象
ProxyManager proxy = new ProxyManager(zbz);
proxy.confer();
proxy.signContact();
proxy.bookTicket();
proxy.sing();
proxy.collectMoney();
}
}
// 公共接口: 真实对象和代理对象都能够实现的方法
interface IStar {
void confer();
void signContact();
void bookTicket();
void sing();
void collectMoney();
}
// 真实对象
class LdhStar implements IStar {
@Override
public void confer() {
System.out.println("刘德华面谈");
}
@Override
public void signContact() {
System.out.println("刘德华签合同");
}
@Override
public void bookTicket() {
System.out.println("刘德华订机票");
}
@Override
public void sing() {
System.out.println("刘德华唱歌");
}
@Override
public void collectMoney() {
System.out.println("刘德华收钱");
}
}
class ZbzStart implements IStar {
@Override
public void confer() {
System.out.println("张柏芝面谈");
}
@Override
public void signContact() {
System.out.println("张柏芝签合同");
}
@Override
public void bookTicket() {
System.out.println("张柏芝订票");
}
@Override
public void sing() {
System.out.println("张柏芝唱歌");
}
@Override
public void collectMoney() {
System.out.println("张柏芝收钱");
}
}
// 静态代理类
class ProxyManager implements IStar {
// 真实对象的引用
private IStar star;
public ProxyManager() {
super();
}
public ProxyManager(IStar star) {
super();
this.setStar(star);
}
@Override
public void confer() {
System.out.println("经纪人面谈");
}
@Override
public void signContact() {
System.out.println("经纪人签合同");
}
@Override
public void bookTicket() {
System.out.println("经纪人订票");
}
@Override
public void sing() {
star.sing();
}
@Override
public void collectMoney() {
System.out.println("经纪人收钱");
}
public IStar getStar() {
return star;
}
public void setStar(IStar star) {
this.star = star;
}
}
动态代理
动态代理的本质就是在代理对象方法调用之前或者之后加入一些通用的方法
面向切面编程就是代理模式的应用,也是AOP的基础
面向切面编程是面向对象的一种方式,在代码的执行过程当中,动态嵌入其他代码,成为面向切面编程
常见的应用场景:
1.日志
2.事物
3.数据库操作
面向切面编程的几个概念:
AOP本质就是动态代理
1.切点(PointCut): 要对哪些连接点进行拦截的定义,即要添加代码的地方 例如info作为切点
2.连接点(JointPoint): 类里面可以被增强的方法,这些方法称为连接点 (例如: info run add 三个连接点)
3.增强(通知)(Advice): 指的是拦截到JoinPoint之后所要做的事情就是通知,即向切点插入的代码片段称为通知
通知的分类: 前置通知,后置通知,异常通知,最终通知,环绕通知(后面讲解)
4.目标对象(Target): 代理的目标对象,这里就是target
5.织入(Weaving): 是把增强应用到目标的过程,即Advice应用到Target的过程
6.代理(Proxy): 一个类被AOP织入增强后,就会产生一个结果代理类
7.引介: 引介是一种特殊的通知在不修改源代码的前提下,可以在运行时期为类动态地加入一些方法或者字段
举例代码如下
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
public static void main(String[] args) {
test1();
test2();
}
// 使用动态代理之前的做法
public static void test1() {
IDog dog = new GunDog();
DogUtils.method1();
dog.info();
DogUtils.method2();
DogUtils.method1();
dog.run();
DogUtils.method2();
}
// 代理之后的做法
public static void test2() {
IDog dog = new GunDog();
IDog proxy = (IDog) MyProxyFactory.getProxy(dog);
proxy.info();
proxy.run();
int result = proxy.add(10, 20);
System.out.println("result: " + result);
}
}
// 代理工厂
class MyProxyFactory {
public static Object getProxy(Object target) {
MyInvocationHandler handler = new MyInvocationHandler();
handler.setTarget(target);
// 通过真实对象实现的接口反推代理对象实现的接口
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
return proxy;
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/**
* proxy: 代理对象
* method: 方法对象,具体调用了哪个方法,就会将这个方法对象传递给我们
* args: 调用者调用的方法的参数也会传递给我们
*
* 代理对象调用任何一个方法,都会让invoke方法被回调
* 并且将调用的方法对象传递给method,将方法的参数传递给args
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName(); // info
Object result = null;
switch (methodName) {
case "info":
DogUtils.method1();
method.invoke(target, args);
DogUtils.method2();
break;
case "run":
DogUtils.method1();
method.invoke(target, args);
DogUtils.method2();
break;
case "add":
result = method.invoke(target, args);
if (args != null) {
for (Object obj : args) {
System.out.println("args: " + obj);
}
}
break;
default:
break;
}
// 如果一个方法的返回值为void,这里返回void,如果返回值不为void,就返回对应结果
return result;
}
}
// 创建一个公共接口
interface IDog {
void info();
void run();
int add(int a, int b);
}
// 猎狗
class GunDog implements IDog {
@Override
public void info() {
System.out.println("一只猎狗");
}
@Override
public void run() {
System.out.println("猎狗在跑");
}
@Override
public int add(int a, int b) {
return a + b;
}
}
class DogUtils {
public static void method1() {
System.out.println("========方法一=========");
}
public static void method2() {
System.out.println("========方法二=========");
}
}
需求:设计一个排序算法工具类(快速排序 选择排序 冒泡排序),使用动态代理来统计排序的执行时间
代码实现
public class DynamicProxyDemo {
public static void main(String[] args) {
int[] arr = new int[100000];
//获取一个随机数的数组
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() *100);
}
// 真实对象,我们不会使用真实对象,我们使用代理对象
ISort sort = new ArraySort();
// 创建代理对象
ISort proxy = (ISort) ProxyFactory.getProxy(sort);
// 通过代理对象调用相应的排序方法,本质其实调用了真实对象的方法,但是又添加响应的增强的代码
proxy.selectSort(arr);
proxy.bubbleSort(arr);
proxy.quickSort(arr);
}
}
class ProxyFactory {
public static Object getProxy(Object target) {
CalculateInvocationHandler handler = new CalculateInvocationHandler();
handler.setTarget(target);
// 通过真实对象实现的接口反推代理对象实现的接口
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
return proxy;
}
}
class CalculateInvocationHandler implements InvocationHandler {
private Object target;
public CalculateInvocationHandler() {
super();
}
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
String sortName = "";
switch (name) {
case "bubbleSort":
sortName = "冒泡排序";
break;
case "selectSort":
sortName = "选择排序";
break;
case "quickSort":
sortName = "快速排序";
break;
default:
break;
}
long start = System.currentTimeMillis();
method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println("本次" + sortName + "一共耗时" + (end - start) + "毫秒");
return null;
}
}
// 使用动态代理一定要有接口
interface ISort {
void bubbleSort(int[] arr);
void selectSort(int[] arr);
void quickSort(int[] arr);
}
class ArraySort implements ISort {
//冒泡排序方法
@Override
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = 0;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//选择排序方法
@Override
public void selectSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = 0;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
//快速排序方法
@Override
public void quickSort(int[] arr) {
Arrays.sort(arr);
}
}