JAVA笔记——代理模式

来源:互联网 发布:mac安装flash失败 编辑:程序博客网 时间:2024/06/06 00:26

  • 什么是代理
  • 静态代理
  • JDK实现动态代理
  • cglib动态代理

什么是代理

举个生活中的例子:有时候我们想要买火车票,但是火车站太远,那么我们可以去附近的火车票代售点进行购买。此时,代售点就是代理,它拥有被代理对象的部分功能——售票功能。

而在编程中,代理类同样拥有被代理类部分功能,但是不仅如此,代理类可以在此基础之上附加一些自己的功能

代理类最常见的用法就是日志功能:在被代理类执行方法之前,写下日志。

静态代理

需求:

现有一只鸟,它有一个fly方法,我们想在它fly的时候,写下日志

先写一个flyable接口:

public interface Flyable {    void fly();}

写一个bird,实现接口

public class Bird implements Flyable {    @Override    public void fly() {        System.out.println("bird is flying....");    }}

写一个日志代理类,注意,代理类也要实现同样的接口

public class LogProxy implements Flyable {    private Flyable f;    public LogProxy(Flyable f){        this.f = f;    }    @Override    public void fly() {        System.out.println("log is writing...");        f.fly();        System.out.println("over...");    }}

测试:

    public static void main(String[] args) {        Bird bird = new Bird();        Flyable f = new LogProxy(bird);        f.fly();    }

结果:

这里写图片描述

静态代理的缺陷也很明显,它只能代理实现了相同接口的类。随着系统业务的增长,需要代理的类可能非常多,那我们也要写非常多的代理类

因此,我们需要动态代理

JDK实现动态代理

JDK为我们提供了动态代理的能力。动态代理的优势在于,它不依赖于任何接口或类

我们先写好一个flyable和bird

public interface Flyable {    void fly();}
public class Bird implements Flyable {    @Override    public void fly() {        System.out.println("bird is flying....");    }}

JDK的动态代理,我们需要实现接口InvocationHandler,例如我们写一个日志的动态代理

public class LogHandler implements InvocationHandler {    private Object target;    public LogHandler(Object target) {        super();        this.target = target;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        System.out.println("log is writing...");        method.invoke(target, null);        System.out.println("over...");        return null;    }}

从上面代理类也可以看出,它不依赖于任何的类和接口

测试:

public class Test {    public static void main(String[] args) {        Bird bird = new Bird();        InvocationHandler h = new LogHandler(bird);        Class<?> cls = bird.getClass();        ClassLoader loader = cls.getClassLoader();        Flyable f = (Flyable) Proxy.newProxyInstance(loader, cls.getInterfaces(), h);        f.fly();    }}

结果:

这里写图片描述

JDK的动态代理也有一定的缺陷,它要求被代理的类必须实现某个接口,也就是说,JDK的动态代理是根据接口来实现的

cglib动态代理

除了JDK动态代理,我们也可以使用cglib来实现,二者的却别在于:cglib的动态代理是根据类来实现的,JDK的是根据接口来实现的

写一个bird类,有fly方法

public class Bird {    public void fly(){        System.out.println("bird is flying...");    }}

代理类:实现MethodInterceptor接口。cglib创建的代理类事实上是被代理类的子类,使用Enhancer来创建

public class LogProxy implements MethodInterceptor {    private Enhancer enhancer = new Enhancer();    /**     * 创建代理类     * @param cls     * @return     */    public Object getProxy(Class cls){        //设置父类        enhancer.setSuperclass(cls);        enhancer.setCallback(this);        //创建子类        return enhancer.create();    }    /**     * 拦截目标类的方法     * 参数:     * obj 被代理的对象     * m 被代理的对象的方法     * args 方法的参数     * proxy 代理类实例     */    @Override    public Object intercept(Object obj, Method m, Object[] args,            MethodProxy proxy) throws Throwable {        //此处我们可以做日志等操作        System.out.println("log .......");        //cglib创建的代理类其实是被代理类的子类,此处执行父类的方法,即执行被代理类真正要执行的方法        proxy.invokeSuper(obj, args);        return null;    }}

测试:

public class Test {    public static void main(String[] args) {        LogProxy proxy = new LogProxy();        Bird bird = (Bird) proxy.getProxy(Bird.class);        bird.fly();    }}

结果:
这里写图片描述

0 0