静态代理和动态代理模式

参考:Java 动态代理 两种实现方法

一、静态代理

Subject.java

package com.test.staticproxy;

/**
 * 需要代理的接口方法
 */
public interface Subject {
    // 需要代理的方法
    void request();
}

RealSubject.java

package com.test.staticproxy;

/**
 * 真实对象
 */
public class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("真正的角色");
    }
}

Proxy.java

package com.test.staticproxy;

/**
 * 代理者
 * 代码模式重点:需要持有一个真实对象
 * 被代理的对象就称为真实对象
 *
 */
public class Proxy implements Subject{
    //真实对象
    private Subject subject;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        System.out.println("begin");
        subject.request();
        System.out.println("end");
    }
}

代码测试入口函数
Test.java

package com.test.staticproxy;

import javax.security.auth.Subject;

public class Test {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.request();
    }
}

输出结果:

begin
真正的角色
end

二、动态代理

  动态代理中,代理类并不是在Java代码中实现,而是在运行时期生成,相比静态代理,动态代理可用很方便的对委托类的方法进行统一处理。
Subject.java

package com.test.staticproxy;

/**
 * 需要代理的接口方法
 */
public interface Subject {
    // 需要代理的方法
    void request();
}

RealSubject.java

package com.test.staticproxy;

/**
 * 真实对象
 */
public class RealSubject implements Subject{
    @Override
    public void request() {
        System.out.println("真正的角色");
    }
}

动态代理的核心类,只要实现动态代理必须要实现InvocationHandler 接口。
静态代理只能在外层进行包装,动态代理能够代理任何方法,作用发生在运行时。
MyInvocationHandler.java

package com.test.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
    // 真实对象类型
    private Object target;

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

    /**
     * 调用invoke
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        /**
         * method:当前代理的方法
         * target:代理的真实对象
         * args: 参数(形参)类型
         */
        Object result = method.invoke(target, args);
        System.out.println("after");
        return result;
    }
}

如果有多个方法的话,可以在invoke()方法中进行相关的接口方法判断
比如:

Object result = null;
if ("request".equals(method.getName())) {
   result = method.invoke(target, args);
}

测试代码主入口
Test.java

package com.test.dynamicproxy;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        //实例化
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(subject);
        /**
         * 第一个参数(classLoader): contextLoader
         * 第二个参数(接口数组):决定返回代理的对象实现了哪些接口
         * 第三个参数:代理时,需要处理具体的操作
         */
        Subject proxy = (Subject) Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                subject.getClass().getInterfaces(),
                myInvocationHandler);
        proxy.request();
    }
}

上面获取接口数组的方法也可以采用这种方式:

new Class[]{Subject.class}

但是个人推荐还是这种方法更好些

subject.getClass().getInterfaces()

proxy.request();
public Object invoke(Object proxy, Method method, Object[] args)

  执行proxy.request();这个语句时,首先会来到MyInvocationHandler类中,调用invoke()方法,将proxy.request()语句中的proxy对象传给invoke()方法中的第一个参数proxy,将当前调用的方法request传给invoke()方法中的第二个参数method,其实也就是Subject中的request()方法,再将Subject类中request()方法中的参数传给invoke()方法中的第三个参数args,这个里面参数为空。

输出结果:

before
真正的角色
after

三、角色

  • Subject
    抽象主题角色,是一个接口,该接口是对象和它的代理公用的接口。

  • RealSubject
    真实主题角色,是实现抽象主题接口的类

  • Proxy
      代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
      实现动态代理关键技术是反射。

demo代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值