Nivelle 开拓视野冲破艰险看见世界 身临其境贴近彼此感受生活

java反射机制,动态代理

2017-06-10
nivelle

java反射

  • 指的是可以于运行时加载探知和使用编译期间完全未知的类

  • 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已经加载的类,都能够知道这个类的所有属性和方法;对于一个对象,都能调用他的任意一个方法和属性

  • 加载完类之后,在堆内会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以称之为:反射。

  • 每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,通过该Class对象就可以访问到JVM中的这个类


首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object对象被加载到方法区中,创建了Object类的class对象在堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。


Class对象的获取

  • 对象的getClass()方法
public class classPersonDemo {
   public static void main(String args[])throws Exception{
     Person per = new Person();
     System.out.println(per.getClass().getName());
   }
}

class Person{};
  • 类的.class属性
public class classPersonDemo2 {
   public static void main(String args[])throws Exception{
     System.out.println(Person.class);
   }
}
  • 运用Class.forName(String className)动态加载类,className需要的是类的权限定名
public class classPersonDemo2 {
   public static void main(String args[])throws Exception{
     Class<?> cls = Class.forName("classPerson.Person2");
     Object obj = cls.newInstance();//实例化对象,和使用关键字new 一样
     Person2 per =(Person2)obj;
     System.out.println(per);
   }
   
}
从Class中获取信息

构造器 : ConstructorgetConstructor(Class<?>...parameterTypes)

public class classPersonDemo2 {
   public static void main(String args[])throws Exception{
     Class<?> cls = Person2.class;
     Constructor<?> cons = cls.getConstructor(String.class,Integer.class) ;
     Object obj = cons.newInstance("nivelle",23);
     System.out.println(obj);
     Constructor<?> cons2 [] = cls.getConstructors();
     for(int x=0;x<cons2.length;x++){
       System.out.println(cons2[x]);
     }
   }
   
}

包含的方法: Method getMethod(String name,Class<?>…parameterTypes)

public class classPersonDemo2 {
  public static void main(String args[]) throws Exception {
    Class<?> cls = Person2.class;
    String name = "nivelle";
    Object obj = cls.newInstance();
    Method getMet = cls.getMethod("getName");
    Method setMet = cls.getMethod("setName", String.class);
    setMet.invoke(obj, name);
    System.out.println(getMet.invoke(obj));
  }
}

包含的属性: Field getField(String name)

public class classPersonDemo2 {
  public static void main(String args[]) throws Exception {
    Class<?> cls = Person2.class;
    
    Field field[] =cls.getDeclaredFields();
    
    for(int x=0;x<field.length;x++){
      System.out.println(field[x]);
    }
    
  }
}

---

public class classPersonDemo2 {
  public static void main(String args[]) throws Exception {
    Class<?> cls = Person2.class;// 取得Class对象
    Object obj = cls.newInstance();// 对象实例化属性才会分配空间
    Field field=cls.getDeclaredField("name");// 找到name属性
    //利用反射操作类中属性
    field.setAccessible(true);
    field.set(obj, "nivelle");
    System.out.println(field.get(obj));
    field.setAccessible(false);
  }
}

包含的Annotation: A getAnnnotation(Class annotationClass);

内部类: Class<?>[]getDeclaredClasses()

外部类: Class<?>getDeclaringClass()

所实现的接口:Class<»[]getIntrfaces()

修饰符 int getModifiers()

所在包 Package getPackage()

类名 String getName()

简称 String getSimpleName()

一些判断类本身信息的方法

注解类型: booean isAnnotation()

使用了该Annotation:boolean isAnnotationPresent(Class<? extends Annotation>annotationClass)

匿名类: boolean isAnonymousClass()

数组: boolean isArray()

枚举: boolean isEnum()

原始类型: boolean isPrimitie()

接口: boolean isInterface()

obj是否是该Class的实例 boolean isInstance(Object obj)

动态代理机制

定义:为其他对象提供一种代理以控制这个对象的访问.


public interface Subject   
{   
  public void doSomething();   
}   
public class RealSubject implements Subject   
{   
  public void doSomething()   
  {   
    System.out.println( "call doSomething()" );   
  }   
}   
public class ProxyHandler implements InvocationHandler   
{   
  private Object proxied;   
     
  public ProxyHandler( Object proxied )   
  {   
    this.proxied = proxied;   
  }   
     
  public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable   
  {   
    //在转调具体目标对象之前,可以执行一些功能处理

    //转调具体目标对象的方法
    return method.invoke( proxied, args);  
    
    //在转调具体目标对象之后,可以执行一些功能处理
  }    
}


import java.lang.reflect.InvocationHandler;   
import java.lang.reflect.Method;   
import java.lang.reflect.Proxy;   
import sun.misc.ProxyGenerator;   
import java.io.*;   
public class DynamicProxy   
{   
  public static void main( String args[] )   
  {   
    RealSubject real = new RealSubject();   
    Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), 
     new Class[]{Subject.class}, 
     new ProxyHandler(real));
         
    proxySubject.doSomething();
   
    //write proxySubject class binary data to file   
    createProxyClassFile();   
  }   
     
  public static void createProxyClassFile()   
  {   
    String name = "ProxySubject";   
    byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject.class } );   
    try  
    {   
      FileOutputStream out = new FileOutputStream( name + ".class" );   
      out.write( data );   
      out.close();   
    }   
    catch( Exception e )   
    {   
      e.printStackTrace();   
    }   
  }   
}

动态代理内部实现

类Proxy代码实现Proxy的主要静态变量

// 映射表:用于维护类装载器对象到其对应的代理类缓存
private static Map loaderToCache = new WeakHashMap(); 

// 标记:用于标记一个动态代理类正在被创建中
private static Object pendingGenerationMarker = new Object(); 

// 同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass 进行相关的判断
private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap()); 

// 关联的调用处理器引用
protected InvocationHandler h;

Proxy的构造方法

// 由于 Proxy 内部从不直接调用构造函数,所以 private 类型意味着禁止任何调用
private Proxy() {} 

// 由于 Proxy 内部从不直接调用构造函数,所以 protected 意味着只有子类可以调用
protected Proxy(InvocationHandler h) {this.h = h;} 


Proxy静态方法newProxyInstance

public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException { 
    // 检查 h 不为空,否则抛异常
    if (h == null) { 
        throw new NullPointerException(); 
    } 

    // 获得与指定类装载器和一组接口相关的代理类类型对象
    Class cl = getProxyClass(loader, interfaces); 

    // 通过反射获取构造函数对象并生成代理类实例
    try { 
        Constructor cons = cl.getConstructor(constructorParams); 
        return (Object) cons.newInstance(new Object[] { h }); 
    } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); 
    } catch (IllegalAccessException e) { throw new InternalError(e.toString()); 
    } catch (InstantiationException e) { throw new InternalError(e.toString()); 
    } catch (InvocationTargetException e) { throw new InternalError(e.toString()); 
    } 
}


类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据:

我们可以import sun.misc.ProxyGenerator,调用 generateProxyClass方法产生binary data,然后写入文件,最后通过反编译工具来查看内部实现原理。 反编译后的ProxySubject.java Proxy静态方法newProxyInstance:

总结

一个典型的动态代理创建对象过程可分为以下四个步骤:

  • 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
  • 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类 Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  • 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型 Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  • 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入 Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
  • 为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。 生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))

下一篇 编程中的数学

评论