spring-4设计模式-源码解析

手动模拟的动态代理

  不需要手动创建类文件(因为一旦手动创建类文件,就会产生类爆炸),通过接口反射生成一个类文件,然后调用第三方的编译技术,动态编译这个产生的类文件成class文件,继而利用UrlclassLoader(因为这个动态产生的class不在工程当中所以需要使用UrlclassLoader)把这个动态编译的类加载到jvm当中,最后通过反射把这个类实例化。

  自己模拟的动态代理:

  缺点:首先要生成文件

  缺点:动态编译文件 class

  缺点:需要一个URLclassloader

  模拟过程:

  Fille --(读取file,生成类的类对象)--> class(byte[]) --(通过类的类对象)-->得到对象 (可以是 clazz.newInstance();直接new 或者通过constructor.newInstance("invoke ");构造方法new 出

 

1、手动创建handle接口

public interface InterfaceHandle {
    public Object invoke(Method method, Object[] args);
}

 

2、实现handle接口

public class User_InvoctionHandle implements InterfaceHandle {
    private Object target;

    public User_InvoctionHandle(Object target) {
        this.target = target;
    }

    public Object invoke(Method method, Object[] args) {
        System.out.println("我是自定义invoke方法");
        try {
            return method.invoke(this.target, null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
}

3、手写代理类(附带逻辑重写)

public class ProxyUtil {
    public static Object getInstance(Class targetInfo, User_InvoctionHandle handle) {
        Object proxy = null;
//        Class targetInfo = target.getClass().getInterfaces()[0];

        String tab = "\t";
        String line = "\n";

        String implName = targetInfo.getSimpleName();
        //创建java内容
        String javaContent = "";
        //package
        String packageContent = "package com.proxy;" + line;

        //importClass
        String impPackageContent = "import "+handle.getClass().getName()+";"+line+
                                   "import java.lang.reflect.Method;"+line+
                                   "import "+targetInfo.getName()+";"+line;

        //创建类体
        String classContent = "public class $Proxy implements " + implName + " {" + line;

        //创建私有对象handle
        String privateObject = tab + "private " + handle.getClass().getSimpleName() + " h;" + line;

        //创建构造,将handle当做对象
        String constructorContent = tab + "public $Proxy (" + handle.getClass().getSimpleName() + " h ){" + line;
        constructorContent +=   tab + tab + "this.h = h;";
        constructorContent +=   line + tab + "}" + line;

        //创建方法
        String methedContent = "";
        Method[] methods = targetInfo.getDeclaredMethods();
        for (Method method : methods) {
            //获取方法的返回类型
            String methodTypeName = method.getReturnType().getSimpleName();
            //获取方法的名字
            String methodName = method.getName();
            methedContent += tab + "public " + methodTypeName + " " + methodName + " (";
            //创建参数
            Object[] args = method.getParameterTypes();
            String argContent = "";
            for (int i = 0; i < args.length - 1; i++) {
                //获取参数的类型
                String argsTypeName = args[i].getClass().getSimpleName();
                //获取参数名称 i1 i2
                argContent = argsTypeName + " i" + i;
                if (i != args.length - 1) {
                    //多个参数的情况下需要使用','但是最后一个不需要
                    argContent += ",";
                }
            }
            //组装方法内容,会自动将方法与目标方法一致
            methedContent += argContent + "){"
                    + line + tab + tab +"try{"
                    + line + tab + tab + tab + "Method method = Class.forName(\""+targetInfo.getName()+"\").getDeclaredMethod(\""+method.getName()+"\");"+line + tab + tab + tab ;
            if(!"void".equals(methodTypeName)){
                methedContent+= "return ("+methodTypeName+")";
            }
                methedContent+=  "h.invoke(method,null);" + line
                    + tab + tab +"}catch(Exception e){"
                    + line + tab + tab + tab + "e.printStackTrace();"
                    + line + tab + tab +"}";
            if(!"void".equals(methodTypeName)){
                methedContent+= line + tab + tab +"return null;";
            }
            methedContent+= line + tab +"}"+line+line;

        }
        javaContent = packageContent + impPackageContent + classContent + privateObject +
                      constructorContent +
                      methedContent + line + "}";
        //1、使用IO字符流将创建好String 放到D盘中,用于查看是否存在问题。
        String filePath = "D:\\com\\proxy\\";
        String classFileName = "com.proxy.$Proxy";
        File fileDir = new File("D:\\com\\proxy\\");
        try {
            if (!fileDir.isDirectory()) {
                fileDir.mkdirs();
            }
            File file = new File("D:\\com\\proxy\\$Proxy.java");
            if (!file.exists()) {
                file.createNewFile();
            }
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.write(javaContent);
            fileWriter.flush();
            fileWriter.close();

            //创建java编译器
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            //第三方管理器
            StandardJavaFileManager fileMgr = javaCompiler.getStandardFileManager(null, null, null);
            //将java文件放到管理器中
            Iterable units = fileMgr.getJavaFileObjects(file);
            //创建编译任务
            JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileMgr, null, null, null, units);
            //开始启动任务
            task.call();
            fileMgr.close();

            //使用反射获取编译后的$Proxy对象
            URL [] urls = new URL[]{new URL("file:D:\\\\")};
            URLClassLoader ucl = new URLClassLoader(urls);
            Class clazz = ucl.loadClass(classFileName);
            Constructor constructor = clazz.getConstructor(User_InvoctionHandle.class);
            proxy = constructor.newInstance(handle);
            System.out.println("成功!");
        } catch (Exception e) {
            System.out.println("失败!");
            e.printStackTrace();
        }
        return proxy;
    }
}

  

4、测试

 public static void main(String args[]) {
        //调用手动写的代理
        ObjectDao objectDao = (ObjectDao) ProxyUtil.getInstance(ObjectDao.class, new User_InvoctionHandle(new User_Defined_Dao()));
        System.out.println(objectDao.queryStr());

      
    }

  

5、测试重生成的$Proxy代理类及class

自动生成代理类的编码

package com.dao;
import com.handle.User_InvoctionHandle;
import java.lang.reflect.Method;
import com.dao.ObjectDao;
public class $Proxy implements ObjectDao {
	private User_InvoctionHandle h;
	public $Proxy (User_InvoctionHandle h ){
		this.h = h;
	}
	public void query (){
		try{
			Method method = Class.forName("com.dao.ObjectDao").getDeclaredMethod("query");
			h.invoke(method,null);
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	public String queryStr (){
		try{
			Method method = Class.forName("com.dao.ObjectDao").getDeclaredMethod("queryStr");
			return (String)h.invoke(method,null);
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}


}

  

结果

JDK动态代理源码分析

  

猜你喜欢

转载自www.cnblogs.com/gnwzj/p/11117781.html