[Java]動態代理

題目:使用動態代理編寫一個系統實現事務,其中,代理在被代理的調用成功時(不拋出任何異常)提執行提交,而在其執行失敗時執行回滾。你的提交和回滾都針對一個外部文本文件,該文件不在Java異常的控制範圍之內。你必須注意操作的原子性。

package test;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 使用Java動態代理實現事務,以向文件中寫入內容爲例
* */
public class FileWriter1Test {
    static File file = new File("D:\\test12.txt");    //寫入內容的目標文件
    static String s = "Hello World! 你好";
    public static void customer(FileWriter1 fileWriter1) {
        try {
            fileWriter1.writer(file,s);         //向file中寫入s
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        FileWriter1 proxy = (FileWriter1) Proxy.newProxyInstance(FileWriter1.class.getClassLoader(),
                new Class[]{ FileWriter1.class },
                new FileWriter1Handler(new FileWriter1Impl()));    //使用Proxy的靜態方法newProxyInstance創建代理對象,第一個參數爲ClassLoader,第二個參數爲代理所需要實現的接口,第三個參數爲調用處理器對象
        customer(proxy);   //使用代理
        //customer(new FileWriter1Impl());  //不使用代理
    }
}
/*
* 接口
* */
interface FileWriter1 {
    public abstract void writer(File file, String str) throws IOException;
}
/*
* FileWriter1接口的實現類,同時也是被代理的類
* */
class FileWriter1Impl implements FileWriter1 {
    @Override
    /*
    * 向file文件中寫入str
    * */
    public void writer(File file, String str) throws IOException {
        FileWriter fw = new FileWriter(file);
        fw.write(str);
        fw.close();
        //int i = 1/0;   //模擬寫入過程中出現錯誤
    }
}
/*
* 調用處理器
* */
class FileWriter1Handler implements InvocationHandler {
    private Object proxied;    //被代理的對象
    public FileWriter1Handler (Object proxied) {
        this.proxied = proxied;
    }
    @Override
    /*
    * 所有對代理的方法的調用都會在invoke方法中被集中處理
    * proxy是代理對象,method對象就是被調用的方法,args是參數數組
    * 在此方法中我們可以增加被代理的類的方法所不具有的功能,例如本例中增加的就是備份和回滾操作
    * */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        File file = (File)args[0];         //添加數據的目標文件
        File copyFile = new File("D:\\tem" + file.getName());   //目標文件的備份文件
        if (!copyFile.exists()) {
            copyFile.createNewFile();
        }
        copyFile(file, copyFile);         //備份文件
        try {
            Object invoke = method.invoke(proxied, args);  //反射,調用被代類的對應方法
        } catch (Exception e) {
            copyFile(copyFile,file);     //發生異常,回滾事務,將備份文件的內容再次恢復到原文件
        } finally {
            copyFile.delete();      //刪除備份文件
        }
        return null;
    }
    /*
    * 將原文件file備份到新的文件copyFile
    * */
    private File copyFile(File file,File copyFile) throws IOException{
        FileReader fr = new FileReader(file);
        FileWriter fw = new FileWriter(copyFile);
        char[] ch = new char[10];
        int n = 0;
        while ((n = fr.read(ch)) != -1) {
            fw.write(ch,0,n);
        }
        fr.close();
        fw.close();
        return copyFile;
    }
}

我的這個實現能夠滿足被代理調用成功時提交,被代理調用失敗時回滾。但是那如果我在備份文件或者回滾時發生了異常又該怎麼辦呢?如果有人有更好的解決辦法還請不吝賜教。謝謝!!!

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