动态代理的原理
我们可以看到动态代理是根据反射实现的,那么我们可以自己实现动态代理吗?
1、每个动态代理的类都实现这个方法,我们自己可以编写:
public interface MyInvocationHandler {
Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
2、编写自己的ClassLoader
public class MyClassLoaderextends ClassLoader{
private FileclassPathFile;
public MyClassLoader() {
String path = MyClassLoader.class.getResource("").getPath();
classPathFile =new File(path);
}
@Override
protected ClassfindClass(String name) {
String className = MyClassLoader.class.getPackage().getName()+"."+name;
FileInputStream inputStream =null;
ByteArrayOutputStream outputStream =null;
if (classPathFile!=null) {
File classFile =new File(classPathFile, name.replaceAll("\\.", "/") +".class");
try{
if (classFile.exists()) {
inputStream =new FileInputStream(classFile);
outputStream =new ByteArrayOutputStream();
byte[] buf =new byte[1024];
int len;
while ((len = inputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
}
return defineClass(className, outputStream.toByteArray(),0,outputStream.size());
}catch (Exception e){
}finally {
try {
inputStream.close();
outputStream.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
3、编写代理类:AgencyProxy
public class AgencyProxyimplements MyInvocationHandler {
private Objecttarget;
public ObjectgetInstance(Object target) {
this.target = target;
return MyProxy.newProxyInstance(new MyClassLoader(),target.getClass().getInterfaces(),this);
}
@Override
public Objectinvoke(Object proxy, Method method, Object[] args)throws Throwable {
Object obj = method.invoke(this.target, args);
return obj;
}
}
4、编写代生成代理的类:
public class MyProxy {
public static final Stringln="\r\n";
public static final StringCOMMA =",";
public static final StringRIGHT ="}";
public static ObjectnewProxyInstance(MyClassLoader classLoader, Class [] interfaces, MyInvocationHandler h){
//动态生成源代码 java 文件
try {
String src =generateSrc(interfaces);
System.out.println(src);
//java 磁盘输出
String path = MyProxy.class.getResource("").getPath();
File file =new File(path +"$Proxy0.java");
FileWriter fileWriter =new FileWriter(file);
fileWriter.write(src);
fileWriter.flush();
fileWriter.close();
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manager = javaCompiler.getStandardFileManager(null, null, null);
Iterable fileObjects = manager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = javaCompiler.getTask(null, manager, null, null, null, fileObjects);
task.call();
manager.close();
//编译生成的.class 文件加载到jvm里面来;
Class proxy0 = classLoader.findClass("$Proxy0");
Constructor constructor = proxy0.getConstructor(MyInvocationHandler.class);
file.delete();
return constructor.newInstance(h);
}catch (Exception e){
}
return null;
}
private static StringgenerateSrc(Class[] interfaces){
StringBuilder sb =new StringBuilder();
String page = interfaces[0].getPackage().getName();
sb.append("package "+page+";" +ln);
sb.append("import "+page +".*;"+ln);
sb.append("import java.lang.reflect.*;"+ln);
sb.append("public class $Proxy0 implements "+ interfaces[0].getName()+"{" +ln);
sb.append(ln);
sb.append("MyInvocationHandler h;"+ln);
sb.append("public $Proxy0 (MyInvocationHandler h) {" +ln);
sb.append("this.h = h;");
sb.append(RIGHT +ln);
for (Method method : interfaces[0].getMethods()) {
Class[] parameters = method.getParameterTypes();
StringBuilder parameterName =new StringBuilder();
StringBuilder parameter =new StringBuilder();
StringBuilder parameterTypes =new StringBuilder();
for (int i =0; i < parameters.length; i++) {
Class clazz = parameters[i];
String type = clazz.getName();
String paramName =toLowerFirstCase(clazz.getSimpleName());
parameterName.append(type +" " + paramName);
parameter.append(paramName);
parameterTypes.append(clazz.getName() +".class");
if (i >0 && i < parameters.length -1) {
parameterName.append(COMMA);
parameterTypes.append(COMMA);
parameter.append(COMMA);
}
}
sb.append("public " + method.getReturnType().getName() +" " + method.getName() +"(" + parameterName.toString() +") {" +ln);
sb.append("try {" +ln);
sb.append("Method m = " + interfaces[0].getName() +".class.getMethod(\"" + method.getName() +"\",new Class[]{" + parameterTypes.toString() +"});" +ln);
sb.append((hasReturnValue(method.getReturnType()) ?"return " :"") +
getCaseCode("this.h.invoke(this,m,new Object[]{" + parameter +"})", method.getReturnType()) +";" +ln);
sb.append("}catch(Error _ex){ ");
sb.append(ln);
sb.append(RIGHT);
sb.append("catch(Throwable e){" +ln);
sb.append(RIGHT +ln);
}
sb.append(RIGHT +ln);
sb.append(RIGHT +ln);
return sb.toString();
}
private static Mapmappings=new HashMap<>();
static {
mappings.put(int.class,Integer.class);
}
private static StringgetCaseCode(String s,Class returnType) {
if (mappings.containsKey(returnType)){
return "((" +mappings.get(returnType).getName()+")" +s+")."+ returnType.getSimpleName()+"Value()";
}
return s;
}
private static boolean hasReturnValue(Class returnType) {
return returnType !=void.class;
}
private static StringtoLowerFirstCase(String simpleName) {
char[] chars = simpleName.toCharArray();
chars[0] +=32;
return String.valueOf(chars);
}
}
其实就是字符串拼接;以上就是完成的字节编写的代理类。