转载

通俗理解jdK/Cglib动态代理

看看了博客,查了查书,硬是被生涩的“官方概念定义”看的云里雾里~

所谓代理通俗来说就是让别人帮自己去做事,而不是自己亲自去做。spring的AOP日志打印就用了动态代理,在不改变原来代码的基础上,打印日志文件。而动态代理和静态代理的原理是一样的。主要区别是静态代理的代理类是手动写好的,而动态代理的代理类是动态生成的。

效果其实也是一样的,只是动态代理更像面向对象的封装性,在不同的地方调用同一个公用的方法。它能每次动态的生成一个代理类,不便于我们的维护。

如下案例:

静态代理

第一步:写个接口

public interface food {
    //吃饭
  public  void eat();
   //睡觉
  public  void sleep();
}

第二步:实现这个接口

public class foodImpl implements food {
    @Override
    public void eat() {
         System.out.println("到吃饭时间了!!");
    }
 
    @Override
    public void sleep() {
        System.out.println("到睡觉的时间了!!");
    }
}

第三步:实现一个代理类

/**
 * 创建代理类
 */
public class proxyTest implements  food{
    private food food = new foodImpl();//注意接口不能被实例化
    @Override
    public void eat() {
        System.out.println("吃饭前洗个手");
       /* System.out.println("到吃饭时间了!!");*/
        food.eat();
        System.out.println("吃完饭擦嘴");
    }
    @Override
    public void sleep() {
        food.sleep();
        System.out.println("熄灯");
    }
}

第四步:测试类

public class testmain {
 
    public  static  void main(String[] args){
 
        //用代理类
        proxyTest proxyTest = new proxyTest();
        proxyTest.eat();
        proxyTest.sleep();
 
    }
}

运行结果:

吃饭前洗个手

到吃饭时间了!!

吃完饭擦嘴

到睡觉的时间了!!

熄灯

如上红色字体就是代理类做的事情。但是有个弊端,每次我要代理一件事情的时候,都得去原来的代码上增加,很不方便我们去维护。

JDK动态代理

那什么是动态代理呢?可以理解为只是jdk帮我们已经把可以动态生成代理对象的类编译好,你只需要拿去用就可以了。从而避免我们自己去写很多代理类。

案例:

第一、二步如上

第三步:创建代理类我们直接实现InvocationHandler接口,重写invoke方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler {
   private Object object;//用于接收具体实现类的实例对象
   //使用带参数的构造器来传递具体实现类的对象
   public DynamicProxy(Object obj){
      this.object = obj;
   }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
        System.out.println("前置内容");
        method.invoke(object, args);
        System.out.println("后置内容");
        return null;
   }
}

第四步:测试类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class testDynamic {
        public static void main(String[] args) {
            foodImpl food = new foodImpl();
            InvocationHandler h = new DynamicProxy(food);
            food proxy = (food) Proxy.newProxyInstance(food.class.getClassLoader(), new Class[]{food.class}, h);
            proxy.eat();
            proxy.sleep();
     }
}

运行结果:

前置内容

到吃饭时间了!!

后置内容

前置内容

到睡觉的时间了!!

后置内容

我们发现每个方法都动态添加了内容。不用我们每次去改写源文件了。

Cglib动态代理的实现

JDK动态代理拥有局限性,那就是必须面向接口编程,没有接口就无法实现代理,我们也不可能为了代理而为每个需要实现代理的类强行添加毫无意义的接口,这时我们需要Cglib,这种依靠继承来实现动态代理的方式,不再要求我们必须要有接口。

第一步:添加Cglib的Maven依赖

 <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
 </dependency>

第二步:创建具体实现类User.java

public class food{
    public void eat(){
        System.out.println("到吃饭时间了");
    }
 }

第三步:创建实现MethodInterceptor接口的代理类

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
 
import java.lang.reflect.Method;
 
public class UserInterceptor implements MethodInterceptor {
 
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("预处理");
        Object object =  methodProxy.invokeSuper(o,objects);
        System.out.println("后处理");
        return object;
    }
 
}

第四步:创建测试类ProxyTest.java

import net.sf.cglib.proxy.Enhancer;
 
public class ProxyTest {
    public static void main(String[] args){
        Enhancer enchancer = new Enhancer();//字节码增强器
        enchancer.setSuperclass(food.class);//设置被代理类为父类
        enchancer.setCallback(new UserInterceptor());//设置回调
        food food= (food)enchancer.create();//创建代理实例
        food.eat();
    }
}

执行结果:

预处理

到吃饭时间了

后处理

区别

静态代理

简单,代理模式,是动态代理的理论基础。常见使用在代理模式

jdk动态代理

需要有顶层接口才能使用,但是在只有顶层接口的时候也可以使用,常见是mybatis的mapper文件是代理。使用反射完成。使用了动态生成字节码技术。

cglib动态代理

可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。

Post Views: 3

原文  http://www.xiwenblog.com/archives/1934
正文到此结束
Loading...