Spring的开发方式之一就是面向切面编程即AOP,AOP的核心构造是切面,它将那些影响多个类的行为封装到可重用的模块中。而AOP的原理就是java的动态代理机制。
本篇主要通过自定义一个Proxy类,来更深刻的理解动态代理的机制和原理。
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
public interface SelfInvocationHandler {
/**
*
* @param proxy 指代我们所代理的那个真实对象
* @param method 指代的是我们所要调用真实对象的某个方法的Method对象
* @param args 指代的是调用真实对象某个方法时接受的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable ;
}
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 自定义代理类
*/
public class SelfProxy {
private static String ln = "\r\n";
/**
*
* @param interfaces
* @return
*/
private static String generateStr(Class<?> interfaces) {
StringBuffer src = new StringBuffer();
src.append("package com.BXD._08Reflect.self;" + ln);
src.append("import java.lang.reflect.Method;" + ln);
src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
src.append("SelfInvocationHandler h;" + ln);
src.append("public $Proxy0(SelfInvocationHandler h){" + ln);
src.append("this.h=h;" + ln);
src.append("}" + ln);
for (Method m : interfaces.getMethods()
) {
src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
src.append("try{");
src.append("Method m=" + interfaces.getName() + ".class.getMethod(\"" + m.getName() + "\", new Class[]{});" + ln);
src.append("this.h.invoke(this,m,null);" + ln);
src.append("}" + ln);
src.append("catch(Throwable throwable){" + ln);
src.append("throwable.printStackTrace();" + ln);
src.append("}");
src.append("}" + ln);
}
src.append("}");
return src.toString();
}
/**
* Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象
* @param loader 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
* @param interfaces 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
* @param h 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
* @return
* @throws IOException
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws InstantiationException
*/
public static Object newProxyInstance(SelfClassLoad loader, Class<?>[] interfaces, SelfInvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.生成源代码
String proxySrc = generateStr(interfaces[0]);
//2.将生成的源代码输出到磁盘,保存为,java文件
String filePath = SelfProxy.class.getResource("").getPath();
File javaFile = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(javaFile);
fw.write(proxySrc);
fw.flush();
fw.close();
//3.编译源代码,并且生成.class文件
JavaCompiler compiler= ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager=compiler.getStandardFileManager(null,null,null);
Iterable iterable=manager.getJavaFileObjects(javaFile);
JavaCompiler.CompilationTask task=compiler.getTask(null,manager,null,null,null,iterable);
task.call();
manager.close();
//4.将class文件中的内容,动态加载到JVM中来
Class proxyClass = loader.findClass("$Proxy0");
//5.返回被代理后的代理对象
Constructor c=proxyClass.getConstructor(SelfInvocationHandler.class);
javaFile.delete();
return c.newInstance(h);
}
}
自定义ClassLoad类,用来将动态生成的.class文件加载到JVM中
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Created by Administrator on 2018/6/23.
* ClassLoader对象,对动态生成的.class文件加载到JVM
*/
public class SelfClassLoad extends ClassLoader{
private File baseDir;
/**
*
*/
public SelfClassLoad() {
String basePath=SelfClassLoad.class.getResource("").getPath();
this.baseDir=new File(basePath);
}
@Override
protected Class<?> findClass(String name) {
String className = SelfClassLoad.class.getPackage().getName() + "." + name;
if (baseDir!=null){
File classFile=new File(baseDir,name.replace("\\.","/")+".class");
if (classFile.exists()){
FileInputStream in=null;
ByteArrayOutputStream out=null;
try {
in=new FileInputStream(classFile);
out=new ByteArrayOutputStream();
byte[] buff=new byte[1024];
int len;
while ((len=in.read(buff))!=-1){
out.write(buff,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if (null!=in){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null!=out){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
classFile.delete();
}
}
}
return null;
}
}
定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外
**
* Created by Administrator on 2018/6/23.
* 定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口
*/
public class Meipo implements SelfInvocationHandler {
/**
* 这个就是我们要代理的真实对象
*/
private Person target;
public Object getInstance(Person target) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
this.target=target;
Class clazz=target.getClass();
System.out.println("被代理对象的class是:"+clazz);
return new SelfProxy().newProxyInstance(new SelfClassLoad(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("我是媒婆");
System.out.println("开始相亲。。。。");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(this.target,args);
System.out.println("结束相亲.......");
return null;
}
}
public interface Person {
//相亲
void findLove();
}
public class XiaoXingXing implements Person{
@Override
public void findLove() {
System.out.println("相亲要求");
System.out.println("高富帅");
System.out.println("有房车");
}
}
/**
* 自定义动态代理
*/
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Person xingxign=(Person)new Meipo().getInstance(new XiaoXingXing());
System.out.println(xingxign);
xingxign.findLove();
}
}