0
点赞
收藏
分享

微信扫一扫

Java后端中的服务隔离策略:如何避免服务之间的相互影响

Java架构领域 2024-10-01 阅读 13

前言

代码

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Newtonsoft.Json;

/// <summary>
/// 临时包装器
/// </summary>
/// <typeparam name="T">字段类型</typeparam>
/// <remarks>
/// 该类主要用于创造某个字段的副本作为该字段的临时缓存,避免直接修改源字段。
/// </remarks>
public class TempWrapper<T> : IDisposable
{
    /// <summary>
    /// 是否为值类型
    /// <para>提示:若为true则表示包装字段为值类型,否则为引用类型</para>
    /// </summary>
    public static bool isValueType => _isValueType;

    /// <summary>
    /// 缓存字段
    /// <para>提示:对于值类型而言,该属性涉及拷贝</para>
    /// </summary>
    public T value
    {
        get
        {
            if (_isDisposed) throw new InvalidOperationException("The wrapper is disposed.");
            return _value;
        }
        set
        {
            if (_isDisposed) throw new InvalidOperationException("The wrapper is disposed.");
            _value = value;
        }
    }

    /// <summary>
    /// 获取引用
    /// <para>提示:对于值类型而言,该属性直接返回引用从而避免拷贝</para>
    /// </summary>
    public ref T refrence
    {
        get
        {
            if (_isDisposed) throw new InvalidOperationException("The wrapper is disposed.");
            return ref _value;
        }
    }

    /// <summary>
    /// 是否已经释放
    /// </summary>
    public bool isDisposed => _isDisposed;

    static readonly bool _isValueType = typeof(T).IsValueType;
    static readonly bool _isDisposable = typeof(IDisposable).IsAssignableFrom(typeof(T));
    static readonly object _key = new object();
    T _value;
    bool _isDisposed;

    TempWrapper() { }

    /// <summary>
    /// 包装指定字段并返回包装类
    /// </summary>
    /// <param name="value">待包装字段的引用</param>
    /// <remarks>
    /// <para>提示:采用二进制序列化和反序列化生成字段副本</para>
    /// <para>提示:该方法仅可用于被 <c>Serializable</c> 标记的字段类型</para>
    /// </remarks>
    public static TempWrapper<T> WrapByBinary(ref T value)
    {
        lock (_key)
        {
            try
            {
                TempWrapper<T> wrapper = new TempWrapper<T>();

                if (_isValueType) wrapper._value = value;
                else
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        IFormatter formatter = new BinaryFormatter();
                        formatter.Serialize(ms, value);
                        ms.Seek(0, SeekOrigin.Begin);
                        wrapper._value = (T)formatter.Deserialize(ms);
                    }
                }

                return wrapper;
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Failed to wrap.", e);
            }

        }
    }

    /// <summary>
    /// 包装指定字段并返回包装类
    /// <para>提示:采用JSON序列化和反序列化生成字段副本</para>
    /// </summary>
    /// <param name="value">待包装字段的引用</param>
    public static TempWrapper<T> WrapByJson(ref T value)
    {
        lock (_key)
        {
            try
            {
                TempWrapper<T> wrapper = new TempWrapper<T>();

                if (_isValueType) wrapper._value = value;
                else
                {
                    string jsonStr = JsonConvert.SerializeObject(value);
                    wrapper._value = JsonConvert.DeserializeObject<T>(jsonStr);
                }

                return wrapper;
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Failed to wrap.", e);
            }
        }
    }

    /// <summary>
    /// 包装生成器所生成的字段并返回包装类
    /// </summary>
    /// <param name="creator">生成器</param>
    public static TempWrapper<T> WrapByCustom(Func<T> creator)
    {
        lock (_key)
        {
            try
            {
                TempWrapper<T> wrapper = new TempWrapper<T>() { _value = creator() };
                return wrapper;
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("Failed to wrap.", e);
            }
        }
    }

    /// <summary>
    /// 解包包装器并赋值给指定的字段
    /// </summary>
    /// <remarks>
    /// <para>提示:采用二进制序列化和反序列化解包</para>
    /// <para>提示:该方法仅可用于被 <c>Serializable</c> 标记的字段类型</para>
    /// </remarks>
    public void UnWrapByBinary(ref T value)
    {
        if (_isValueType) value = _value;
        else
        {
            lock (_key)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(ms, _value);
                    ms.Seek(0, SeekOrigin.Begin);
                    value = (T)formatter.Deserialize(ms);
                }
            }
        }
    }

    /// <summary>
    /// 解包包装器并赋值给指定的字段
    /// <para>提示:采用JSON序列化和反序列化解包</para>
    /// </summary>
    public void UnwrapByJson(ref T value)
    {
        if (_isValueType) value = _value;
        else
        {
            lock (_key)
            {
                string jsonStr = JsonConvert.SerializeObject(_value);
                value = JsonConvert.DeserializeObject<T>(jsonStr);
            }
        }
    }

    /// <summary>
    /// 释放包装器所包装的字段
    /// <para>提示:当所包装字段实现了IDisposable接口时该方法才有效</para>
    /// </summary>
    public void Dispose()
    {
        if (_isDisposed) return;

        DoDispose(true);
        GC.SuppressFinalize(this);
    }

    void DoDispose(bool disposing)
    {
        if (_isDisposed) return;

        _isDisposed = true;
        if (disposing && _isDisposable && _value is IDisposable ds)
            ds.Dispose();
    }

    ~TempWrapper()
    {
        DoDispose(false);
    }
}

测试

#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

// TempWrapper测试脚本
public class TempWrapperTest : MonoBehaviour
{
    [SerializeField] int[] intArray;
    [SerializeField] string[] strArray;
    [SerializeField] StructA[] structaArray;
    [SerializeField] ClassA classA;
    [SerializeField] StructA structA;
    [SerializeField] Transform tf;

    [Serializable]
    struct StructA
    {
        public string key;
        public int value;

        public override string ToString()
        {
            return $"(key:{key},value:{value})";
        }
    }

    [Serializable]
    class ClassA
    {
        public string key;
        public StructA structA;

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder("[key:");
            builder.Append(key).Append(",").Append($"StructA:{structA}");
            builder.Append("]");
            return builder.ToString();
        }
    }

    TempWrapper<int[]> intArrayWrapper;
    TempWrapper<string[]> strArrayWrapper;
    TempWrapper<StructA[]> structaArrayWrapper;
    TempWrapper<ClassA> classaWrapper;
    TempWrapper<StructA> structaWrapper;
    TempWrapper<Transform> tfWrapper;

    void Awake()
    {
        intArrayWrapper = TempWrapper<int[]>.WrapByBinary(ref intArray);
        strArrayWrapper = TempWrapper<string[]>.WrapByBinary(ref strArray);
        structaArrayWrapper = TempWrapper<StructA[]>.WrapByBinary(ref structaArray);
        classaWrapper = TempWrapper<ClassA>.WrapByBinary(ref classA);
        structaWrapper = TempWrapper<StructA>.WrapByBinary(ref structA);
        tfWrapper = TempWrapper<Transform>.WrapByCustom(() => Instantiate(tf));
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            PrintWrapper();
            PrintHashCode();
            PrintWrapperHashCode();
        }

        if (Input.GetKeyDown(KeyCode.W))
        {
            WriteWrapper();
            UnWrap();
        }
    }

    void PrintWrapper()
    {
        intArrayWrapper.value.LogC("IntArrayWrapper:");
        strArrayWrapper.value.LogC("StrArrayWrapper:");
        structaArrayWrapper.value.LogC(s => $"[key:{s.key},value:{s.value}]", "StructaArrayWrapper:");
        LogUtility.Log("ClassAWrapper:" + classaWrapper.value);
        LogUtility.Log("StructAWrapper:" + structaWrapper.value);
        LogUtility.Log("TfWrapper:" + tfWrapper.value.position);
    }

    void PrintHashCode()
    {
        LogUtility.Log("IntArray:" + intArray.GetHashCode());
        LogUtility.Log("StrArray:" + strArray.GetHashCode());
        LogUtility.Log("StructaArray:" + structaArray.GetHashCode());
        LogUtility.Log("ClassA:" + classA.GetHashCode());
        LogUtility.Log("StructA:" + structA.GetHashCode());
        LogUtility.Log("Tf:" + tf.GetHashCode());
    }

    void PrintWrapperHashCode()
    {
        LogUtility.Log("IntArrayWrapper:" + intArrayWrapper.value.GetHashCode());
        LogUtility.Log("StrArrayWrapper:" + strArrayWrapper.value.GetHashCode());
        LogUtility.Log("StructaArrayWrapper:" + structaArrayWrapper.value.GetHashCode());
        LogUtility.Log("ClassAWrapper:" + classaWrapper.value.GetHashCode());
        LogUtility.Log("StructAWrapper:" + structaWrapper.value.GetHashCode());
        LogUtility.Log("TfWrapper:" + tfWrapper.value.GetHashCode());
    }

    void WriteWrapper()
    {
        List<int> ints = new List<int>(intArrayWrapper.value) { 99, 100 };
        intArrayWrapper.value = ints.ToArray();

        List<string> strs = new List<string>(strArrayWrapper.value) { "D", "E" };
        strArrayWrapper.value = strs.ToArray();

        List<StructA> strcutAs = new List<StructA>(structaArrayWrapper.value)
        {
            new StructA { key = "D", value = 99 },
            new StructA { key = "E", value = 100 }
        };
        structaArrayWrapper.value = strcutAs.ToArray();

        structaWrapper.refrence.key = "E";
        structaWrapper.refrence.value = 1000;

        classaWrapper.value.key = "DE";
        classaWrapper.value.structA.key = "D";
        classaWrapper.value.structA.value = 999;

        tfWrapper.value.position = Vector3.zero;
    }

    void UnWrap()
    {
        intArrayWrapper.UnWrapByBinary(ref intArray);
        strArrayWrapper.UnWrapByBinary(ref strArray);
        structaArrayWrapper.UnWrapByBinary(ref structaArray);
        structaWrapper.UnWrapByBinary(ref structA);
        classaWrapper.UnWrapByBinary(ref classA);
    }
}
#endif
用例ID用例名称前者测试预期结果是否通过
1简单值类型数组可缓存通过
2不可变引用类型数组可缓存通过
3复合值类型数组可缓存通过
4自定义引用类型可缓存通过
5自定义值类型可缓存通过
6Unity对象可缓存通过

分析

版本改进

......

系列文章

......

如果这篇文章对你有帮助,请给作者点个赞吧!

举报

相关推荐

0 条评论