前言:spring中AOP的原理就是java的动态代理机制,动态代理又与反射相关,所以回顾一下反射与动态代理的知识。
Jvm利用类加载器将.class文件加载到jvm内存中,.class文件的二进制字节流转换为方法区的运行时数据结构,保存着类object的版本,字段,方法,接口等信息,同时在堆中生成每个类唯一的类型对象class对象,作为方法区类信息的访问入口。
Java反射机制让我们在编译期之外的运行期获得任何一个类的class对象,得到方法区中的类的接口,方法,字段等信息,也可以在运行期实例化对象。
Class demo1 = Class.forname(“Reflect.name”);//通过全限定名实例化Class对象
Class demo2 = new Demo().getInstance();
Class demo3 = Demo.class;
demo1.getClass().getName();
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