spring-4设计模式-代理动态,代理源码分析,实现自己的动态代理

什么事代理?

  就是对一个对象功能的增强,例如网上售票,代理的就是各个售票点的代理

 

java实现的代理两种办法

  名词:代理对象、 目标对象  。代理和目标不是绝对的,例如:故宫售票、网上售票、黄牛售票。故宫售票对于网上售票来说,前者属于目标对象,后者属于代理对象,网上售票和黄牛售票也是同理,所以代理对象与目标对象不是绝对的,会随着代码的改变而改变。

  静态代理:

    继承:代理对象继承目标对象,重写需要增强的方法

      缺点:对象太多,复杂。

下面代码模拟静态继承代理

 1、父类dao

package dao;

public class IndexDao implements Dao {
    public void query() {
        System.out.println("IndexDao_Query");
    }
}

  

2、子类(继承静态代理)

package dao;

public class LogDao extends IndexDao {

    @Override
    public void query() {
        System.out.println("插入日志_LogDao");
        super.query();
    }
}

  

3、测试

package test;

import dao.Dao;
import dao.LogDao;
import dao.TimeDao;

public class ProxyStaticTest {
    public static void main(String args[]){
        Dao dao = new LogDao();
        dao.query();

        Dao dao1 = new TimeDao();
        dao1.query();
    }
}

  

 

4、截图

 

    聚合:目标对象和代理对象实现同一接口,代理对象当中要包含目标对象(通过构造或者set),再次重新调用目标对象的方法并增强此方法

      缺点:也会产生过多的类(内存溢出)

  下面代码模拟静态聚合代理

  1、日志dao

package dao;

public class LogDao {

Dao dao;
public LogDao(Dao dao) {
this.dao = dao;
}


public void query() {
System.out.println("日志管理——LogDao");
dao.query();
}
}

  

 2、测试

package test;

import dao.Dao;
import dao.LogDao;
import dao.TimeDao;

public class ProxyStaticTest {
    public static void main(String args[]){
        Dao dao1 = new TimeDao();
        LogDao LogDao = new LogDao(dao1);
        LogDao.query();

    }
}

 

3、截图

 

    总结:静态代理只适合确定类的数量的情况下才能使用,否则就会出现类爆炸(类过多的问题)

    扩展:聚合静态代理很类似装饰者设计模式,只不过装饰者设计模式是用set方法将对象赋值。而聚合代理是用构造方法将对象赋值(IO中的类是用的就是装饰者设计模式)

    相关博客:https://www.cnblogs.com/ChrisRIM/archive/2012/08/21/2648372.html

 

  动态代理

  1、接口

package com.dao;

public interface ObjectDao {

    public void query();
}

  2、实现类

package com.dao;

public class User_Defined_Dao implements ObjectDao {

    public User_Defined_Dao() {
    }

    public void query() {
        System.out.println("自定义Dao中的query方法");
    }
}

  3、代理类

package com.proxy;

/*
 * 对象是如何生成的?
 * java
 * class
 * new
 * **/

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class ProxyUtil {


    public static Object getInstance(Object target) {
        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 " + targetInfo.getName() + ";" + line;
        //创建类体
        String classContent = "public class $Proxy implements " + implName + " {" + line;
        //创建私有变量
        String privateObject = tab + "private " + implName + " target;" + line;
        //创建构造
        String constructorContent = tab + "public $Proxy (" + implName + " target ){" + line;
        constructorContent = constructorContent + tab + tab + "this.target = target;" + line;
        constructorContent = constructorContent + 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 + "System.out.println(\"自定义Dao方法\");" + line
                    + tab;
            methedContent += tab + tab + "target." + methodName + "(" + argContent + ");";
            methedContent += line + tab + "}";
        }
        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(targetInfo);
            proxy = constructor.newInstance(target);
            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(new User_Defined_Dao());
        objectDao.query();
    }

  5测试结果

 

    

posted @ 2019-06-30 15:34  为了WZJ  阅读(276)  评论(0编辑  收藏  举报