(五)Java架构师成长之路-设计模式:代理模式

一.定义

为其他对象提供一种代理,以便控制对这个对象的访问,起到一种中介的作用。

属于结构型模式

生活中的媒婆、快递小哥、房产中介等等都可以看做是代理模式。

二.详细介绍

代理模式分为两种,一种是静态代理,另一种是动态代理。

静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的.class文件就已经存在了,是一种硬

编码的方式。

动态代理:有jdk的动态代理和cglib的动态代理,是通过编译期间动态生成字节码文件来实现。

1.代码实现

静态代理

我们以生活中租房为例,先创建一个Person类,它有租房这个方法。

public class Person {

    public void findHouse() {
        System.out.println("我是租户,我想找房子");
    }
}

然后创建中介代理类,帮忙找房子

public class Agency {

    private Person person;

    public Agency(Person person) {
        this.person = person;
    }

    public void findHouse() {
        this.person.findHouse();
    }
}

在测试类中,我们创建一个中介类对象,构造方法传入租户对象

public class Test {

    public static void main(String[] args) {
        Agency agency = new Agency(new Person());
        agency.findHouse();
    }
}

静态代理的方式缺陷很明显,要代理的对象是硬编码的,这时候我们如果要代理其他对象就没办法做到了,代理类也是需要我们创建的。

动态代理

为了解决静态代理的问题,我们使用动态代理。

(1)jdk动态代理实现:

抽象出一个顶层接口:

public interface ISubject {

    void execute();
}

创建一个实现了ISubject的类RealSubject

public class RealSubject implements ISubject{

    public void execute() {
        System.out.println("execute...");
    }
}

jdk的动态代理是要实现InvocationHandler接口,然后我们重写它的invoke方法就好了,在真正的方法执行之前和之后我们可以干一些别的事情。这种方式就比较灵活,只要是实现ISubject接口的类都可以被代理。

public class SubjectJdkProxy implements InvocationHandler {

    private ISubject subject;

    public ISubject getInstance(ISubject subject) {
        this.subject = subject;
        Class clazz = subject.getClass();
        return (ISubject) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before...");
        Object object = method.invoke(this.subject, args);
        System.out.println("after...");
        return object;
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        SubjectJdkProxy subjectJdkProxy = new SubjectJdkProxy();
        ISubject subject = subjectJdkProxy.getInstance(new RealSubject());
        subject.execute();
    }
}

输出结果

可以看到。我们只是调用了execute方法,代理里自动帮我们对方法进行了增强,输出了before和after。

(2)cglib动态动态代理实现

这时候我们被代理的对象不需要实现任何接口

public class RealSubject {

    public void execute() {
        System.out.println("execute...");
    }
}

cglib的动态代理是需要实现MethodInterceptor接口,重写intercept方法

public class SubjectCglibProxy implements MethodInterceptor {

    public Object getInstance(Class clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        Object object = methodProxy.invokeSuper(o, objects);
        System.out.println("after");
        return object;
    }
}

测试类

public class Test {

    public static void main(String[] args) {
        RealSubject realSubject = (RealSubject) new SubjectCglibProxy().getInstance(RealSubject.class);
        realSubject.execute();
    }
}

输出结果

可以看到,通过cglib的动态代理我们也实现了同样的效果

(3)jdk和cglib动态代理的区别:

jdk的动态代理是通过实现接口实现的,目标对象需要实现一个接口,因为Proxy.newProxyInstance方法传入的参数需要它实现的接口;而cglib是通过继承实现的,它是创建了一个目标对象的子类。cjlib底层没有用到反射,效率更高。

三.spring中的代理

1.当bean有实现接口时,使用jdk动态代理

2.当bean没有实现接口时,使用cglib动态代理

3.可以强制spring使用cglib动态代理

四.代理模式的优缺点

优点:降低了耦合度,增强了目标对象的能力

缺点:增加了系统复杂度,使系统处理请求变慢

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值