欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JDK動(dòng)態(tài)代理過程原理及手寫實(shí)現(xiàn)詳解

 更新時(shí)間:2022年09月07日 15:35:02   作者:丨Jack_Chen丨  
這篇文章主要為大家介紹了JDK動(dòng)態(tài)代理過程原理及手寫實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

JDK動(dòng)態(tài)代理的過程

JDK動(dòng)態(tài)代理采用字節(jié)重組,重新生成對(duì)象來替代原始對(duì)象,以達(dá)到動(dòng)態(tài)代理的目的。

JDK中有一個(gè)規(guī)范,在ClassPath下只要是$開頭的.class文件,一般都是自動(dòng)生成的。

要實(shí)現(xiàn)JDK動(dòng)態(tài)代理生成對(duì)象,首先得弄清楚JDK動(dòng)態(tài)代理的過程。

1.獲取被代理對(duì)象的引用,并且使用反射獲取它的所有接口。

2.JDK動(dòng)態(tài)代理類重新生成一個(gè)新的類,同時(shí)新的類要實(shí)現(xiàn)被代理類實(shí)現(xiàn)的所有接口。

3.動(dòng)態(tài)生成Java代碼,新添加的業(yè)務(wù)邏輯方法由一定的邏輯代碼調(diào)用。

4.編譯新生成的Java代碼(.class文件)。

5.重新加載到VM中運(yùn)行。

手寫實(shí)現(xiàn)JDK動(dòng)態(tài)代理

JDK動(dòng)態(tài)代理功能非常強(qiáng)大, 接下來就模仿JDK動(dòng)態(tài)代理實(shí)現(xiàn)一個(gè)屬于自己的動(dòng)態(tài)代理。

創(chuàng)建MyInvocationHandler接口

參考JDK動(dòng)態(tài)代理的InvocationHandler 接口,創(chuàng)建屬于自己的MyInvocationHandler接口

public interface MyInvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

創(chuàng)建MyClassLoader類加載器

public class MyClassLoader extends ClassLoader {
    private File classPathFile;
    public MyClassLoader() {
        String classPath = MyClassLoader.class.getResource("").getPath();
        this.classPathFile = new File(classPath);
    }
    @Override
    protected Class<?> findClass(String name) {
        String className = MyClassLoader.class.getPackage().getName() + "." + name;
        if (classPathFile != null) {
            File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
            if (classFile.exists()) {
                FileInputStream in = null;
                ByteArrayOutputStream out = null;
                try {
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    int len;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }
                    return defineClass(className, out.toByteArray(), 0, out.size());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

創(chuàng)建代理類

創(chuàng)建的代理類是整個(gè)JDK動(dòng)態(tài)代理的核心

public class MyProxy {
    // 回車、換行符
    public static final String ln = "\r\n";
    /**
     * 重新生成一個(gè)新的類,并實(shí)現(xiàn)被代理類實(shí)現(xiàn)的所有接口
     *
     * @param classLoader       類加載器
     * @param interfaces        被代理類實(shí)現(xiàn)的所有接口
     * @param invocationHandler
     * @return 返回字節(jié)碼重組以后的新的代理對(duì)象
     */
    public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler invocationHandler) {
        try {
            // 動(dòng)態(tài)生成源代碼.java文件
            String sourceCode = generateSourceCode(interfaces);
            // 將源代碼寫入到磁盤中
            String filePath = MyProxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(sourceCode);
            fw.flush();
            fw.close();
            // 把生成的.java文件編譯成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manage.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
            task.call();
            manage.close();
            // 編譯生成的.class文件加載到JVM中來
            Class proxyClass = classLoader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(MyInvocationHandler.class);
            //刪除生成的.java文件
            f.delete();
            // 返回字節(jié)碼重組以后的新的代理對(duì)象
            return c.newInstance(invocationHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 動(dòng)態(tài)生成源代碼.java文件
     *
     * @param interfaces 被代理類實(shí)現(xiàn)的所有接口
     * @return .java文件的源代碼
     */
    private static String generateSourceCode(Class<?>[] interfaces) {
        StringBuffer sb = new StringBuffer();
        sb.append(MyProxy.class.getPackage() + ";" + ln);
        sb.append("import " + interfaces[0].getName() + ";" + ln);
        sb.append("import java.lang.reflect.*;" + ln);
        sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
        sb.append("MyInvocationHandler invocationHandler;" + ln);
        sb.append("public $Proxy0(MyInvocationHandler invocationHandler) { " + ln);
        sb.append("this.invocationHandler = invocationHandler;");
        sb.append("}" + ln);
        for (Method m : interfaces[0].getMethods()) {
            Class<?>[] params = m.getParameterTypes();
            StringBuffer paramNames = new StringBuffer();
            StringBuffer paramValues = new StringBuffer();
            StringBuffer paramClasses = new StringBuffer();
            for (int i = 0; i < params.length; i++) {
                Class clazz = params[i];
                String type = clazz.getName();
                String paramName = toLowerFirstCase(clazz.getSimpleName());
                paramNames.append(type + " " + paramName);
                paramValues.append(paramName);
                paramClasses.append(clazz.getName() + ".class");
                if (i > 0 && i < params.length - 1) {
                    paramNames.append(",");
                    paramClasses.append(",");
                    paramValues.append(",");
                }
            }
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames + ") {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses + "});" + ln);
            sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + getCaseCode("this.invocationHandler.invoke(this,m,new Object[]{" + paramClasses + "})", m.getReturnType()) + ";" + ln);
            sb.append("}catch(Error ex) { }");
            sb.append("catch(Throwable e){" + ln);
            sb.append("throw new UndeclaredThrowableException(e);" + ln);
            sb.append("}");
            sb.append(getReturnEmptyCode(m.getReturnType()));
            sb.append("}");
        }
        sb.append("}" + ln);
        return sb.toString();
    }
    /**
     * 定義返回類型
     */
    private static Map<Class, Class> mappings = new HashMap<Class, Class>();
    /**
     * 初始化一些返回類型
     */
    static {
        mappings.put(int.class, Integer.class);
        mappings.put(Integer.class, Integer.class);
        mappings.put(double.class, Double.class);
        mappings.put(Double.class, Double.class);
    }
    private static String getReturnEmptyCode(Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            if (returnClass.equals(int.class) || returnClass.equals(Integer.class)) {
                return "return 0;";
            } else if (returnClass.equals(double.class) || returnClass.equals(Double.class)) {
                return "return 0.0;";
            } else {
                return "return 0;";
            }
        } else if (returnClass == void.class) {
            return "";
        } else {
            return "return null;";
        }
    }
    /**
     * 判斷返回值類型
     *
     * @param code
     * @param returnClass
     * @return
     */
    private static String getCaseCode(String code, Class<?> returnClass) {
        if (mappings.containsKey(returnClass)) {
            // ((java.lang.Double) this.invocationHandler.invoke(this, m, new Object[]{})).doubleValue();
            String re = "((" + mappings.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName().toLowerCase() + "Value()";
            return re;
        }
        return code;
    }
    /**
     * 判斷代理接口的方法的返回值是否為void
     *
     * @param clazz 方法的返回值類型
     * @return
     */
    private static boolean hasReturnValue(Class<?> clazz) {
        return clazz != void.class;
    }
    /**
     * 參數(shù)首字母小寫
     *
     * @param src
     * @return
     */
    private static String toLowerFirstCase(String src) {
        char[] chars = src.toCharArray();
        if (chars[0] >= 'A' && chars[0] <= 'Z') {
            chars[0] += 32;
        }
        return String.valueOf(chars);
    }
    /**
     * 首字母大寫
     *
     * @param src
     * @return
     */
    private static String toUpperFirstCase(String src) {
        char[] chars = src.toCharArray();
        if (chars[0] >= 'a' && chars[0] <= 'z') {
            chars[0] -= 32;
        }
        return String.valueOf(chars);
    }
}

使用自定義動(dòng)態(tài)代理類

創(chuàng)建接口

public interface IUser {
    void shopping();
    Double expenses();
}

創(chuàng)建被代理接口

public class User implements IUser {
    @Override
    public void shopping() {
        System.out.println("user shopping....");
    }
    @Override
    public Double expenses() {
        return 50.5;
    }
}

創(chuàng)建代理接口

public class UseProxy implements MyInvocationHandler {
    private Object target;
    public Object myJDKProxy(Object target){
        this.target = target;
        Class&lt;?&gt; clazz =  target.getClass();
        return MyProxy.newProxyInstance(new MyClassLoader(),clazz.getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理user,執(zhí)行shopping()開始...");
        Object result = method.invoke(this.target, args);
        System.out.println("代理user,執(zhí)行shopping()結(jié)束...");
        return result;
    }
}

客戶端調(diào)用

    public static void main(String[] args) {
        UseProxy useProxy = new UseProxy();
        IUser user = (IUser) useProxy.myJDKProxy(new User());
        user.shopping();
        System.out.println(user.expenses());
    }

執(zhí)行結(jié)果

代理user,執(zhí)行shopping()開始...
user shopping....
代理user,執(zhí)行shopping()結(jié)束...
--------------------------------
代理user,執(zhí)行shopping()開始...
代理user,執(zhí)行shopping()結(jié)束...
--------------------------------
50.5

生成源代碼

查看生產(chǎn)的Java文件源代碼

package cn.ybzy.demo.proxy.proxy;
import cn.ybzy.demo.proxy.client.IUser;
import java.lang.reflect.*;
public class $Proxy0 implements cn.ybzy.demo.proxy.client.IUser{
MyInvocationHandler invocationHandler;
public $Proxy0(MyInvocationHandler invocationHandler) { 
this.invocationHandler = invocationHandler;}
public java.lang.Double expenses() {
try{
Method m = cn.ybzy.demo.proxy.client.IUser.class.getMethod("expenses",new Class[]{});
return ((java.lang.Double)this.invocationHandler.invoke(this,m,new Object[]{})).doubleValue();
}catch(Error ex) { }catch(Throwable e){
throw new UndeclaredThrowableException(e);
}return 0.0;}public void shopping() {
try{
Method m = cn.ybzy.demo.proxy.client.IUser.class.getMethod("shopping",new Class[]{});
this.invocationHandler.invoke(this,m,new Object[]{});
}catch(Error ex) { }catch(Throwable e){
throw new UndeclaredThrowableException(e);
}}}

以上就是JDK動(dòng)態(tài)代理過程原理及手寫實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于JDK動(dòng)態(tài)代理過程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • spring-boot-maven-plugin:unknown的完美解決方法

    spring-boot-maven-plugin:unknown的完美解決方法

    這篇文章主要介紹了spring-boot-maven-plugin:unknown的完美解決方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Spring Boot四大神器之CLI的具體使用

    Spring Boot四大神器之CLI的具體使用

    本文主要介紹了Spring Boot四大神器之CLI的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • springmvc注解配置實(shí)現(xiàn)解析

    springmvc注解配置實(shí)現(xiàn)解析

    這篇文章主要介紹了springmvc注解配置實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • java中反射和注解的簡(jiǎn)單使用方法

    java中反射和注解的簡(jiǎn)單使用方法

    相信大家對(duì)注解和反射應(yīng)該并不陌生,在現(xiàn)在信息飛速發(fā)展的年代,各種優(yōu)秀的框架或許都離不開注解的使用,這篇文章主要給大家介紹了關(guān)于java中反射和注解的簡(jiǎn)單使用方法,需要的朋友可以參考下
    2021-08-08
  • SpringMvc根據(jù)返回值類型不同處理響應(yīng)的方法

    SpringMvc根據(jù)返回值類型不同處理響應(yīng)的方法

    這篇文章主要介紹了SpringMvc根據(jù)返回值類型不同處理響應(yīng),我們可以通過控制器方法的返回值設(shè)置跳轉(zhuǎn)的視圖,控制器支持如void,String,ModelAndView類型,需要的朋友可以參考下
    2023-09-09
  • REST架構(gòu)及RESTful應(yīng)用程序簡(jiǎn)介

    REST架構(gòu)及RESTful應(yīng)用程序簡(jiǎn)介

    這篇文章主要為大家介紹了REST架構(gòu)及RESTful的應(yīng)用程序簡(jiǎn)介,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Springmvc基于fastjson實(shí)現(xiàn)導(dǎo)包及配置文件

    Springmvc基于fastjson實(shí)現(xiàn)導(dǎo)包及配置文件

    這篇文章主要介紹了Springmvc基于fastjson實(shí)現(xiàn)導(dǎo)包及配置文件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • java實(shí)現(xiàn)一個(gè)桌球小游戲

    java實(shí)現(xiàn)一個(gè)桌球小游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)一個(gè)桌球小游戲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Java內(nèi)存模型的深入講解

    Java內(nèi)存模型的深入講解

    這篇文章主要給大家介紹了關(guān)于Java內(nèi)存模型的相關(guān)資料,我們常說的JVM內(nèi)存模式指的是JVM的內(nèi)存分區(qū),而Java內(nèi)存模式是一種虛擬機(jī)規(guī)范,需要的朋友可以參考下
    2021-07-07
  • jar命令修改jar包中的application.yml配置文件

    jar命令修改jar包中的application.yml配置文件

    本文主要介紹了jar命令修改jar包中的application.yml配置文件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08

最新評(píng)論