<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xx.xx</groupId>
<artifactId>project-train-proxy</artifactId>
<version>0.0.1</version>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerVersion>${java.version}</compilerVersion>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgs>
<arg>-verbose</arg>
<arg>-Xlint:unchecked</arg>
<arg>-Xlint:deprecation</arg>
<arg>-bootclasspath</arg>
<arg>${java.home}/lib/rt.jar${path.separator}${java.home}/lib/jce.jar</arg>
<arg>-extdirs</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.test.service;
import com.test.service.dto.UserDto;
public interface UserService {
public UserDto findHouse(UserDto userDto);
}
package com.test.service.impl;
import com.test.service.UserService;
import com.test.service.dto.UserDto;
import java.util.Random;
public class UserServiceImpl implements UserService {
@Override
public UserDto findHouse(UserDto userDto) {
try {
System.out.println(" findHouse:I'm finding house,maybe need some time...");
userDto.setHouseName("new House");
userDto.setId("01");
Thread.sleep(new Random().nextInt(10000));
System.out.println(" findHouse:I found a good house");
} catch (InterruptedException e) {
e.printStackTrace();
}
return userDto;
}
}
package com.test.service.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UserDto {
private String id;
private String name;
private String houseName;
}
package com.test;
import com.test.proxy.dynamicproxy.cglib.CGLibProxyFactory;
import com.test.proxy.dynamicproxy.jdkproxy.JDKProxyFactory;
import com.test.proxy.ownproxyhigher.SNProxyFactory;
import com.test.proxy.ownproxylower.SNProxy;
import com.test.proxy.staticproxy.SaticProxyByExtend;
import com.test.proxy.staticproxy.SaticProxyByReference;
import com.test.service.UserService;
import com.test.service.dto.UserDto;
import com.test.service.impl.UserServiceImpl;
import org.junit.Before;
import org.junit.Test;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by xx
* 2020/8/4.
*/
public class TestProxy {
//定义被代理对象
private UserService userService;
//查询参数
private UserDto userDto;
@Before
public void setUp() {
userService = new UserServiceImpl();
userDto = new UserDto(null, "张辉", "仙鹤门");
}
/**
* 自定义动态代理测试:高级版的自定义实现
*/
@Test
public void test6_ownProxyHigher() {
UserService userServiceProxy = SNProxyFactory.getInstance(userService);
userServiceProxy.findHouse(userDto);
}
/**
* 动态代理测试:测试JDK prxoy生成的字节码
*/
@Test
public void test7_ProxyGenerator() {
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[] { UserServiceImpl.class });
try (FileOutputStream os = new FileOutputStream("d://$ProxyUserServiceImpl.class")) {
os.write(bytes);
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.test.proxy.ownproxyhigher.framework;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by xx
* 2020/8/4.
*/
public class SNProxy {
//换行符
public static final String BR = "\r\n";
public static final String CLASS_PATH = "d:/src";
private static final String PACKAGE = "com";
private static final String CLASS_NAME = "$Proxy2";
public static Object newProxyInstance(ClassLoader classLoader, Class[] interfaces, SNInvocationHandler snInvocationHandler) {
//java代理类文件
File proxyFile = null;
try {
//1.生成java文件字符串
String src = generateJavaFileString(PACKAGE, CLASS_NAME, interfaces);
//2.将字符串转换成.java文件
proxyFile = generateFile(src);
//3.编译Java文件,生成.class文件
compileJavaFile(proxyFile);
//4.将.class文件加载到java虚拟机中
Class clazz = loadClass(classLoader);
//5.通过class反射获得对象,返回对象
Constructor constructor = clazz.getConstructor(SNInvocationHandler.class);
return constructor.newInstance(snInvocationHandler);
} 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();
} finally {
//6.清除中间生成的.java文件 .class文件
//proxyFile = null;
if (proxyFile != null) {
proxyFile.delete();
String javaFilePath = proxyFile.getPath();
String classFilePath = javaFilePath.substring(0, javaFilePath.lastIndexOf(".")) + ".class";
new File(classFilePath).delete();
}
}
return null;
}
private static Class loadClass(ClassLoader classLoader) throws ClassNotFoundException {
return classLoader.loadClass(PACKAGE + "." + CLASS_NAME);
}
private static void compileJavaFile(File proxyFile) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(proxyFile);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, compilationUnits);
task.call();
}
private static File generateFile(String src) {
String packagePath = CLASS_PATH + "/" + (PACKAGE.replaceAll("[.]", "/"));
//创建文件夹
File packageFile = new File(packagePath);
if (!packageFile.exists()) {
packageFile.mkdirs();
}
String filePath = packagePath + "/" + CLASS_NAME + ".java";
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
fileOutputStream.write(src.getBytes());
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
public static String generateJavaFileString(String packageName, String className, Class[] interfaces) {
Class interfaceClazz = interfaces[0];
Method[] declaredMethods = interfaceClazz.getDeclaredMethods();
StringBuffer sb = new StringBuffer();
sb.append("package ").append(packageName).append(";").append(BR);
sb.append("import java.lang.reflect.Method;").append(BR);
sb.append("import com.test.proxy.ownproxyhigher.framework.SNInvocationHandler;").append(BR);
sb.append("public class ").append(className).append(" implements ").append(interfaceClazz.getName()).append(" {").append(BR);
sb.append(" private SNInvocationHandler h;").append(BR);
sb.append("public " + className + "(SNInvocationHandler h) {this.h = h;}").append(BR);
for (Method method : declaredMethods) {
Class<?>[] parameterTypes = method.getParameterTypes();
sb.append("public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append(" ").append("(");
if (null != parameterTypes && 0 < parameterTypes.length) {
for (int i = 0; i < parameterTypes.length; i++) {
sb.append(parameterTypes[i].getName()).append(" p" + i);
if (i != parameterTypes.length - 1) {
sb.append(",");
}
}
}
sb.append(")").append(BR);
sb.append("{").append(BR);
sb.append(" try {").append(BR);
sb.append("Method method = " + interfaceClazz.getName() + ".class.getDeclaredMethod(").append("\"").append(method.getName())
.append("\"").append(",").append("new Class[]{");
for (int i = 0; i < parameterTypes.length; i++) {
sb.append(parameterTypes[i].getName()).append(".class ");
if (i != parameterTypes.length - 1) {
sb.append(",");
}
}
sb.append("}").append(");").append(BR);
sb.append("method.setAccessible(true);").append(BR);
sb.append("Object[] args = new Object[]{");
for (int i = 0; i < parameterTypes.length; i++) {
sb.append("p").append(i);
if (i != parameterTypes.length - 1) {
sb.append(",");
}
}
sb.append("};").append(BR);
if (!"void".equals(method.getReturnType().getName())) {
sb.append("return ("+method.getReturnType().getName()+")h.invoke(this,method,args);").append(BR);;
} else {
sb.append("h.invoke(this,method,args);").append(BR);
}
sb.append("}catch (Throwable throwable) {").append(BR);
sb.append("throwable.printStackTrace();").append(BR);
sb.append("}").append(BR);
if (!"void".equals(method.getReturnType().getName())) {
sb.append(" return null;");
}
sb.append("}").append(BR);
sb.append("}").append(BR);
}
//System.out.println(sb.toString());
return sb.toString();
}
}
package com.test.proxy.ownproxyhigher.framework;
import java.lang.reflect.Method;
/**
* Created by xx
* 2020/8/4.
*/
public interface SNInvocationHandler {
Object invoke(Object proxyObject, Method method, Object[] args) throws Throwable;
}
package com.test.proxy.ownproxyhigher.framework;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Created by xx
* 2020/8/4.
*/
@Getter
@Setter
@AllArgsConstructor
public class SNClassLoader extends ClassLoader{
private String classPath;
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = readClassFile(name);
return super.defineClass(bytes, 0, bytes.length);
}
private byte[] readClassFile(String name) {
String filePath = this.getClassPath() + "/" + (name.replaceAll("[.]", "/")) + ".class";
try (FileInputStream fileInputStream = new FileInputStream(filePath);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();) {
byte[] bytes = new byte[1024];
int count = -1;
while (-1 != (count = fileInputStream.read(bytes))) {
byteArrayOutputStream.write(bytes, 0, count);
}
return byteArrayOutputStream.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
package com.test.proxy.ownproxyhigher;
import com.test.proxy.ownproxyhigher.framework.SNClassLoader;
import com.test.proxy.ownproxyhigher.framework.SNProxy;
/**
* Created by xx
* 2020/8/4.
*/
public class SNProxyFactory {
public static <T> T getInstance(T target) {
SNClassLoader snClassLoader = new SNClassLoader(SNProxy.CLASS_PATH);
return (T) SNProxy.newProxyInstance(snClassLoader, target.getClass().getInterfaces(),
new LogSnInvocationHandler(target));
}
}
package com.test.proxy.ownproxyhigher;
import com.test.proxy.ownproxyhigher.framework.SNInvocationHandler;
import java.lang.reflect.Method;
/**
* Created by xx
* 2020/8/8.
*/
public class LogSnInvocationHandler implements SNInvocationHandler {
private Object target;
public LogSnInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxyObject, Method method, Object[] args) throws Throwable {
System.out.printf("come JDKProxyFactory,paramer={%s)\r\n", args);
long begin = System.currentTimeMillis();
Object result = method.invoke(this.target, args);
long end = System.currentTimeMillis();
System.out.printf("leave JDKProxyFactory,result={%s)\r\n", result);
System.out.printf("the time of the method costs is{%d}\r\n", end - begin);
return result;
}
}