代理模式详解

前言

代理模式在软件开发中经常用到,它是指为对象提供一种的代理,以控制对这个对象的访问。代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。代理模式主要有两种:静态代理和动态代理,接下来,我们就用实际例子来解释

静态代理

静态代理实现很简单,就是客户端不直接使用目标对象方法,而是调用代理对象方法,而代理对象方法里面调用目标对象,同时在其前后做相应的增强
显示生活中,大学生毕业往往面临找工作,找工作的方式有很多种,比如托亲戚帮忙找,下面我们就用这样一种场景来做案例来解释静态代理
我们首先定义一个接口
Person:

public interface Person {
    public void findJob();
}

然后定义学生类
Student :

public class Student implements Person{
    @Override
    public void findJob() {
        System.out.println("钱多活少离家近");
    }
}

最后是亲戚类
Qinqi:

public class Qinqi implements Person {
    private Student student;
    public Qinqi(Student student) {
        this.student = student;
    }
    @Override
    public void findJob() {
        System.out.println("亲戚开始帮忙寻找");
        this.student.findJob();
        System.out.println("找到了,签订劳务合同");
    }
}

可以看到亲戚类在构造中注入student,然后在findJob方法中调用student的findJob方法,同时在前后做了增强
测试

public class Test {
    public static void main(String[] args) {
        Qinqi qinqi = new Qinqi(new Student());
        qinqi.findJob();
    }
}

在这里插入图片描述
静态代理很简单,但是这里有一个问题,就是静态代理只能对特定的类进行代理,不具有普遍性,所以就出现了动态代理

动态代理

动态代理和静态代理的思路进本一致,只不过其应用的功能更加强大,下面我们还是用找工作来解释,比如社会上有很多帮忙找工作的猎头,可以帮助各种需要找工作的和需要工作人员的人提供帮助。
动态代理主要有两种实现方式:JDK实现方式和CGlib实现方式

JDK实现方式

定义代理类

JobProxy :

public class JobProxy implements InvocationHandler {
    private Object target;
    public Object getInstance(Object target) throws Exception {
        this.target=target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(this.target,args);
        after();
        return obj;
    }
    private void before() {
        System.out.println("我是中介,开始连线");
    }
    private void after() {
        System.out.println("如果合适的话,就签合同");
    }
}

这个类中,首先实现InvocationHandler 接口,然后在getInstance方法中将需要代理的对象进行注入等一系列操作,最后在invoke中对目标对象方法进行增强。

定义接口

jdk实现方式需要目标对象实现相应的接口,因为代理类的getInstance方法返回的是相应接口的类型
Employee:

public interface Employee {
    public void findJob() ;
}

Employer :

public interface Employer {
    public void findWorker();
}

我们定义了两个接口分别是雇佣者和被雇佣者

实现接口

Student :

public class Student implements Employee{
    @Override
    public void findJob() {
        System.out.println("员工要求:钱多活少离家近");
    }
}

Boss :

public class Boss implements Employer{
    @Override
    public void findWorker() {
        System.out.println("老板要求:听话勤快技术好");
    }
}

我们的Student 类和Boss 类分别实现了这两种接口

测试

Test :

public class Test {
    public static void main(String[] args) {
        try{
            Employee student = (Employee)new JobProxy().getInstance(new Student());
            student.findJob();
            Employer boss = (Employer)new JobProxy().getInstance(new Boss());
            boss.findWorker();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
通过测试我们可以看到,中介类对象可以对雇佣者和被雇佣者两种对象进行代理,这就是JDK方式的动态代理

CGlib方式的动态代理

我们还是上面找工作为例

引入CGlib

我们在pom.xml里引入CGlib相关依赖
pom.xml:

<dependency>
    <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>2.2.2</version>
 </dependency>

新建代理类

CglibJobProxy :

public class CglibJobProxy implements MethodInterceptor {
    public Object getInstance(Class<?> clazz) throws Exception {
        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 {
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }
    private void before() {
        System.out.println("我是中介,开始连线");
    }
    private void after() {
        System.out.println("如果合适的话,就签合同");
    }
}

我们代理类实现MethodInterceptor 接口,然后在getInstance中引入目标对象的class进行注入,最后在intercept方法中对相应方法进行加强

新建目标类

我们新建Student和Boss类,此时,这两个类就不需要实现什么接口了
Boss:

public class Boss{
    public void findWorker() {
        System.out.println("老板要求:听话勤快技术好");
    }
}

Student :

public class Student {
    public void findJob() {
        System.out.println("员工要求:钱多活少离家近");
    }
}

测试

Test :

public class Test {
    public static void main(String[] args) {
        try{
            Student student = (Student) new CglibJobProxy().getInstance(Student.class);
            student.findJob();
            Boss boss = (Boss)new CglibJobProxy().getInstance(Boss.class);
            boss.findWorker();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
测试中,我们可以看到,使用Cglib代理类对象的getInstance输入参数是目标对象的class,然后返回的类型也是目标对象的类型,这是Cglib与JDK代理使用方式最大的不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值