概念
为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
实现方式:静态代理和动态代理。静态代理有一个类文件描述代理模式;动态代理在内存中形成代理类。
动态代理
使用一个例子介绍动态代理:
美的公司的总部在广东,假如那里负责生产和销售空调。如果有一个用户想要购买美的空调,可以去广东的总部购买。另外美的在全国各地也有空调的代理商,用户也可以去代理商那里进行购买。
这里的美的总部就是真实的对象,被代理的对象,而代理商就是代理对象。
实现步骤:
- 代理对象和真实对象实现相同的接口
- 代理对象 = Proxy.newProxyInstance();
- 使用代理对象调用方法。
- 增强方法
接口:
public interface Sale {
public String sale(double moeny);
public void show();
}
真实对象:
/** 真实对象
* @author liwenlong
* @data 2020/4/24
*/
public class Midea implements Sale{
@Override
public String sale(double moeny) {
System.out.println("花了"+ moeny +"元,买了台美的空调");
return "美的空调"; //返回一台空调
}
@Override
public void show() {
System.out.println("演示空调使用");
}
}
测试类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/** 测试类
* @author liwenlong
* @data 2020/4/24
*/
public class ProxyTest {
public static void main(String[] args) {
//创建真实美的对象
Midea midea = new Midea();
//使用动态代理增强对象
/* 三个参数
第一个参数:类加载器:真实对象.getClass().getClassLoader()
第二个参数:真实对象实现的接口:真实对象.getClass().getInterfaces()
第三个参数:new InvocationHandler()
*/
Sale proxy_midea = (Sale) Proxy.newProxyInstance(midea.getClass().getClassLoader(), midea.getClass().getInterfaces(), new InvocationHandler() {
/*
代理对象调用真实对象的所有方法,都会触发invoke方法的执行
三个参数:
第一个参数:proxy,代理对象,一般不用管
第二个参数:method,代理对象调用的方法,会在这里被封装成为对象
第三个参数:代理对象在调用方法时,传递的实际参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke方法被执行");
System.out.println(method.getName());
System.out.println(args[0]);
return null;
}
});
//代理对象调用方法
//proxy_midea.show();
/*输出:
invoke方法被执行
show
*/
String airCondition = proxy_midea.sale(3000);
System.out.println(airCondition);
/*输出:
invoke方法被执行
sale
3000.0
null
*/
}
}
发现上面在使用代理对象执行方法时候,只是invoke中的方法被执行,被调用的方法没有被执行,这是因为还没有在invoke中使用真实对象调用方法,并且返回值目前是return null
在实际使用中,应该在invoke方法中调用真实对象的方法,设置返回值。如果invoke方法中是这样的,那么就和真实对象实现的逻辑一样:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = method.invoke(midea, args);
return obj;
}
执行下面方法时就会输出:
String airCondition = proxy_midea.sale(3000);
System.out.println(airCondition);
/*
输出:
花了3000.0元,买了台美的空调
美的空调
*/
目前已经实现代理对象和真实对象调用方法实现的业务逻辑是一样的,但是代理对象的好处还没有体现,那就是可以在目标对象实现的基础上,增强额外的功能操作。
根据方法的三要素,增强方式有三种:
- 增强参数列表
- 增强返回值类型
- 增强方法体执行逻辑
继续上一个例子,用户从代理商那里购买空调是3000,代理商进价是售价的80%
public class ProxyTest {
public static void main(String[] args) {
//创建真实美的对象
Midea midea = new Midea();
Sale proxy_midea = (Sale) Proxy.newProxyInstance(midea.getClass().getClassLoader(), midea.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.增强参数
// 判断是否是sale方法
if (method.getName().equals("sale")) {
double money = (double) args[0]; //获取sale方法的参数
money = 0.8 * money;
Object obj = method.invoke(midea, money);
return obj;
}else {
Object obj = method.invoke(midea, args);
return obj;
}
}
});
String airCondition = proxy_midea.sale(3000);
System.out.println(airCondition);
}
}
输出结果:
花了2400.0元,买了台美的空调
美的空调
继续增强,这次增强返回值的类型,原始对象返回一台空调,现在代理商从中间赚取了差价,返回了比原对象更多的东西。
/**
* 测试类
*
* @author liwenlong
* @data 2020/4/24
*/
public class ProxyTest {
public static void main(String[] args) {
//创建真实美的对象
Midea midea = new Midea();
Sale proxy_midea = (Sale) Proxy.newProxyInstance(midea.getClass().getClassLoader(), midea.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否是sale方法
if (method.getName().equals("sale")) {
//1.增强参数
double money = (double) args[0]; //获取sale方法的参数
money = 0.8 * money;
Object obj = method.invoke(midea, money);
//2.增强返回值
return obj+" 赠送上门安装";
}else {
Object obj = method.invoke(midea, args);
return obj;
}
}
});
String airCondition = proxy_midea.sale(3000);
System.out.println(airCondition);
}
}
输出结果:
花了2400.0元,买了台美的空调
美的空调 赠送上门安装
对方法体的内容进行增强,例如在方法体内,安排专人服务。
public class ProxyTest {
public static void main(String[] args) {
//创建真实美的对象
Midea midea = new Midea();
Sale proxy_midea = (Sale) Proxy.newProxyInstance(midea.getClass().getClassLoader(), midea.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否是sale方法
if (method.getName().equals("sale")) {
//1.增强参数
double money = (double) args[0]; //获取sale方法的参数
money = 0.8 * money;
Object obj = method.invoke(midea, money);
//2.增强返回值
return obj+" 赠送上门安装";
}else {
Object obj = method.invoke(midea, args);
return obj;
}
}
});
String airCondition = proxy_midea.sale(3000);
System.out.println(airCondition);
}
}
输出:
花了2400.0元,买了台美的空调
专属客服服务
美的空调 赠送上门安装