5、动态代理
1、介绍
切面编程 AOP
业务对象的的每个方法都要进行性能统计,存在大量重复的代码
代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的
Proxy 方法: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
动态代理的优点
- 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接口本身做代理
- 可以为被代理对象的所有方法做代理
- 可以在不改变方法源码的情况下,实现对方法功能的增强
- 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率
关键步骤
- 必须有接口,实现类要实现接口(代理通常是基于接口实现的)
- 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象
动态代理:目标对象 + 代理逻辑 = 代理对象
- JDK:代理对象和目标对象出于同一个接口之下
- CGLib:代理对象是目标对象的子对象
// 接口
public interface UserService {
String login(String loginName, String password);
void selectUsers();
boolean deleteUsers();
}
// 实现类
public class UserServiceImpl implements UserService {
@Override
public String login(String loginName, String password) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ("admin".equals(loginName) && "123".equals(password)) return "success";
return "fail";
}
@Override
public void selectUsers() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("账号: admin, 密码: 123");
}
@Override
public boolean deleteUsers() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
2、JDK 动态代理
JDK 动态代理,依赖接口
// 代理实现统计方法耗时
public class ProxyUtil {
// 泛型方法: 为任何对象做代理
public static <T> T getProxy(T obj) {
return (T) Proxy.newProxyInstance(
obj.getClass().getClassLoader(), // 类加载器, 负责加载代理类到内存中使用
obj.getClass().getInterfaces(), // 获取代理类实现的全部接口
new InvocationHandler() { // 代理逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 参数一: 代理对象本身, 一般不管
// 参数二: 正在被代理的方法
// 参数三: 被代理方法传入的参数
long startTime = System.currentTimeMillis();
Object result = method.invoke(obj, args); // 业务代码
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " 耗时: " + (endTime - startTime) / 1000.0);
return result;
}
});
}
}
// 测试
public class Test {
public static void main(String[] args) {
UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
System.out.println(userService.login("admin", "123"));
userService.selectUsers();
userService.deleteUsers();
}
}
// login 耗时: 1.014
// success
// 账号: admin, 密码: 123
// selectUsers 耗时: 1.013
// deleteUsers 耗时: 1.012
3、CGLib 动态代理
CGLib 动态代理,不依赖接口,但是不能对声明为 final 的类或者方法进行代理,因为 CGLib 原理是动态生成被代理类的子类
public class CGLibProxyUtil {
public static <T> T getProxy(T obj) {
// 1. 创建 Enhancer 对象, 类似 JDK 代理中的 Proxy 类
Enhancer enhancer = new Enhancer();
// 2. 设置父类的字节码对象
enhancer.setSuperclass(obj.getClass());
// 3. 设置回掉函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
/*
o 代理对象
method 真实对象中的方法的 Method 实例
args 实际参数
methodProxy 代理对象中的方法的 method 实例
*/
long startTime = System.currentTimeMillis();
Object result = method.invoke(obj, args); // 业务代码
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " 耗时: " + (endTime - startTime) / 1000.0);
return result;
}
});
// 4. 创建代理对象(属于目标对象类的子类的对象)
return (T) enhancer.create();
}
}
4、更多
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17473107.html