代理模式及应用

代理模式

定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

优点:

  1. 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  2. 代理对象可以扩展目标对象的功能;
  3. 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;

缺点:

  1. 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
  2. 增加了系统的复杂度

静态代理

Demo(smbj)

//InputStream 代理类
public class SharedInputStream extends InputStream {
private final SmbFile file;

private final InputStream inputStream;
    public SharedInputStream(SmbFile file) {
        this.file = file;
        this.inputStream = file.getInputStream();
    }
    @Override
    public void close() throws IOException {
        inputStream.close();
        file.close();
    }
}
//使用代理类
......
InputStream in = new SharedInputStream(file);
in.read(buff,offset,length);
in.close();
......

SharedInputStream 是InputStream的代理类,扩展了InputStream close功能,在InputStream close同时对SmbFile 也进行了close。像上面代理类在程序运行前就已经存在的称做静态代理。

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

动态代理

代理类在程序运行时创建的代理方式被成为动态代理,并且被代理的类必须是实现某个接口。

public abstract class BasePresenter<V extends IBaseView> implements IBasePresenter {

    private SoftReference<IBaseView> mReferenceView;
    private V mProxyView;

    @SuppressWarnings("unchecked")
    @Override
    public void attech(IBaseView view) {
        mReferenceView = new SoftReference<>(view);
        //设置动态代理
        mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws    Throwable {
                if (mReferenceView == null || mReferenceView.get() == null) {
                    return null;
                }
                return method.invoke(mReferenceView.get(), objects);
           }

        });

    }

    @SuppressWarnings("unchecked")
    public V getView() {
        return mProxyView;
    }
    @Override
    public void detech() {
        mReferenceView.clear();
        mReferenceView = null;
    }

}

在MVP模式模式中,我们经常会在Presenter中调用view的方法时,先进行view的判空,当然如果你用kotin直接使用?操作符就能解决,但用java一般就是在方法最前面执行if(view==null) returen;这样就显得比较麻烦,像上面的代码我们可以给view设置一个动态代理,在代理方法中进行view的判空,这样就简单的多。

动态代理主要通过Proxy.newProxyInstance进行创建

Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);

Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler 

Demo(smbj)

通过反射设置代理类添加打印,定位耗时操作在verifyPacketSignature方法中

public class Connection implements Closeable, PacketReceiver<SMBPacketData<?>>{
    private SMB2MessageConverter smb2Converter = new SMB2MessageConverter();
   ...
    @Override
    public void handle(SMBPacketData uncheckedPacket) throws TransportException {
      ...
        Request request = outstandingRequests.getRequestByMessageId(messageId);
        logger.trace("Send/Recv of packet {} took << {} ms >>", packetData, System.currentTimeMillis() - request.getTimestamp().getTime());
        SMB2Packet packet = null;
        try {
            packet = smb2Converter.readPacket(request.getPacket(), packetData);
        } catch (Buffer.BufferException e) {
            throw new TransportException("Unable to deserialize SMB2 Packet Data.", e);
        }
        long sessionId = packetData.getHeader().getSessionId();
        if (sessionId != 0L && (packetData.getHeader().getMessage() != SMB2MessageCommandCode.SMB2_SESSION_SETUP)) {
            Session session = sessionTable.find(sessionId);
            if (session == null) {
                session = preauthSessionTable.find(sessionId);
                if (session == null) {
                    logger.warn("Illegal request, no session matching the sessionId: {}", sessionId);
                    return;
                }
            }
            verifyPacketSignature(packet, session);
        }
        outstandingRequests.receivedResponseFor(messageId).getPromise().deliver(packet);
      ...
    }
   ...
}
//创建SMB2MessageConverter代理类,在readPacket添加打印,统计耗时
class ProxySMB2MessageConverter extends SMB2MessageConverter {
    private SMB2MessageConverter mSMB2MessageConverter;
    public ProxySMB2MessageConverter(SMB2MessageConverter smb2MessageConverter) {
        mSMB2MessageConverter = smb2MessageConverter;
    }
    @Override
    public SMB2Packet readPacket(SMBPacket requestPacket, SMB2PacketData packetData) throws Buffer.BufferException {
        long start = SystemClock.elapsedRealtime();
        SMB2Packet smb2Packet = super.readPacket(requestPacket, packetData);
        Log.i("JTime", "" + (SystemClock.elapsedRealtime() - start));
        return smb2Packet;
    }
}
//使用反射获取smb2MessageConverter属性,并创建代理类进行替换
SMB2MessageConverter smb2MessageConverter = Reflect.on(mConnection).get("smb2Converter");
ProxySMB2MessageConverter proxySMB2MessageConverter=new ProxySMB2MessageConverter(smb2MessageConverter);
Reflect.on(mConnection).set("smb2Converter",proxySMB2MessageConverter);

注意:Reflect是一个好用的java反射工具类,详情可见:

 

verifyPacketSignature是对smb数据包进行签名校验,获取数据包的签名,如果和header中的签名字段一致,代表是有效数据。通过session中的PacketSignatory类实现的,耗时主要在verify方法中。

private void verifyPacketSignature(SMB2Packet packet, Session session) throws TransportException {
    if (packet.getHeader().isFlagSet(SMB2MessageFlag.SMB2_FLAGS_SIGNED)) {
        if (!session.getPacketSignatory().verify(packet)) {
            logger.warn("Invalid packet signature for packet {}", packet);
            if (session.isSigningRequired()) {
                throw new TransportException("Packet signature for packet " + packet + " was not correct");
            }
        }
    } else if (session.isSigningRequired()) {
        logger.warn("Illegal request, session requires message signing, but packet {} is not signed.", packet);
        throw new TransportException("Session requires signing, but packet " + packet + " was not signed");
    }
}

处理:通过反射session设置PacketSignatory代理类,让verify方法始终返回true,来跳过接收数据的签名校验

//创建PacketSignatory代理类,接收一个PacketSignatory对象做被代理类
public class ProxyPacketSignatory extends PacketSignatory {
    private PacketSignatory mPacketSignatory;
    public ProxyPacketSignatory(PacketSignatory packetSignatory) {
        super(null, null);
        mPacketSignatory = packetSignatory;
    }
    @Override
    void init(byte[] secretKey) {
        mPacketSignatory.init(secretKey);
    }
    @Override
    boolean isInitialized() {
        return mPacketSignatory.isInitialized();
    }
    @Override
    SMB2Packet sign(SMB2Packet packet) {
        return mPacketSignatory.sign(packet);
    }
    @Override
    public boolean verify(SMB2Packet packet) {
        //让verify始终返回true,跳过签名校验
        return true;
    }
}
//反射设置代理类
private void cancelSignatureVerification() {
    PacketSignatory packetSignatory = Reflect.on(mSession).get("packetSignatory");
    ProxyPacketSignatory proxyPacketSignatory = new ProxyPacketSignatory(packetSignatory);
    Reflect.on(mSession).set("packetSignatory", proxyPacketSignatory);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值