代理模式(Proxy)

代理模式指的是:为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。

 


 

使用场景:

1、安全代理:屏蔽对真实角色的直接访问。

2、远程代理:通过代理类处理远程方法调用(RMI)。

3、延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。


分类:

1、静态代理:静态定义代理类。

  例子:静态代理设计模式

2、动态代理:动态生成代理类。

   实现方式:

  •   JDK自带的动态代理
  •   javassist字节码操作库实现
  •   CGLIB
  •   ASM

JDK自带的动态代理

实现:

  1、创建一个处理器,处理器继承 java.lang.reflect 包下的InvocationHandler 接口,组合真实对象,重写  invoke  方法,在invoke方法中实现对真实对象的控制访问。

  2、在需要代理角色的时候,通过java.lang.reflect.Proxy 类的静态方法    newProxyInstance(类加载器,处理器的构造器参数,处理器)获取一个代理对象。

 


例子:

Star  接口:

/**
 * 歌星
 */
public interface Star {
    void eat();//吃饭
    void sing();//唱歌
    void sleep();//睡觉
}

RealStar 真实对象:

/**
 * 歌星:佩奇
 */
public class RealStar implements Star{
    @Override
    public void eat() { System.out.println("佩奇吃饭饭"); }

    @Override
    public void sing() { System.out.println("我是一只佩奇~  我不会唱歌~"); }

    @Override
    public void sleep() { System.out.println("佩奇睡觉觉"); }
}

StarHandler  歌星处理器:实现 InvocationHandler 接口,组合 Star 类,重写 inboke 类。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 处理器
 */
public class StarHandler implements InvocationHandler {
    private Star star;//需要代理的对象

    public StarHandler(Star star) { this.star = star; }
/** * * @param o 代理对象 * @param method 获取的对象的方法 * @param objects 方法的参数 * @return * @throws Throwable */ @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { System.out.println("---------------invoke方法开始"); //调用的是吃饭,代理对象来处理 if(method.getName().equals("eat")){ System.out.println(o.getClass().getSimpleName()+":吃饭我来就行了"); } //如果是唱歌,那就让真正的歌星去唱歌。 if(method.getName().equals("sing")){ method.invoke(star,objects); } //调用的是睡觉,代理对象来处理 if(method.getName().equals("sleep")){ System.out.println(o.getClass().getSimpleName()+":睡觉我来就行了"); } System.out.println("---------------invoke方法结束"); return null; } }

测试:

import java.lang.reflect.Proxy;

public class Client {
    public static void main(String[] args) {
        //创建真实对象
        Star peiqi = new RealStar();
        //获取处理器
        StarHandler starHandler = new StarHandler(peiqi);
        //获取代理类对象:通过Proxy获取,需要指定类加载器、构造器参数、处理器。
        Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Star.class},
                starHandler);
        //代理角色吃饭干活
        proxy.eat();
        proxy.sing();
        proxy.sleep();
    }
}

运行结果:


cglib实现动态代理

使用第三方插件,基于字节码文件,生成真实对象的子类对象作为代理。

效率高于JDK自带的动态代理。

实现:

  1、准备真实对象

  2、准备回调对象,实现 net.sf.cglib.proxy.MethodInterceptor 接口,重写 intercept 方法,在 intercept 方法中实现对真实对象的控制访问。

  3、在需要代理角色的时候,创建 net.sf.cglib.proxy.Enhancer 类。

  4、通过  setSuperclass  方法设置被代理的对象它的的静态方法,通过setCallback方法设置回调对象。

  5、通过create方法获取代理对象(真实对象的子类)。


 

需要导入jar包:

 


例子:

真实对象:

/**
 * 真实对象歌星:佩奇
 */
public class RealStar{
    public void eat() { System.out.println("佩奇吃饭饭"); }

    public void sing() { System.out.println("我是一只佩奇~  我不会唱歌~"); }

    public void sleep() { System.out.println("佩奇睡觉觉"); }
}

回调对象:

public class ProxyStar implements MethodInterceptor {
    /**
     * @param o 真实对象
     * @param method 代理的方法对象
     * @param objects 方法参数
     * @param methodProxy 代理方法
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //调用的是吃饭,代理对象来处理
        if(method.getName().equals("eat")){
            System.out.println(methodProxy.getClass().getSimpleName()+":吃饭我来就行了");
        }
        //如果是唱歌,那就让真正的歌星去唱歌。
        if(method.getName().equals("sing")){
            //invokeSuper(),调用父类的方法
            methodProxy.invokeSuper(o,objects);
        }
        //调用的是睡觉,代理对象来处理
        if(method.getName().equals("sleep")){
            System.out.println(methodProxy.getClass().getSimpleName()+":睡觉我来就行了");
        }
        return null;
    }
}

测试:

public class Clients {
    public static void main(String[] args) {
        //动态代理对象
        Enhancer enhancer = new Enhancer();
        //设置被代理的对象
        enhancer.setSuperclass(CallbackStar.class);
        //设置回调对象
        enhancer.setCallback(new ProxyStar());
        //通过回调创建一个代理对象
        CallbackStar star = (CallbackStar) enhancer.create();
        //执行方法
        star.eat();
        star.sing();
        star.sleep();
    }
}

结果:

 

posted @ 2022-11-24 21:58  在博客做笔记的路人甲  阅读(502)  评论(0编辑  收藏  举报