java反射笔记、内省、动态代理、InvocationHandler、cglib
文章目录反射和内省(introspector)的区别InvocationHandler调用处理接口动态代理示例动态代理报错 object is not an instance of declaring classInvocationHandler的invoke的proxy参数invoke方法自动调用 重proxy的newProxyInstance()方法的参数有几个分别是什么?反射获取方法反射获取类反射获取某些属性值面试题说下对反射的理解动态代理有几种方式?spring中的动态代理是怎样的?反射早就知道今天翻博客发现居然没有反射的笔记那弄一篇吧。反射和内省(introspector)的区别反射反射是指在运行时获取一个类的所有信息包括成员变量、成员方法、构造器等并可以操纵这些部分。反射机制将类的各种成分映射成Java对象以便在运行时进行操作。内省内省是指程序在运行时检查对象的能力而反射则是指程序在运行时修改对象的能力。内省主要用于获取对象的属性和方法信息而反射则更侧重于动态操作对象。—反射内省定义反射是指在运行时获取一个类的所有信息包括成员变量、成员方法、构造器等并可以操纵这些部分。反射机制将类的各种成分映射成Java对象以便在运行时进行操作。略区别反射则是指程序在运行时修改对象的能力。反射则更侧重于动态操作对象。内省是指程序在运行时检查对象的能力。内省主要用于获取对象的属性和方法信息。InvocationHandler调用处理接口代码publicinterfaceInvocationHandler{publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable;}InvocationHandler是反射的重要组成部分。动态代理示例步骤1、定义一个接口。# 这是你的业务接口2、实现InvocationHandler接口。# 这个接口用于处理代理实例上的方法调用3.创建代理对象然后代理对象调用业务方法(这步调用方法不说也一样)。 # 使用Proxy.newProxyInstance()方法创建一个代理对象举个例子就比较好理解了。例如交通工具可以跑现在想要记录下跑一定距离花费的时间。交通工具接口类。// 交通工具publicinterfaceVehicle{// 跑publicvoidrun(Stringdistance);}汽车是交通工具的一个实现类。Slf4jpublicclassCarimplementsVehicle{Overridepublicvoidrun(Stringdistance){log.info(run方法开始distance{},distance);}publicstaticvoidmain(String[]args){CarcarnewCar();TimeInvocationHandlertimeInvocationHandlernewTimeInvocationHandler(car);VehicleproxyInstance(Vehicle)Proxy.newProxyInstance(Car.class.getClassLoader(),newClass[]{Vehicle.class},timeInvocationHandler);proxyInstance.run(100米);}}时间动态代理。Slf4jpublicclassTimeInvocationHandlerimplementsInvocationHandler{privatefinalObjectvehicle;publicTimeInvocationHandler(Objectvehicle){this.vehiclevehicle;}OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{longsSystem.currentTimeMillis();log.info(invoke方法开始method{}开始时间{},method.getName(),System.currentTimeMillis());Objectinvokemethod.invoke(vehicle,args);log.info(invoke方法完成method{}结束时间{}耗时{},method.getName(),System.currentTimeMillis(),System.currentTimeMillis()-s);returninvoke;}}动态代理报错 object is not an instance of declaring class当然不只是一种情况个人遇到的是invoke方法的对象错写为this了实际应该是构造器传入的对象。InvocationHandler的invoke的proxy参数动态代理的proxy代码中并没有用到是可有可无的吗?关于这个参数说法太多了。有说它就是代理对象的也有说可以递归调用的。invoke方法自动调用 重说实话这个问题困扰我半天一直没想明白返回的明明是业务接口调用方法是如何和invoke产生关联的。后来终于找到了网上确实有高人。 详见另外一篇博客。proxy的newProxyInstance()方法的参数有几个分别是什么?千万别小看这个问题对着代码什么都明白背过代码啥都记不起来脑子是白长的吗?publicstaticObjectnewProxyInstance(ClassLoaderloader,Class?[]interfaces,InvocationHandlerh)有3个参数分别是loader # 类加载器interfaces # 业务接口数组InvocationHandler # 调用处理接口反射获取方法反射获取类反射获取某些属性值例如获取attr1-20属性的值。publicstaticMapLong,LongbuildDimMapFromAttrs(Objectdetail){MapLong,LongdimMapnewHashMap();if(detailnull){returndimMap;}Class?clazzdetail.getClass();for(inti1;i50;i){try{Fieldfieldclazz.getDeclaredField(attri);// 属性为attr1、attr2等field.setAccessible(true);Longvalue(Long)field.get(detail);if(value!null){dimMap.put((long)i,value);}}catch(NoSuchFieldException|IllegalAccessExceptione){// ignore}}returndimMap;}注这里的detail以前是具体的类型实际可以用Object适配性更强。面试题说下对反射的理解基于reflect包在运行时查看、创建、修改对象的能力。动态代理有几种方式?1、jdk动态代理2、cglib动态代理—jdk动态代理cglib动态代理底层原理实现接口的实现类基于jdk内置字节码生成器生成代理类(接口实现类)字节码继承父类实现子类基于asm字节码工具生成子类依赖基于jdk内部字节码生成器基于asm字节码工具反射全程依赖反射主要是Method.invoke()创建对象用到反射方法调用依靠FastClass绕过反射性能更高限制必须有接口类、方法不能用final修饰否则无法生成类(无法被继承)方法(无法被重写)spring中的动态代理是怎样的?是不是会这么答?有接口 用jdk动态代理 # 默认无接口 用cglib动态代理所以spring自动做了兼容无论是否有接口都可以实现。对是对还可以答的更好。springboot2.0之后默认是cglib动态代理。如果需要关闭可以通过设置参数proxy-target-classfalse即1、全局都用jdk动态代理。2、有接口没问题、无接口会报错。注2.0为了统一化设置为false后不再自动兼容。