代理模式详解

Posted 前进道路上的程序猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代理模式详解相关的知识,希望对你有一定的参考价值。

代理模式详解

前言

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

静态代理

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

以上是关于代理模式详解的主要内容,如果未能解决你的问题,请参考以下文章

java设计模式详解:代理模式

详解 Java 中的三种代理模式

详解 Java 中的三种代理模式!

Java动态代理 深度详解

详解 Java 中的三种代理模式

大厂高级工程师面试必问系列:Java动态代理机制和实现原理详解