java反射和动态代理详解

前言:spring中AOP的原理就是java的动态代理机制,动态代理又与反射相关,所以回顾一下反射与动态代理的知识。

反射

 Jvm利用类加载器将.class文件加载到jvm内存中,.class文件的二进制字节流转换为方法区的运行时数据结构,保存着类object的版本,字段,方法,接口等信息,同时在堆中生成每个类唯一的类型对象class对象,作为方法区类信息的访问入口。

Java反射机制让我们在编译期之外的运行期获得任何一个类的class对象,得到方法区中的类的接口,方法,字段等信息,也可以在运行期实例化对象。

  • 实例化Class对象:
Class<?> demo1 = Class.forname(“Reflect.name”);//通过全限定名实例化Class对象
Class<?> demo2 = new Demo().getInstance();
Class<?> demo3 = Demo.class;
  • 通过一个实例对象获取完整包名和类名:

demo1.getClass().getName();

  • 通过Class对象实例化类的实例
a)无参构造器实例化:
 Person p = (Person) demo1.newInstance();
b)有参构造器实例化,先获取构造器:
Constructor<?> cons[] = demo.getConstructors();
Person p1 = (Person)cons[1].newInstance(“Rollen”);返回一个类的接口:
Class<?> demo = Class.forname(“Reflect.person”);
//保存所有的接口
Class<?> intes[] = demo.getInterfaces();
intes[i].getName();
  • 取得其他类的父类:
Class<?> temp = demo.getSuperclass();
temp.getName();
  • 获取其他类的构造函数:
Constructor<?> cons[] = demo.getConstructors();
  • 获取其他类的属性(字段):

//本类属性 (比如: public string name)
Field[] field = demo.getDeclaredFields();
//权限修饰符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
//属性类型
Class

//调用Person类中的sayChina方法
Method method = demo.getMethod(“sayChina”);
method.invoke(demo.newInstance());

//调用Person类中的sayHello方法
Method method = demo.getMethod(“sayHello”,String.class,int.class);
method.invoke(demo.newInstance(),”Rollen”,20);
  • 通过反射操作属性:
Class<?> demo = Class.forname(“Reflect.Person”);
Object obj = demo.newInstance();
Field field = demo.getDeclaredField(“sex”);
field.setAccessible(true);
field.set(obj,”男”);//设置sex属性为“男”

动态代理机制

 动态代理机制中有一个重要的类Proxy和一个重要接口InvocationHandler。先牢记三个概念:1.动态代理类,每一个动态代理类都是InvocationHandler的子类。2.代理对象,由Proxy.newProxyInstance(…)创建的代理对象,每一个代理对象都会关联一个动态代理类实例,当代理对象调用真实对象方法时会转换为对handler动态代理类的invoke方法的调用。 3.真实对象,我们想要代理的对象。

介绍完动态代理类,代理对象和真实对象的概念,我们通过一个实例来真正地了解动态代理模式是如何实现的:

首先定义一个Subject接口,定义rent()方法和hello()方法:

package Invocation;

/**
 * Created by kang on 17/9/28.
 */
public interface Subject {

    public void rent();

    public void hello(String hello);
}

定义一个realSubject接口,这个类是真实对象,也就是被代理对象:

package Invocation;

/**
 * Created by kang on 17/9/28.
 */
//真实对象
public class realSubject implements Subject {

    @Override
    public void rent() {
        System.out.println("I want to rent my house!");
    }

    @Override
    public void hello(String hello) {
        System.out.println("hello  " +hello);
    }
}

定义一个动态代理类,每一个动态代理类都需要实现InvocationHandler接口,在动态代理类中传入真实对象,然后每个代理对象绑定一个动态代理类实例,且每个动态代理类均有一个invoke方法。

package Invocation;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Created by kang on 17/9/28.
 */


//动态代理类MyInvocationHandler是InvocationHandler的子类,必须实现invoke方法
public class DynamicProxy implements InvocationHandler {

    //要代理的真实对象
    private Object object;

    //给要代理的真实对象赋值
    public DynamicProxy(Object object){
        this.object = object;
    }

    /**
     *
     * @param proxy  指创造的代理对象
     * @param method  指我们要代理的真实对象的某个方法的Method对象
     * @param args    指真实对象的某个方法的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //在代理真实对象前添加我们添加一些自己的操作
        System.out.println("before rent house");

        System.out.println("Method:" + method);

        //当代理对象调用真实对象的方法时,会自动跳转到动态代理类即InvocationHandler的子类的invoke方法来调用
        method.invoke(object,args);

        //代理真实对象后添加一些操作
        System.out.println("after rent house");

        return null;
    }
}

查看Client类:

package Invocation;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * Created by kang on 17/9/28.
 */
public class Client {

    public static void main(String[] args) {

        //subject是真实对象,handler是动态代理类,往动态代理类传入真实对象
        Subject realsubject = new realSubject();
        InvocationHandler handler = new DynamicProxy(realsubject);


        /**
         * 通过Proxy的newProxyInstance方法创建代理对象
         * 1.第一个参数handler.getClass().getClassLoader()表示用动态代理类的类加载器加载代理对象
         * 2.第二个参数realSubject.getClass().getInterfaces()传入真实对象的接口,所以代理对象也可以调用接口,使用真实对象的方法。
         *
         * 3.第三个对对象handler让代理对象与动态代理类联系起来,当代理对象调用真实对象的方法时可以自动跳转到执行handler的invoke方法。
         *
         */
        Subject subject = (Subject) Proxy.newProxyInstance(
                handler.getClass().getClassLoader(),realsubject.getClass().getInterfaces(),handler);

        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("nihao");

    }

}

我们先来看看控制台的输出:

com.sun.proxy.$Proxy0
before rent house
Method:public abstract void Invocation.Subject.rent()
I want to rent my house!
after rent house
before rent house
Method:public abstract void Invocation.Subject.hello(java.lang.String)
hello  nihao
after rent house


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值