zoukankan      html  css  js  c++  java
  • AOP实现JDK中的动态代理和cglib代理

    java.lang.reflect  Interface InvocationHandler

    可参考http://www.gznc.edu.cn/yxsz/jjglxy/book/Java_api/java/lang/reflect/InvocationHandler.html

    http://www.gznc.edu.cn/yxsz/jjglxy/book/Java_api/java/lang/reflect/Proxy.html

    invocation是“调用”的意思。这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事.InvocationHandler接口把我们的代理对象和被代理对象解耦了.动态代理类可以对任何实现某一接口的类进行功能性的增强。

    关于Method对象的invoke方法,根据java的反射机制可以获得某个对象的某个方法,也可以动态调用,假设已经获取了这个方法method.那么method.invoke(owner,args)就是动态调用,owner表示方法所属的对象,args为Object[]类型的方法参数。

    接口InvocationHandler的方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    proxy:在其上调用方法的代理实例(Proxy类型的对象)。

    method:对应于在代理实例上调用的接口方法的 Method 实例。。

    args:为方法的参数

     1 package proxy;
    2
    3 import java.lang.reflect.InvocationHandler;
    4 import java.lang.reflect.Method;
    5 import java.lang.reflect.Proxy;
    6 public class DynProxy implements InvocationHandler{
    7 private Object src;//被代理对象
    8 //bind为自定义方法,将src绑定到某个代理中
    9 //把当前对象(实现了InvocationHandler接口)传递给代理对象
    10 //返回代理对象
    11 public Object bind(Object src){
    12 this.src=src;
    13 Object proxy=Proxy.newProxyInstance(
    14 src.getClass().getClassLoader(),//被代理对象的类加载器
    15 src.getClass().getInterfaces(),//被代理对象实现的接口们,代理对象可以实现全部接口
    16 this //当前对象(实现了InvocationHandler接口) 回调,拦截到一个方法后可以触发哪个类中的哪个方法。
    17 );
    18 //返回的是一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
    19 return proxy;
    20 }
    21 //InvocationHandler接口方法
    22 //src(目标对象)中的每个方法会被此方法送去JVM调用,也就是说,src的方法只能通过此方法调用
    23 //此方法不能自己调用
    24 public Object invoke(Object proxy, Method method, Object[] args)
    25 throws Throwable {
    26 // TODO Auto-generated method stub
    27 System.out.println(method.getName()+"调用前");
    28 Object result=method.invoke(src, args);
    29 return result;
    30 }
    31 public static void main(String[] args) {
    32 Login src=new Login(); //被代理对象
    33 DynProxy dp=new DynProxy();
    34 ILogin proxy=(ILogin)dp.bind(src); //返回代理对象
    35 String username="tazi",password="123";
    36 proxy.login(username, password); //在代理实例上调用接口方法
    37 }
    38 }

    代理对象实现了目标对象的接口,使用时要用接口来引用代理对象。

    以上的代码改个名字更好理解:

     1 package com.tazi.aop;
    2
    3 import java.lang.reflect.InvocationHandler;
    4 import java.lang.reflect.Method;
    5 import java.lang.reflect.Proxy;
    6 //JDK方式的动态代理对象的创建工厂
    7 public class JDKProxyFactory implements InvocationHandler{
    8 private Object target;//目标对象
    9 //创建代理对象的方法
    10 //返回的是已经实现了目标对象所有接口的代理对象
    11 public Object createProxy(Object target){
    12 this.target=target;
    13 //以下前两个参数跟目标对象有关
    14 //第三个参数是一个包含回调方法(invoke)的对象(实现InvocationHandler接口)
    15 return Proxy.newProxyInstance(target.getClass().getClassLoader()
    16 , target.getClass().getInterfaces(),this);
    17 }
    18 //当拦截到目标对象某个方法时的回调方法
    19 public Object invoke(Object proxy, Method method, Object[] args)
    20 throws Throwable {
    21 // TODO Auto-generated method stub
    22 System.out.println("方法执行前");
    23 Object result=method.invoke(target, args);
    24 System.out.println("方法执行后");
    25
    26 return result;
    27 }
    28 }

    测试用例:

    package junit.test;

    import static org.junit.Assert.*;

    import org.junit.BeforeClass;
    import org.junit.Test;



    import com.tazi.aop.JDKProxyFactory;
    import com.tazi.aop.PersonService;
    import com.tazi.aop.PersonServiceBean;

    public class ProxyTest {
    private static JDKProxyFactory proxyFactory;
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    proxyFactory=new JDKProxyFactory();
    }
    @Test
    public void proxy() throws Exception {
    PersonService pService=(PersonService)proxyFactory.createProxy(new PersonServiceBean());
    pService.save("xxx");
    }
    }

    CGLIB实现动态代理

    但实际中情况会比较复杂,有可能目标对象没有实现接口。如果没有就不能创建代理对象。此时用到第三方的jar包来创建代理对象。cglib.jar。这时目标对象可以不实现接口。

    cglib的实现方式是创建被代理对象的子类,这个子类覆盖了目标对象的所有的非final的所有方法。然后设置回调方法。

     1 package com.tazi.aop;
    2
    3 import java.lang.reflect.Method;
    4
    5 import net.sf.cglib.proxy.Enhancer;
    6 import net.sf.cglib.proxy.MethodInterceptor;
    7 import net.sf.cglib.proxy.MethodProxy;
    8
    9 public class CglibProxyFactory implements MethodInterceptor{
    10 private Object target;
    11 public Object createProxy(Object target){
    12 this.target=target;
    13 Enhancer enhancer=new Enhancer();
    14 enhancer.setSuperclass(target.getClass());
    15 enhancer.setCallback(this);
    16 return enhancer.create();
    17 }
    18 public Object intercept(Object proxy, Method method, Object[] args,
    19 MethodProxy methodProxy) throws Throwable {
    20 System.out.println("方法执行前00");
    21 Object result=method.invoke(target, args);
    22 System.out.println("方法执行后00");
    23 return result;
    24 }
    25 }




     

  • 相关阅读:
    开源框架---通过Bazel编译使用tensorflow c++ API 记录
    图像处理---视频<->图片
    C++ ---释放内存(new和delete)
    目标检测---搬砖一个ALPR自动车牌识别的环境
    ubuntu系统---ubuntu16.04 + virtualenv + py2.7 + tf1.5.0 + keras2.2.4 + opencv2.4.9 +Numpy1.14
    Ubuntu系统---中英文问题小记
    Ubuntu系统---nvidia驱动下载之问题
    Ubuntu系统---又显示nvidia-smi 未找到命令
    Ubuntu系统---安装English版本之后的一些工作
    Ubuntu系统---安装“搜狗拼音法”导致桌面打不开
  • 原文地址:https://www.cnblogs.com/tazi/p/2299557.html
Copyright © 2011-2022 走看看