一、概念
1.真实对象:被代理的对象
2.代理对象:咱们写的本身
3.代理模式:代理对象代理真实对象,达到增强真实对象的功能和目的。
4.实现方式:动态代理在内存中形成代理类,代理对象和真实对象必须实现相同接口。
原理:利用反射生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
二、JDK动态代理--生活代码案例
通过以上生活案例,我们来写代码,总是代理模式和生活的意思一样,现在商业处处都是代理,买房子,微商等等,有了这些代理,客户获取了更好的感受。
1.卖电脑接口2
/**
* 真实对象和代理对象实现相同的卖电脑接口
*/
public interface SaleComputer {
String pay(double money);
void show();
}
2.北京联想公司(真实对象)
public class Lenovo implements SaleComputer {
@Override
public String pay(double money) {
System.out.println("客户支付了"+money+"买了一台电脑");
return "联想电脑";
}
@Override
public void show() {
System.out.println("展示电脑");
}
}
3.天津代理商(代理对象)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 增强代理对象测试
*/
public class ProxyTest {
public static void main(String[] args) {
Lenovo lenovo = new Lenovo();
/*
* java.lang.reflect.Proxy提供用于创建动态代理类和实例的静态方法,大家可以查看JDK文档。
* 1.Proxy.newProxyInstance()通过调用newInstance 方法创建代理实例。
* 2.方法中有三个参数
* ClassLoader loader:定义代理类的类加载器(即真实对象)
* Class<?>[] interfaces:真实对象实现的接口数组
* InvocationHandler h:调用处理程序,执行方法。
*/
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(),
lenovo.getClass().getInterfaces(), new InvocationHandler() {
@Override
//invoke方法是核心代理逻辑思想,代理对象调用的所有方法都会触发该方法执行
//增强方式有三种:1.增强参数 2.增强返回值 3.增强方法体
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* 三个参数
* 1.proxy:就是代理对象本身
* 2.method:代理对象调用的方法,被封装为的对象。简单说 谁在运行调用,这个method就是谁。
* 3.args:代理对象调用方法时,传递的实际参数
*/
//增强参数
if (method.getName().equals("pay")) {
//增强参数,代理需要赚取利润,代理修改了参数。
//这里args[0]代表方法的第一个参数。
double money = (double) args[0];
money = money * 1.2;
//增强方法体
System.out.println("买电脑专车接送");
//修改了方法参数 这里method.invok就是调用方法。
String computer = (String) method.invoke(lenovo, money);
//增强方法体
System.out.println("买电脑免费配送");
//增强返回值
return computer+"送鼠标垫";
} else {
//如果没有,那么就原样输出
Object obj = method.invoke(lenovo, args);
return obj;
}
}
});
String computer = proxy_lenovo.pay(5000);
System.out.println(computer);
proxy_lenovo.show();
}
}
4.测试结果
三、JDK动态代理--业务逻辑案例
在我们web项目开发中,业务层存在UserService接口,其中有查询所有用户,删除用户等业务逻辑,UserServiceImpl实现类重写方法。我们要对每个方法进行性能分析,检测每个方法的消耗时间,那么我们可以不改变原有类的基础上增强对象。
1.UserService接口
public interface UserService {
/**
* 查询用户
*/
void getUsers();
/**
* 删除用户
*/
void deleteUser();
}
2.UserServiceImpl实现类
public class UserServiceImpl implements UserService {
@Override
public void getUsers() {
try {
/**
* 这里让他睡一下,咱们这个业务逻辑只是输出一句话
* 没有做真正的业务查询,不然运行太快
*/
Thread.sleep(1000);
System.out.println("查询了100个用户");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void deleteUser() {
try {
Thread.sleep(2000);
System.out.println("删除了50个用户");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.定义一个获取代理对象的工具类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static UserService getProxy(UserServiceImpl obj) {
return (UserService)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取开始时间
long start=System.currentTimeMillis();
method.invoke(obj,null);
//获取结束时间
long end=System.currentTimeMillis();
System.out.println(method.getName()+"方法耗时"+(end-start)/1000+"s");
return obj;
}
});
}
}
4.测试类
public class MyTest {
public static void main(String[] args) {
UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
userService.getUsers();
userService.deleteUser();
}
}
5.测试结果
以上还可以把代理工具类传递的参数用泛型,那么传递任何东西都可以了。