设计模式之代理模式

一、代理模式(静态代理)

举个生活小李子:

假如你现在需要买房,你是客户,但是你自己不想去找房源,你会找一个中介帮你去做这件事。

此时你就是被代理对象,而中介则是代理对象,代理对象可以帮你实现你不想实现的功能。

看代码:

// 客户
public interface User {
    // 找房源
    void findHouse();
}


// 我(被代理对象
public class Me implements User{
    @Override
    public void findHouse() {
        System.out.println("我自己找房子");
    }
}


// 代理对象(中介
public class UserProxy implements User{

    private User me;

    public UserProxy(User me) { //注入被代理对象
        this.me = me;
    }

    @Override
    public void findHouse() {
        System.out.println("中介帮你找房子");
    }
}

public class Main {
    public static void main(String[] args) {
        User me = new Me(); //被代理对象

        UserProxy proxy = new UserProxy(me);//代理对象

        proxy.findHouse(); //输出:中介帮你找房子
    }
}

通过代理对象,我们可以改变代码实现逻辑,或者增强原功能,比如说在调用方法后输出日志等。

但是这样做有什么缺点?

如果接口增加了一个功能,但是这个功能不需要由代理类来处理,但我们不得不修改代理类源代码,因此有了动态代理。

二、动态代理(核心:无侵入性地增强对象行为

假如你现在是中介,有几十个客户来找你看房子,一个个处理太麻烦,于是你开发了一个智能中介系统(动态代理)

客户->生成对应的中介


// 1. 动态代理处理器
public class UserHandler implements InvocationHandler {
    private Object user;

    public StarHandler(Object user) {
        this.user= user;
    }

    // 2. 所有方法调用都走这里
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        
        if ("findHouse".equals(methodName)) {
            System.out.println("动态代理看房子"); // 拦截
            return null;
        } else {
            // 其他方法原样执行
            return method.invoke(me, args);
        }
    }
}

// 3. 使用动态代理
public class Main {
    public static void main(String[] args) {
        User me= new Me();
        
        // 4. 动态生成代理对象
        User proxy = (User) Proxy.newProxyInstance(
            me.getClass().getClassLoader(),
            me.getClass().getInterfaces(),
            new UserHandler(me)
        );
        
        proxy.findHouse();
    }
}
关键点
  • InvocationHandler:所有方法调用的统一处理入口。

  • Proxy.newProxyInstance:动态生成代理类的实例。

  • 自动适配接口:接口新增方法时,无需修改代理逻辑。

使用案例:

  • Spring AOP:aop 使用动态代理技术实现对功能的增强
  • Spring 解决循环依赖问题
  • @Trancational注解:在方法上添加该注解,在执行该方法前拦截该方法,在方法执行前后添加事务开启和提交。
  • mybatis:动态代理生成mapper接口的实例,将接口方法转化为执行sql语句。
 动态代理的两种实现
类型 JDK动态代理 CGLIB动态代理
原理 基于接口 基于类继承(可代理无接口的类)
性能 生成快,调用慢 生成慢,调用快
Spring选择 目标类有接口时优先使用 目标类无接口时使用
示例 Proxy.newProxyInstance() Enhancer.create()

总结

  • 代理模式:找个中介帮你干活。

  • 动态代理:让程序自动生成中介。

你可能感兴趣的:(设计模式,设计模式,代理模式)