导语:最近在准备春招,所以有计划的在复习java基础知识,整理了一些笔记分享出来,这篇是关于代理,上一篇是关于反射。
1.代理的作用:
- 在不改变原代码的情况下实现增强代码(例如为公司项目的每一个方法前后添加打印日志功能并且不修改源代码)
2.静态代理:
还以现行打印日志功能为例:我们需要为项目的每一个类编写一个对应的代理类,并且二者实现同一个接口(假设都有)

代理对象干的事:通过构造器塞入一个目标对象,然后在代理对象的方法内部调用目标对象同名方法,并在调用前后打印日志。
也就是说,代理对象 = 增强代码 + 目标对象(原对象)

静态代理的缺陷:需要为每一个类编写代理对象,假设项目有1000个类呢?所以我们需要少写1000个代理类来实现代理功能,于是有了动态代理
3.动态代理
静态代理还是动态代理本质都是最终生成代理对象:
- 静态代理:静态代理对象需要先手动创建代理类,再创建代理对象。
- 动态代理:动态代理对象则因为接口中含有了被代理类差不多的构造,我只需要通过接口+一个构造方法自动生成一个代理对象,直接跳过了代理类的书写过程。
4.JDK的动态代理
自动生成代理对象过程:
第一步:通过 Proxy.getProxyClass(ClassLoader,interfaces) 获取代理类的Class对象
第二步:通过代理类的Class对象获取一个代理类的有参构造器,参数为InvocationHandler接口的Class对象
第三步:通过有参构造器.newInstance(new InvocationHandler(){})方法反射也就获得到了代理对象
/**
* @description: 下面为jdk动态代理的过程,但是一般编程不会这样写,这样写是原理展示
* @author:
* @date: 2021/3/11 12:09
**/
import java.lang.reflect.*;
public class Main {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/**
* 第一步通过接口的类加载器以及接口的class对象获取代理类的class对象
*/
Class proxyClass = Proxy.getProxyClass(Study.class.getClassLoader(), Study.class);
/**
* 第二步获取有参的构造器
*/
Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
/**
* 第三步通过构造器反射生成代理对象
*/
Study s = (Study)constructor.newInstance(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理增强,学习算法前我需要先熟悉数据结构
System.out.println("先学习数据结构");
return method.invoke(proxy,args);
}
});
}
}
现实中编程一般会用Proxy.newProxyInstance(),是上面三步的组合,隐藏获取代理对象的细节
/**
* @description: 一般现实中编程会用Proxy.newProxyInstance(),影藏获取代理对象的实现细节
* @author:
* @date: 2021/3/11 12:11
**/
public class Main2 {
public static void main(String[] args) throws Exception {
/**
* 被代理目标对象,实现了study接口
*/
Student student = new Student();
/**
* 获取代理对象,类型为study接口
*/
Study studentProxy = (Study)getProxy(student);
/**
* 代理对象调用目标对象方法,并实现代码增强实现自己的功能,调用目标对象方法之前都会先调用invoke方法
*/
studentProxy.suanfa();
}
public static Object getProxy(final Object target) throws Exception{
/**
* 传入一个类加载器,目标对象实现的接口,以及一个InvacationHandler
* 使用newProxyInstance可以帮你影藏具体得到代理对象的细节
*/
Object proxy =Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代码增强,先学习数据结构");
System.out.println(method.getName() + "方法开始执行...");
Object result = method.invoke(target, args);
System.out.println(result);
System.out.println(method.getName() + "方法执行结束...");
return result;
}
});
return proxy;
}
}
流程图

181

被折叠的 条评论
为什么被折叠?



