java 静态代理 jdk动态代理 使用方式 及实现原理 使用场景

java 代理 是什么?

静态代理 :一个接口 A ,一个实现类B ,我现在想要在实现B 的同时增加一个事务的功能,但是又不想改B 的代码,就可以增加一个代理类C(C 实现A ,引用B)

动态代理为啥出现?

我有100个类,他们实现的接口不同,但是我想在每个类里都增加记录事务的功能。如果用静态代理,我得写100个代理类。于是java 团队创造了动态代理。

 

静态代理代码实现:

B b=new B();

A c=new C(b);

c.do();

动态代理代码实现:

B b=new B();

自定义 TransactionInvocationHandler 类 内部 引用B ,并且实现InvocationHandler接口。

A c=Proxy.newProxyInstance(A.class,new TransactionInvocationHandler(b));

c.do();

 

java 动态代理实现主要靠Proxy 类和 InvocationHandler 接口

原理讲解:

Proxy类做了什么?

MyInvocationHanndlerI实现类做了什么?

package com.tgb.proxy;  

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;  
import javax.tools.JavaCompiler;  
import javax.tools.StandardJavaFileManager;  
import javax.tools.ToolProvider;  
import javax.tools.JavaCompiler.CompilationTask;  

public class Proxy {  
    /** 
     *  
     * @param infce 被代理类的接口 
     * @param h 代理类 
     * @return 
     * @throws Exception 
     */  
    public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {   
        String methodStr = "";  
        String rt = "\r\n";  

        //利用反射得到infce的所有方法,并重新组装  
        Method[] methods = infce.getMethods();    
        for(Method m : methods) {  
            methodStr += "    @Override" + rt +   
                         "    public  "+m.getReturnType()+" " + m.getName() + "() {" + rt +  
                         "        try {" + rt +  
                         "        Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +  
                         "        h.invoke(this, md);" + rt +  
                         "        }catch(Exception e) {e.printStackTrace();}" + rt +                          
                         "    }" + rt ;  
        }  

        //生成Java源文件  
        String srcCode =   
            "package com.tgb.proxy;" +  rt +  
            "import java.lang.reflect.Method;" + rt +  
            "public class $Proxy1 implements " + infce.getName() + "{" + rt +  
            "    public $Proxy1(InvocationHandler h) {" + rt +  
            "        this.h = h;" + rt +  
            "    }" + rt +            
            "    com.tgb.proxy.InvocationHandler h;" + rt +                           
            methodStr + rt +  
            "}";  
        String fileName =   
            "d:/src/com/tgb/proxy/$Proxy1.java";  
        File f = new File(fileName);  
        FileWriter fw = new FileWriter(f);  
        fw.write(srcCode);  
        fw.flush();  
        fw.close();  

        //将Java文件编译成class文件  
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();  
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);  
        Iterable units = fileMgr.getJavaFileObjects(fileName);  
        CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);  
        t.call();  
        fileMgr.close();  

        //加载到内存,并实例化  
        URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};  
        URLClassLoader ul = new URLClassLoader(urls);  
        Class c = ul.loadClass("com.tgb.proxy.$Proxy1");  

        Constructor ctr = c.getConstructor(InvocationHandler.class);  
        Object m = ctr.newInstance(h);  

        return m;  
    }  

}  

可以看到proxy 类的newProxyInstance 方法,主要作用就是根据参数1 接口类型 生成 代理类源代码,参数2 做为代理类的属性。

然后使用java 编译器 编译源码,并且 使用类加载器加载class 文件到内存获取class 对象,然后根据class 对象获取了代理对象。

package com.tgb.proxy;  

import java.lang.reflect.Method;  

public class TransactionInvocationHandler implements InvocationHandler {  

    private Object target;  

    public TransactionHandler(Object target) {  
        super();  
        this.target = target;  
    }  

    @Override  
    public void invoke(Object o, Method m,Object[] params) {  
        System.out.println("开启事务.....");  
        try {  
            m.invoke(target,params);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        System.out.println("提交事务.....");  
    }  

}  

invocationHandler (调用处理器)主要就是逻辑增强的代码部分,代理对象调用方法 的时候,

方法内部都会调用 h.invoke(this,method,params);    所以说 invocationHandler 是调用处理器。

换句话说 更准确是  代理类调用处理器。而这个处理器内部并不复杂。

调用处理器做的事儿就是   触发被代理对象的  方法( 代理类想要调用的那个方法)。

 

为什么jdk动态代理只能代理接口,不能代理类?

最初设计的就是代理接口,生成的代理类也是实现了接口的,代理和实现类无关,只和接口有关,

invocationhandler 才和实现类有关。

 

spring aop 如何实现?

如果是代理接口,则使用 jdk动态代理,如果是代理类,则使用CGLIB

 

aop 定义了一个切面类 ,切面类里定义了切点 和 切入位置

spring 会扫描所有切点,然后对切点做动态代理,入参的innovationhander类 是固定的,这个innovationhander 类里有2个属性,

1 个是 Object  被代理类 ,1个是 切面类 ,  innovationhander.invoke  方法内部实现逻辑应该是

先判断方法是否是切点的部分,如果不是,则直接执行method.invoke,如果是获取切面类的注解,

如果包含了before和after,则先执行切面类.before 在执行 method.invoke 再执行切面类.after

如果是around ,则执行切面类的around 完事儿。

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值