博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring-4设计模式-代理动态,代理源码分析,实现自己的动态代理
阅读量:5110 次
发布时间:2019-06-13

本文共 6347 字,大约阅读时间需要 21 分钟。

什么事代理?

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

 

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中的类是用的就是装饰者设计模式)

    相关博客:

 

  动态代理

  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测试结果

 

    

转载于:https://www.cnblogs.com/gnwzj/p/11110035.html

你可能感兴趣的文章
文件流的使用以及序列化和反序列化的方法使用
查看>>
Android-多线程AsyncTask
查看>>
第一个Spring冲刺周期团队进展报告
查看>>
红黑树 c++ 实现
查看>>
Android 获取网络链接类型
查看>>
linux中启动与终止lnmp的脚本
查看>>
gdb中信号的处理[转]
查看>>
LeetCode【709. 转换成小写字母】
查看>>
如何在Access2007中使用日期类型查询数据
查看>>
Jzoj4757 树上摩托
查看>>
CF992E Nastya and King-Shamans(线段树二分+思维)
查看>>
oracle 几个时间函数探究
查看>>
第一个Java Web程序
查看>>
树状数组_一维
查看>>
如果没有按照正常的先装iis后装.net的顺序,可以使用此命令重新注册一下:
查看>>
linux install ftp server
查看>>
嵌入式软件设计第8次实验报告
查看>>
算法和数据结构(三)
查看>>
Ubuntu下的eclipse安装subclipse遇到没有javahl的问题...(2天解决了)
查看>>
alter database databasename set single_user with rollback IMMEDIATE 不成功问题
查看>>