欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot
反射(运行期动态加载 .class 字节码文件到JVM,产生一个Class对象,使用编译期完全未知的类)
Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的
反射最重要的用途就是开发各种通用框架。
反射就是把java类中的各种成分(成员变量、方法、构造方法、包等信息)映射成一个个的Java对象。
反射需要解决的问题
Java中编译类型有两种:
静态编译:在编译时确定类型,绑定对象即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。
Java反射是Java被视为动态(或准动态)语言的一个关键性质。
反射(reflection)允许静态语言在运行时(runtime)检查、修改程序的结构与行为。
在静态语言中,程序运行时的行为都是固定的。如果想在运行时改变,就需要反射这东西了。
代理(为了增加通用的业务逻辑)
代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问,隐藏和保护委托类对象,实施不同控制策略。
代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。
静态代理与动态代理
按照代理的创建时期,代理类可以分为两种:
静态:在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成。
静态代理类优缺点:
优点:解耦
缺点:代码重复,难以维护,代理对象只服务于一种类型的对象。
动态代理优缺点:
优点:
日志系统、事务、拦截器、权限控制等。这也就是 AOP(面向切面编程)的基本原理。
Spring 中的 Aop 使用动态代理增强,Mybatis 中使用动态代理生成 mapper。
接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理,代码复用性强。
动态代理原理
动态代理:是使用反射和字节码的技术,在运行期创建指定接口或类的子类,增强代码。
动态代理主要有JDK和CGLIB两种方式。
JDK实现的动态代理(基于反射)
jdk实现的动态代理由两个重要的成员组成,java.lang.reflect 包下提供的 Proxy、InvocationHandler。
Proxy:
是所有动态代理的父类,它提供了一个静态方法来创建动态代理的 class 对象和实例。
InvocationHandler:
每个动态代理实例都有一个关联的 InvocationHandler,
在代理实例上调用方法,方法调用将被转发到 InvocationHandler 的 invoke() 方法。
Proxy 类 newProxyInstance():
通过反射,将h作为参数,实例化代理类,返回代理类实例( return cons.newInstance(new Object[]{h}); )
InvocationHandler 类 invoke() (通过反射动态调用某个实例的方法):
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeAdvice();
Object obj = method.invoke(target, args);
advice.afterAdvice();
return obj;
}
public Object invoke(Object obj, Object... args) {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz,
Modifier.isStatic(modifiers) ? null : obj.getClass(),
modifiers);
}
MethodAccessor ma = methodAccessor;
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
public class Myhandler implements InvocationHandler {
private Object object;
public Object getProxy(Object object){
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前的日志记录");
Object obj = method.invoke(object,args);
System.out.println("执行后的日志记录");
return obj;
}
}
从执行效率上看,Cglib动态代理效率较高。
动态代理详解
CGLIB动态代理(基于字节码生成库)
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。
CGLIB通过继承的方式实现代理,应此final方法无法生成代理。
CGLIB的实现也有两个重要的成员组成,Enhancer、MethodInterceptor
Enhancer:
来指定要代理的目标对象,实际处理代理逻辑的对象,
最终通过调用create() 方法得到代理对象、对这个对象所有的非 final 方法的调用都会转发给 MethodInterceptor。
MethodInterceptor:
动态代理对象的方法调用都会转发到 intercept 方法进行增强。
CGLIB动态代理详解
AOP
AOP(AspectOrientedProgramming):
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,实现代码解耦。
问题汇总
什么是反射:
在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个属性和方法。
哪里用到反射机制:
JDBC中,利用反射动态加载了数据库驱动程序。
Web服务器中利用反射调用了Sevlet的服务方法。
Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
很多框架都用到反射机制,注入属性,调用方法,如Spring。
反射机制的优缺点:
优点:可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。
缺点:对性能有影响,这类操作总是慢于直接执行java代码。
动态代理是什么?有哪些应用:
动态代理是运行时动态生成代理类。
动态代理的应用有 Spring AOP、测试框架的后端 mock、rpc,Java注解对象获取等。
怎么实现动态代理:
JDK 原生动态代理和 cglib 动态代理。
JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。