Java 反射、动态代理
一、反射
1.1 是什么:
程序运行时能够动态的获得自身的信息,给定类的名字能够获得该类的属性以及方法
1.2 做什么:
在运行时判断任意一个对象所属的类。 在运行时判断任意一个类所具有的成员变量和方法。 在运行时任意调用一个对象的方法。 在运行时构造任意一个类的对象。
二、Class 类
Class 类是反射的基础,Class 可以帮助我们后去一个类的属性和方法Class 可以说是所有类的一个容器。创建的类的类信息都会保存在 Class中,每一种类类型都会具备一个 Class,Java 虚拟机(JVM)首先检查是否所要加载的类对应的 Class 对象是否已经加载。如果没有加载,JVM 就会根据类名查找.class 文件,并将其 Class 对象载入
三、反射优缺点
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在 J2EE 的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容, 进行反编译。对于 JAVA 这种先编译再运行的语言来说,反射机制可以使代码更加灵活, 更加容易实现面向对象。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉 JVM,我们希望做什么并且让它满足我们的要求。这类操作总是慢于直接执行相同的操作。
//获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"韦小宝");//执行有参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法
//反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给 null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给 null//反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法四、动态代理
静态代理
有某代理对象调用被代理的对象中的方法,代理对象可以额外的添加不同的操作扩展被代理对象的功能和职责
//被代理对象
public class StaticProxyClassImpl {
public void doSomething() {
System.out.println("staticProxy test");
}
}
//代理类
public class StaticProxy {
private StaticProxyClassImpl staticProxyClass ;
//传入代理对象
public StaticProxy(StaticProxyClassImpl staticProxyClass){
this.staticProxyClass = staticProxyClass;
}
public void doSomething() {
System.out.println("代理中");
staticProxyClass.doSomething();
System.out.println("代理结束");
}
}
class StaticMain{
public static void main(String[] args) {
StaticProxyClassImpl staticProxyClass = new
StaticProxyClassImpl();
StaticProxy staticProxy = new StaticProxy(staticProxyClass);
staticProxy.doSomething();
}
}动态代理
静态代理面对很多需要代理的类,需要手动重复的编写代理类,比较浪费精力和时间,动态代理可以解决这个问题动态代理可以在程序运行时动态生成,从而实现目标对象的代理
动态代理实现方式
1 、 JDK 动 态 代 理 : java.lang.reflect 包中的 Proxy 类 和InvocationHandler 接口提 供了生成动态代理类的能力。
2、Cglib 动态代理:Cglib (Code Generation Library )是一个第三方代码生成类 库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
区别:JDK 动态代理必须实现一个或多个接口类,CGLIB 无需实现接口类,达到代理类无侵入
JDK 动态代理
public class TestProxy implements InvocationHandler {
private Object object;
//输入代理对象
public TestProxy(Object object){
super();
this.object = object;
}
//这里是通过获取类加载器,在类加载器中将被代理对象注入到生成的代理类中,在自
己生成的代理类中
// 利用反射去获取被代理对象的方法,这里使用 proxy 就是去干这件事
public Object getProxy(){
return
Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader
(),
object.getClass().getInterfaces(), this);
}
//在调用代理对象之前打印日志。这是将我们需要的操作(扩展的方法),放到生成的
代理类的方法中。代理类也是继承自被代理对象的接口
@Override
public Object invoke(Object proxy, Method method, Object[]
args) throws Throwable {
System.out.println("proxy begin");
//执行代理对象的方法
Object result = method.invoke(object, args);
System.out.println("proxy end");
return result;
}
}CGLIB 动态代理
public class CGLIBProxy implements MethodInterceptor {
//代理对象
private Object object;
public CGLIBProxy(Object object){
super();
this.object = object;
}
/**
*
* @param o 代理对象
* @param method 被代理对象的方法
* @param objects 方法入参
* @param methodProxy 代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[]
objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB begin");
Object o1 = method.invoke(object,objects);
System.out.println("CGLIB end");
return o1;
}
}主方法
public class ProxyMain {
public static void main(String[] args) {
TestImpl test = new Test();
//JDK 动态代理
TestProxy testProxy = new TestProxy(test);
TestImpl proxy = (TestImpl) testProxy.getProxy();
proxy.say();
proxy.doSomething();
System.out.println("___________________________");
//CGLIB 动态代理
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(TestImpl.class);
//设置回调
enhancer.setCallback(new CGLIBProxy(test));
//获取代理对象
TestImpl cglibTest = (TestImpl) enhancer.create();
cglibTest.say();
cglibTest.doSomething();
}
}Jdk 动态代理比 cglib 动态代理的效率高Java 动态代理和 cglib 比较
生成代理类技术不同
java 动态代理:jdk 自带类 ProxyGenerator 生成 class 字节码
cglib:通过 ASM 框架生成 class 字节码文件
生成代理类的方式不同
java 动态代理:代理类继承 java.lang.reflect.Proxy,实现被代理类的接口
cglib:代理类继承被代理类,实现 net.sf.cglib.proxy.Factory
生成类数量不同
java 动态代理:生成一个 proxy 类
cglib:生成一个 proxy,两个 fastclass 类
调用方式不同
java 动态代理:代理类->InvocationHandler->反射调用被代理类方法
cglib:代理类->MethodInterceptor->调用索引类 invoke->直接调用被代理类方法