应用场景介绍,有一个People接口,接口方法eat。接口实现ZhangSan类的eat方法,打印出字符串"张三吃饭喜欢看手机!!"。利用代理的方法,在eat方法调用前,打出字符串"吃饭之前要洗手!!!"。在eat方法调用后,打出字符串"吃完饭以后要洗碗!!!"。
一、标准的jdk的动态代理
1、接口
/**
*
* @date 2019/10/22 19:30
*/
package com.proxy;
/**
* <类描述>
* @date 2019/10/22 19:30
* @version V1.0
*/
public interface People {
void eat() throws Throwable;
void sleep() throws Throwable;
void sport() throws Throwable;
}
2、接口实现类
/**
*
* @date 2019/10/22 19:31
* @version V1.0
*/
package com.proxy;
/**
* <类描述>
* @date 2019/10/22 19:31
* @version V1.0
*/
public class ZhangSan implements People {
@Override
public void eat() throws Throwable {
System.out.println("张三吃饭喜欢看手机!!");
}
@Override
public void sleep() throws Throwable {
System.out.println();
}
@Override
public void sport() throws Throwable {
System.out.println();
}
}
3、InvocationHandler接口实现类
/**
* @date 2019/10/22 19:36
* @version V1.0
*/
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* <类描述>
* 声明类
* @date 2019/10/22 19:36
* @version V1.0
*/
public class ProxyHandler implements InvocationHandler {
People people = null;
public ProxyHandler(People people){
this.people = people;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
method.invoke(people,null);
after();
return null;
}
private void before(){
System.out.println("吃饭之前要洗手!!!");
}
private void after(){
System.out.println("吃完饭以后要洗碗!!!");
}
}
4、JDK动态代理使用测试
/**
* @date 2019/10/22 19:39
* @version V1.0
*/
package com.proxy;
import sun.misc.ProxyGenerator;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
/**
* <类描述>
* @date 2019/10/22 19:39
* @version V1.0
*/
public class Test {
public static void main(String[] args) throws Throwable {
//Proxy.newProxyInstance内存中创建了一个类
People people = (People) Proxy.newProxyInstance(People.class.getClassLoader(),
new Class[]{People.class},new ProxyHandler(new ZhangSan()));
System.out.println("JDK的动态代理");
people.eat();
}
}
=============
执行结果如下:
JDK的动态代理
吃饭之前要洗手!!!
张三吃饭喜欢看手机!!
吃完饭以后要洗碗!!!
二、自己写动态代理
1、参考InvocationHandler接口,写自己的MyInvocationHandler接口
/**
* @date 2019/10/23 10:09
*/
package com.proxy;
import java.lang.reflect.Method;
/**
* <类描述>
* @date 2019/10/23 10:09
* @version V1.0
*/
public interface MyInvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
JDK提供的InvocationHandler接口信息如下图
2、实现MyInvocationHandler接口的MyProxyHandler
/**
* @date 2019/10/23 10:11
* @version V1.0
*/
package com.proxy;
import java.lang.reflect.Method;
/**
* <类描述>
* @date 2019/10/23 10:11
* @version V1.0
*/
public class MyProxyHandler implements MyInvocationHandler {
People people = null;
public MyProxyHandler(People people){
this.people = people;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
method.invoke(people,null);
after();
return null;
}
private void before(){
System.out.println("吃饭之前要洗手!!!");
}
private void after(){
System.out.println("吃完饭以后要洗碗!!!");
}
}
3、生成代理的MyProxy
/**
* @date 2019/10/23 10:05
* @version V1.0
*/
package com.proxy;
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;
/**
* <类描述>
* @date 2019/10/23 10:05
* @version V1.0
*/
public class MyProxy {
static String rt = "\r\n";
public static Object createProxyInstance(ClassLoader loader,Class intf,MyInvocationHandler handler){
Method[] methods = intf.getMethods();
//1、创建一个java文件,用流的方式
String proxyClass = "package com.proxy;" + rt
+ "import java.lang.reflect.Method;" + rt
+ "public class $Proxy0 implements " + intf.getName() + "{" + rt
+ "MyProxyHandler h;" + rt
+ "public $Proxy0(MyProxyHandler h) {" + rt
+ "this.h = h;" + rt + "}"
+ getMethodString(methods,intf) + rt + "}";
//2、把类生成文件
String fileName = "D:/workspace_study/springstudy/src/main/java/com/proxy/$Proxy0.java";
File f = new File(fileName);
try {
FileWriter fw = new FileWriter(f);
fw.write(proxyClass);
fw.flush();
fw.close();
//3、编译java文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,units);
t.call();
fileMgr.close();
//4、把class加载到内存
MyClassLoader loader1 = new MyClassLoader("D:/workspace_study/springstudy/src/main/java/com/proxy/");
Class proxy0Class = loader1.findClass("$Proxy0");
Constructor m = proxy0Class.getConstructor(MyProxyHandler.class);
Object o = m.newInstance(handler);
return o;
//1、
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
private static String getMethodString(Method[] methods,Class intf){
String proxyMe = "";
for(Method method : methods) {
proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt
+ "Method md = " + intf.getName() + ".class.getMethod(\"" + method.getName()
+ "\",new Class[]{});" + rt
+ "this.h.invoke(this,md,null);" + rt + "}" + rt;
}
return proxyMe;
}
}
4、MyClassLoader
/**
* @date 2019/10/23 11:21
* @version V1.0
*/
package com.proxy;
import java.io.*;
/**
* <类描述>
* @date 2019/10/23 11:21
* @version V1.0
*/
public class MyClassLoader extends ClassLoader {
private File dir;
MyClassLoader(String path){
dir = new File(path);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if(dir != null){
File clazzFile = new File(dir,name + ".class");
if(clazzFile.exists()){
FileInputStream input = null;
try {
input = new FileInputStream(clazzFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while((len = input.read(buffer)) != -1){
baos.write(buffer,0,len);
}
return defineClass("com.proxy." + name,baos.toByteArray(),0,baos.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(input != null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return super.findClass(name);
}
}
5、生成的$Proxy0信息