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測試結果

 

    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章