当前位置:   article > 正文

Java面试八股文 PDF,从没有人将代理模式分析得如此透彻,被大佬问到自闭_面试八股文pdf

面试八股文pdf

try {

return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();

} catch (RuntimeException | Error var2) {

throw var2;

} catch (Throwable var3) {

throw new UndeclaredThrowableException(var3);

}

}

static {

try {

m1 = Class.forName(“java.lang.Object”).getMethod(“equals”,

new Class[]{Class.forName(“java.lang.Object”)});

m3 = Class.forName(“com.tom.pattern.proxy.dynamicproxy.jdkproxy.IPerson”)

.getMethod(“findLove”, new Class[0]);

m2 = Class.forName(“java.lang.Object”).getMethod(“toString”, new Class[0]);

m4 = Class.forName(“com.tom.pattern.proxy.dynamicproxy.jdkproxy.IPerson”)

.getMethod(“buyInsure”, new Class[0]);

m0 = Class.forName(“java.lang.Object”).getMethod(“hashCode”, new Class[0]);

} catch (NoSuchMethodException var2) {

throw new NoSuchMethodError(var2.getMessage());

} catch (ClassNotFoundException var3) {

throw new NoClassDefFoundError(var3.getMessage());

}

}

}

我们发现,$Proxy0继承了Proxy类,同时实现了Person接口,而且重写了findLove()等方法。在静态代码块中用反射查找到了目标对象的所有方法,而且保存了所有方法的引用,重写的方法用反射调用目标对象的方法。小伙伴们此时一定会好奇:这些代码是从哪里来的?其实是JDK自动生成的。现在我们不依赖JDK,自己来动态生成源码、动态完成编译,然后替代目标对象并执行。

创建GPInvocationHandler接口。

public interface GPInvocationHandler {

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable;

}

创建GPProxy类。

/**

  • 用来生成源码的工具类

  • Created by Tom.

*/

public class GPProxy {

public static final String ln = “\r\n”;

public static Object newProxyInstance(GPClassLoader classLoader, Class<?> [] interfaces,

GPInvocationHandler h){

try {

//1.动态生成源码.java文件

String src = generateSrc(interfaces);

//2.Java文件输出磁盘

String filePath = GPProxy.class.getResource(“”).getPath();

File f = new File(filePath + “$Proxy0.java”);

FileWriter fw = new FileWriter(f);

fw.write(src);

fw.flush();

fw.close();

//3.把生成的.java文件编译成.class文件

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);

Iterable iterable = manage.getJavaFileObjects(f);

JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);

task.call();

manage.close();

//4.编译生成的.class文件加载到JVM中

Class proxyClass = classLoader.findClass(“$Proxy0”);

Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);

f.delete();

//5.返回字节码重组以后的新的代理对象

return c.newInstance(h);

}catch (Exception e){

e.printStackTrace();

}

return null;

}

private static String generateSrc(Class<?>[] interfaces){

StringBuffer sb = new StringBuffer();

sb.append(GPProxy.class.getPackage() + “;” + ln);

sb.append("import " + interfaces[0].getName() + “;” + ln);

sb.append(“import java.lang.reflect.*;” + ln);

sb.append("public class $Proxy0 implements " + interfaces[0].getName() + “{” + ln);

sb.append(“GPInvocationHandler h;” + ln);

sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);

sb.append(“this.h = h;”);

sb.append(“}” + ln);

for (Method m : interfaces[0].getMethods()){

Class<?>[] params = m.getParameterTypes();

StringBuffer paramNames = new StringBuffer();

StringBuffer paramValues = new StringBuffer();

StringBuffer paramClasses = new StringBuffer();

for (int i = 0; i < params.length; i++) {

Class clazz = params[i];

String type = clazz.getName();

String paramName = toLowerFirstCase(clazz.getSimpleName());

paramNames.append(type + " " + paramName);

paramValues.append(paramName);

paramClasses.append(clazz.getName() + “.class”);

if(i > 0 && i < params.length-1){

paramNames.append(“,”);

paramClasses.append(“,”);

paramValues.append(“,”);

}

}

sb.append("public " + m.getReturnType().getName() + " " + m.getName() + “(” + paramNames.toString() + “) {” + ln);

sb.append(“try{” + ln);

sb.append(“Method m = " + interfaces[0].getName() + “.class. getMethod(”” + m.getName() + “”,new Class[]{" + paramClasses.toString() + “});” + ln);

sb.append((hasReturnValue(m.getReturnType()) ? "return " : “”) + getCaseCode(“this.h.invoke(this,m,new Object[]{” + paramValues + “})”,m.getReturnType()) + “;” + ln);

sb.append(“}catch(Error _ex) { }”);

sb.append(“catch(Throwable e){” + ln);

sb.append(“throw new UndeclaredThrowableException(e);” + ln);

sb.append(“}”);

sb.append(getReturnEmptyCode(m.getReturnType()));

sb.append(“}”);

}

sb.append(“}” + ln);

return sb.toString();

}

private static Map<Class,Class> mappings = new HashMap<Class, Class>();

static {

mappings.put(int.class,Integer.class);

}

private static String getReturnEmptyCode(Class<?> returnClass){

if(mappings.containsKey(returnClass)){

return “return 0;”;

}else if(returnClass == void.class){

return “”;

}else {

return “return null;”;

}

}

private static String getCaseCode(String code,Class<?> returnClass){

if(mappings.containsKey(returnClass)){

return “((” + mappings.get(returnClass).getName() + “)” + code + “).” + returnClass.getSimpleName() + “Value()”;

}

return code;

}

private static boolean hasReturnValue(Class<?> clazz){

return clazz != void.class;

}

private static String toLowerFirstCase(String src){

char [] chars = src.toCharArray();

chars[0] += 32;

return String.valueOf(chars);

}

}

创建GPClassLoader类。

public class GPClassLoader extends ClassLoader {

private File classPathFile;

public GPClassLoader(){

String classPath = GPClassLoader.class.getResource(“”).getPath();

this.classPathFile = new File(classPath);

}

@Override

protected Class<?> findClass(String name) throws ClassNotFoundException {

String className = GPClassLoader.class.getPackage().getName() + “.” + name;

if(classPathFile != null){

File classFile = new File(classPathFile,name.replaceAll(“\.”,“/”) + “.class”);

if(classFile.exists()){

FileInputStream in = null;

ByteArrayOutputStream out = null;

try{

in = new FileInputStream(classFile);

out = new ByteArrayOutputStream();

byte [] buff = new byte[1024];

int len;

while ((len = in.read(buff)) != -1){

out.write(buff,0,len);

}

return defineClass(className,out.toByteArray(),0,out.size());

}catch (Exception e){

e.printStackTrace();

}

}

}

return null;

}

}

创建GPMeipo类。

public class GpMeipo implements GPInvocationHandler {

private IPerson target;

public IPerson getInstance(IPerson target){

this.target = target;

Class<?> clazz = target.getClass();

return (IPerson) GPProxy.newProxyInstance(new GPClassLoader(),clazz.getInterfaces(),this);

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

before();

Object result = method.invoke(this.target,args);

after();

return result;

}

private void after() {

System.out.println(“双方同意,开始交往”);

}

private void before() {

System.out.println(“我是媒婆,已经收集到你的需求,开始物色”);

}

}

客户端测试代码如下。

public static void main(String[] args) {

GpMeipo gpMeipo = new GpMeipo();

IPerson zhangsan = gpMeipo.getInstance(new Zhangsan());

zhangsan.findLove();

}

至此,手写JDK动态代理就完成了。小伙伴们是不是又多了一个面试用的“撒手锏”呢?

5 CGLib动态代理API原理分析


简单看一下CGLib动态代理的使用,还是以媒婆为例,创建CglibMeipo类。

public class CGlibMeipo implements MethodInterceptor {

public Object getInstance(Class<?> clazz) throws Exception{

//相当于JDK中的Proxy类,是完成代理的工具类

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(clazz);

enhancer.setCallback(this);

return enhancer.create();

}

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

before();

Object obj = methodProxy.invokeSuper(o,objects);

after();

return obj;

}

private void before(){

System.out.println(“我是媒婆,我要给你找对象,现在已经确认你的需求”);

System.out.println(“开始物色”);

}

private void after(){

System.out.println(“双方同意,准备办婚事”);

}

}

创建单身客户类Customer。

public class Customer {

public void findLove(){

System.out.println(“符合要求”);

}

}

这里有一个小细节,CGLib动态代理的目标对象不需要实现任何接口,它是通过动态继承目标对象实现动态代理的,客户端测试代码如下。

public static void main(String[] args) {

try {

//JDK采用读取接口的信息

//CGLib覆盖父类方法

//目的都是生成一个新的类,去实现增强代码逻辑的功能

//JDK Proxy对于用户而言,必须要有一个接口实现,目标类相对来说复杂

//CGLib可以代理任意一个普通的类,没有任何要求

//CGLib生成代理的逻辑更复杂,调用效率更高,生成一个包含了所有逻辑的FastClass,不再需 要反射调用

//JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用

//CGLib有一个缺点,CGLib不能代理final的方法

Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);

System.out.println(obj);

obj.findLove();

} catch (Exception e) {

e.printStackTrace();

}

}

CGLib动态代理的实现原理又是怎样的呢?我们可以在客户端测试代码中加上一句代码,将CGLib动态代理后的.class文件写入磁盘,然后反编译来一探究竟,代码如下。

public static void main(String[] args) {

try {

//使用CGLib的代理类可以将内存中的.class文件写入本地磁盘

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “E://cglib_proxy_class/”);

Customer obj = (Customer)new CglibMeipo().getInstance(Customer.class);

obj.findLove();

} catch (Exception e) {

e.printStackTrace();

}

}

重新执行代码,我们会发现在E://cglib_proxy_class目录下多了三个.class文件,如下图所示。

file

通过调试跟踪发现,Customer E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB3feeb52a.class就是CGLib动态代理生成的代理类,继承了Customer类。

package com.tom.pattern.proxy.dynamicproxy.cglibproxy;

import java.lang.reflect.Method;

import net.sf.cglib.core.ReflectUtils;

import net.sf.cglib.core.Signature;

import net.sf.cglib.proxy.*;

public class Customer E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB3feeb52a extends Customer

implements Factory

{

final void CGLIB$findLove$0()

{

super.findLove();

}

public final void findLove()

{

CGLIB$CALLBACK_0;

if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1

_L1:

JVM INSTR pop ;

CGLIB$BIND_CALLBACKS(this);

CGLIB$CALLBACK_0;

_L2:

JVM INSTR dup ;

JVM INSTR ifnull 37;

goto _L3 _L4

_L3:

break MISSING_BLOCK_LABEL_21;

_L4:

break MISSING_BLOCK_LABEL_37;

this;

CGLIB$findLove 0 0 0Method;

CGLIB$emptyArgs;

CGLIB$findLove 0 0 0Proxy;

intercept();

return;

super.findLove();

return;

}

}

我们重写了Customer类的所有方法,通过代理类的源码可以看到,代理类会获得所有从父类继承来的方法,并且会有MethodProxy与之对应,比如Method CGLIB f i n d L o v e 000 M e t h o d 、 M e t h o d P r o x y C G L I B findLove 0 0 0Method、MethodProxy CGLIB findLove000MethodMethodProxyCGLIBfindLove 0 0 0Proxy等方法在代理类的findLove()方法中都有调用。

//代理方法(methodProxy.invokeSuper()方法会调用)

final void CGLIB$findLove$0()

{

super.findLove();

}

//被代理方法(methodProxy.invoke()方法会调用

//这就是为什么在拦截器中调用methodProxy.invoke会发生死循环,一直在调用拦截器)

public final void findLove()

{

//调用拦截器

intercept();

return;

super.findLove();

return;

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

《MySql面试专题》

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

《MySql性能优化的21个最佳实践》

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

《MySQL高级知识笔记》

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

文中展示的资料包括:**《MySql思维导图》《MySql核心笔记》《MySql调优笔记》《MySql面试专题》《MySql性能优化的21个最佳实践》《MySq高级知识笔记》**如下图

全网火爆MySql 开源笔记,图文并茂易上手,阿里P8都说好

关注我,点赞本文给更多有需要的人

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

uYOm-1712432767580)]

《MySQL高级知识笔记》

[外链图片转存中…(img-iao4as20-1712432767580)]

[外链图片转存中…(img-AvX99Eo1-1712432767581)]

[外链图片转存中…(img-CVEq0dkv-1712432767581)]

[外链图片转存中…(img-B40dnmsn-1712432767581)]

[外链图片转存中…(img-AVxBGYD0-1712432767582)]

[外链图片转存中…(img-tUogpiHc-1712432767582)]

[外链图片转存中…(img-D9TTLdk8-1712432767582)]

[外链图片转存中…(img-hPlHprtm-1712432767583)]

[外链图片转存中…(img-C0HjKeny-1712432767583)]

[外链图片转存中…(img-FVlm94LL-1712432767583)]

文中展示的资料包括:**《MySql思维导图》《MySql核心笔记》《MySql调优笔记》《MySql面试专题》《MySql性能优化的21个最佳实践》《MySq高级知识笔记》**如下图

[外链图片转存中…(img-cMqW4ml8-1712432767584)]

关注我,点赞本文给更多有需要的人

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/805163
推荐阅读
相关标签
  

闽ICP备14008679号