代理设计模式

代理设计模式的作用

代理模式(Proxy Pattern)是指建立某一个对象的代理对象,并且由代理对象控制对原对象的引用。可以在目标对象的基础上,增强额外的功能操作,即扩展目标对象的功能.

  • 需求
    项目经理:有一天早上项目经理突然对小张说,小张啊现在给你分配一个需求,之前小王开发的那个接口的功能还不够完善你看着给他完善一下。。。
    小张:好的经理,突然小张心想他妈的我去改他的代码万一改出问题了咋办,那岂不是给自己增加工作量,那有没有一种方法可以在不改小王代码的前提下完成本次需求也了。。。突然小张灵机一动代理模式好像可以解决这个问题
    下面小张就开始写代码了

  • 首先
    小王写了一个 UserService 接口
public interface UserService {

    /**
     * 吃饭
     */
    void eat();

    void run();
}

小王写了一个 UserService 实现类 UserServiceImpl

public class UserServiceImpl implements UserService {

    @Override
    public void eat() {
        System.out.println("开始吃饭了哦");
    }

    @Override
    public void run() {
        System.out.println("跑步中");
    }
}
  • 小王接到的任务是在不动原来代码的前提下完成现有的功能
    上文说到小王想到可以使用动态代理完成现有的需求,鉴于本次更改的量比较小,所以首先使用静态代理完成本次需求
    1、创建静态 Proxy 类
public class UserProxy {

    private UserService target;

    public UserProxy(UserService target) {
        this.target = target;
    }

    public void enhanceEat() {
        before();
        target.eat();
        after();
    }
    
    // 前置增强
    public void before() {
        System.out.println("执行 eat 方法之前 需要先洗手");
    }
    // 后置增强
    public void after() {
        System.out.println("执行 eat 方法之后 需要先洗手");
    }
}
  • 2、静态代理测试
public class UserProxyTest {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserProxy userProxy = new UserProxy(userService);
        userProxy.enhanceEat();
    }
}


3、小王心想如何后面经理让我改很多个接口了,那岂不要写很多个代理类,妈的这也太麻烦了吧,要不试一下动态代理
4、编写代理类 UserHandler 需要实现 InvocationHandler 接口并重写 invoke 接口进行动态的方法增强

public class UserHandler implements InvocationHandler {

    private Object target;

    public UserHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置增强");
        Object res = method.invoke(target , args);
        System.out.println("后置增强");
        return res;
    }
}

5、测试动态代理

public class UserProxyTest {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ClassLoader loader = userService.getClass().getClassLoader();
        Class<?>[] interfaces = userService.getClass().getInterfaces();
        UserHandler userHandler = new UserHandler(userService);
        UserService o = (UserService)Proxy.newProxyInstance(loader, interfaces, userHandler);
        o.run();
    }
}

6、CGLIB 实现动态代理

public class ProxyFactory implements MethodInterceptor {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object newInstance() {
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置增强");
        method.invoke(target , args);
        System.out.println("后置增强");
        return null;
    }
}

7、CGLIB 动态代理测试

public class ProxyFactoryTest {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService userService1 = (UserService)new ProxyFactory(userService).newInstance();

        userService1.run();
    }
}

静态代理的优劣势

  • 优点
    实现简单不侵入原来的代码
  • 缺点
    1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
    2、代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

动态代理的优劣势

  • 缺点
    1、动态代理基于 Java 反射机制实现, 必须要实现了接口的业务类才能用这种方法生成代理对象
  • 优点
    1、不用创建代理类
    2、可以给不同的目标随时创建代理
posted @ 2023-07-08 15:07  ayiZzzz  阅读(10)  评论(0编辑  收藏  举报