模拟JDK动态代理-独立逻辑代码

本文介绍了一种模拟JDK动态代理的方法,通过四个步骤实现:分析业务代码创建代理类源码、编译代理类源码、加载并实例化代理对象、返回代理对象。文中提供了详细的代码示例和说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


模拟JDK动态代理-独立逻辑代码

实现动态代理可以简单的分为四个步骤,我们只需要分析清楚逻辑代码流程,代码什么的都不是事,下面给大家简单介绍说下我的实现步骤。
1. 分析业务代码,明白需要横切的逻辑代码,通过File创建代理类的源码;
2. 使用JavaCompiler将代理类的源码进行编译成字节码文件;
3. 利用反射原理将字节码加载到JVM内存中,并实例化代理对象;
4. 返回代理对象以供调用;

话不多说,直接上代码吧!demo中使用的是项目jar包,文末附上源码


DEMO–查询方法添加一个记录查询时间的功能

步骤1

–项目结构
项目结构

–为query方法添加功能
为query方法添加功能

编写Proxy代理类

package com.coffice.proxy;


/**
 * Created by coffice on 2017-12-14.
 */

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import com.coffice.logic.ILogicExecute;

public class Proxy {

    //代理类java文件
    static File file;

    //代理类java文件的内容
    static String clazzContent="";

    //需要添加逻辑处理java类的接口类
    static Class invokeInterface;

    //获取当前操作系统临时目录
    static String rootDirectory=System.getProperty("java.io.tmpdir");

    //公开此方法用来获取代理对像
    public static Object getInstance(Class clazz,ILogicExecute preExcute,String ProxyFilDirectory) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
        if(ProxyFilDirectory != null)Proxy.rootDirectory = ProxyFilDirectory;
        File tempDirectory=new File(rootDirectory+"com\\proxy");
        createJavaFileFromContext(tempDirectory, createClassContext(clazz, preExcute));
        return compilerJavaFile(preExcute);
    }


    //公开此方法用来获取代理对像(重载)
    /**
     * 
     * @param clazz 需要代理的类
     * @param preExcute  独立逻辑代码处理类的对象
     * @return
     */
    public static Object getInstance(Class clazz,ILogicExecute preExcute) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{
        File tempDirectory=new File(rootDirectory+"com\\proxy");
        createJavaFileFromContext(tempDirectory, createClassContext(clazz, preExcute));
        return compilerJavaFile(preExcute);
    }

    /**
     * 使用JavaCompiler编译代理类
     * 
     * @param preExcute  独立逻辑代码处理类的对象
     * @return  返回代理对象
     */
    static Object compilerJavaFile(ILogicExecute preExcute) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
        JavaCompiler  compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMange = compiler.getStandardFileManager(null, null, null);
        Iterable it=fileMange.getJavaFileObjects(file.getPath());
        compiler.getTask(null, fileMange, null, null, null, it).call();
        URL url = new URL("file:/"+rootDirectory);
        URL[] urls = new URL[]{url};
        URLClassLoader  urlClassLoader = new URLClassLoader(urls);
        Class clazzProxy =urlClassLoader.loadClass("com.proxy.Proxy$");
        Constructor constructor= clazzProxy.getConstructor(invokeInterface);
        Object object =constructor.newInstance(preExcute);
        return object;
    }

    /**
     * 创建代理类的java文件
     * 
     * @param directory 代理类存放的文件目录
     * @param Context  创建的代理类的类容
     * @throws IOException
     */
    static void createJavaFileFromContext(File directory,String Context) throws IOException{
        if(!directory.exists() && !directory.isDirectory()){
            directory.mkdirs();
        }
        file=new File(directory+"\\Proxy$.java");
        if(!file.exists()){
        file.createNewFile();
        }
        FileWriter fw = new FileWriter(file);
        fw.write(clazzContent);
        fw.flush();
        fw.close();
    }

    /**
     * 生成代理类的内容
     * 
     * @param clazz 需要代理的类
     * @param preExcute  独立逻辑代码处理类的对象
     * @return  返回代理类的内容
     */
    static String createClassContext(Class clazz,ILogicExecute preExcute){
        String line="\n";
        String tab="\t";
        String methodContent="";

        //获取独立逻辑代码处理类所实现的接口
        invokeInterface=preExcute.getClass().getInterfaces()[0];
        //拼接代理类的头部以及构造函数
        clazzContent+="package com.proxy;"+line
                +"import java.lang.reflect.Method;"+line
                +"import "+clazz.getName()+";"+line
                +"import "+invokeInterface.getName()+";"+line
                    +"public class Proxy$ implements "+clazz.getSimpleName()+"{"+line
                    +tab+"private "+invokeInterface.getSimpleName()+" pre;"+line
                    +tab+"public Proxy$ ("+invokeInterface.getSimpleName()+" pre) {"+line
                    +tab+tab+" this.pre = pre;"+line
                    +tab+"}";
        Method[] methods = clazz.getMethods();

        //拼接代理类的方法(反射执行独立逻辑代码处理类中的方法,动态调用)
        for(Method m : methods){
            methodContent +=line+tab+"public void " + m.getName() +"(){"+line
             +tab+"try {"+line
             +tab+tab+"Method md = "+clazz.getSimpleName()+".class.getMethod(\""+m.getName()+"\");"+line
             +tab+tab+"pre.invoke(md);"+line
             +tab+"}catch(Exception e) {"+line
             +tab+tab+"e.printStackTrace();"+line+tab+"}"+line
             +tab+tab+"}";
        }
        clazzContent+=methodContent+line+line+tab+"}";
        return clazzContent;
    }






}

以上为Proxy.java核心代码,然后我们再看看逻辑处理java类的接口吧!

package com.coffice.logic;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public interface ILogicExecute {
    void invoke(Method method) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
}

那么问题来了,为什么我需要提供这个接口呢?这个时候反射的魅力就出来了,大家看图!

这里写图片描述

XXX.invoke();

想必这个方法大家是很熟悉的了,我们可以需要执行的dao层的方法作为参数传递给我们编写的实现了ILogicExecute接口的类,至于为什么有这个接口呢,是为了把我们说需要独立的逻辑代码封装在我们的实现类中执行,这样才做到逻辑代码的动态分离,我们的实现类中需要提供一个构造函数,来传递我们的dao层处理逻辑代码的目标对象,最后目标对象和方法在我们的ILogicExecute的实现类中都拿到了,通过invoke()方法就能执行目标对象的主逻辑代码了,我们也可以在这之间加入我们附加的代码。

这里写图片描述

最后我们来测试一下吧!

这里写图片描述

代理执行结果

这里写图片描述

so,我们若想给其他方法做处理,只需要在ILogicExecute的实现类中添加自己需要的代码即可!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值