Spring成神之路---aop---2

1.aop实例化模型
在这里插入图片描述
我们在使用切面时,当目标对象是多例时,默认生成的切面对象是单例的,为了符合业务场景,因此在某些情况下切面的创建也必须是多例的,可通过上述方式对切面类进行设置。

2.aop实现原理

1)手写jdk动态代理(山寨版)

为了更好的理解jdk动态代理的底层实现,因此自己手写了一个jdk的实现过程,主要原理一样,可以仔细研究一下哈。
public class ProxyUtilTwo
{
public static Object newInstance( Class targetInf,CxjInvocationHandler cxjInvocationHandler)
{
//获取接口名称
String infName = targetInf.getSimpleName();
String context = “”;
String line="\n";
String tab ="\t";

    //构建代理类中的通用数据
    String packageContext = "package com;"+line; //包名称
    String importantContent = "import "+targetInf.getName()+";"+line
            +"import java.lang.reflect.Method;"+line
            +"import java.lang.Exception;"+line
            +"import com.cxj.til.CxjInvocationHandler;"+line; //引入类名称

    //创建代理类
    String classFirstLineContent = "public class $Proxy implements "+infName+"{"+line;
    //创建属性
    String filedContnt = tab+"private CxjInvocationHandler h;"+line;
    //创建构造方法
    String constructorContent=tab+"public $Proxy (CxjInvocationHandler h ){"+line
            +tab+tab+"this.h=h;"
            +line+tab+"}"+line;

    String methodContent="";
    //获取接口的所有方法
    Method methods[] = targetInf.getDeclaredMethods();
    for (Method method : methods )
    {
        String returnTypeName = method.getReturnType().getSimpleName();
        String methodName = method.getName();
        Class args[] = method.getParameterTypes();
        //代理类中方法的定义形参
        String argsContent = "";
        //只包括形参名称
        String paramsContent="";
        //通过参数名获取到对应的类型
        String paramsTypes="";
        int flag = 0;
        //构造代理类中的方法
        for (Class arg : args) {
            String tmp = arg.getSimpleName();
            argsContent+=tmp+" p"+flag+",";
            paramsContent+="p"+flag+",";
            paramsTypes = "(p"+flag+").getClass(),";
            flag++;
        }
        if(argsContent.length() > 0)
        {
            argsContent = argsContent.substring(0,argsContent.length()-1);
            paramsContent = paramsContent.substring(0,paramsContent.length()-1);
            paramsTypes = paramsTypes.substring(0,paramsTypes.length()-1);
        }

        if(!paramsTypes.isEmpty())
        {
            methodContent += tab+"public "+returnTypeName+" "+methodName+"("+argsContent+") throws Exception {"+line
                    +tab+tab+"Method method = Class.forName(\""+targetInf.getName()+"\").getDeclaredMethod(\""+methodName+"\","+paramsTypes+");"+line
            ;
        }else
        {
            methodContent += tab+"public "+returnTypeName+" "+methodName+"("+argsContent+") throws Exception {"+line
                    +tab+tab+"Method method = Class.forName(\""+targetInf.getName()+"\").getDeclaredMethod(\""+methodName+"\");"+line
            ;
        }


        if(!returnTypeName.equals("void"))
        {
            methodContent +=tab+tab+"return ("+returnTypeName+") h.invoke(method,new Object[]{"+paramsContent+"});"+line
                    +tab+"}"+line;
        }else
        {
            methodContent +=tab+tab+" h.invoke(method,new Object[]{"+paramsContent+"});"+line
                    +tab+"}"+line;
        }

    }

    //拼接形成类字符串
    context = packageContext+importantContent+classFirstLineContent+filedContnt+constructorContent+methodContent+line+"}";

    //创建保留字符串的java文件
    File file = new File("e:\\com\\$Proxy.java");

    try {
        if(!file.exists())
        {
            file.createNewFile();
        }

        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write(context);
        fileWriter.flush();
        fileWriter.close();

        //将java文件动态编译为class文件

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);
        Iterable units = fileMgr.getJavaFileObjects(file);

        JavaCompiler.CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,units);
        t.call();
        fileMgr.close();

        //创建对象

        URL[] urls = new URL[]{new URL("file:E:\\\\")};
        URLClassLoader urlClassLoader = new URLClassLoader(urls);
        Class clazz = urlClassLoader.loadClass("com.$Proxy");
       return clazz.getConstructor(CxjInvocationHandler.class).newInstance(cxjInvocationHandler);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

}
相比与java的动态代理,山寨版的动态代理只是为了让读者更容易理解其中涉及的原理,很多细节和具体的实现没
有具体的实现,当然,其中最主要的是字节码的生成过程有较大的差异,望读者明白。

2)cglib动态代理

该代理有较多参考博客,读者可以查看,底层的字节码生成技术asm比较复杂,读者可以不用太深入研究,当然
,也不反对。

猜你喜欢

转载自blog.csdn.net/hdjansdasd/article/details/86246682
今日推荐