`
elicer
  • 浏览: 133395 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

AOP Cache的 HashCode cachekey 实现

阅读更多
AOP的cache  大家都很熟悉,关于cachekey的生成方式有多种,最简单的是className+methodName+parameters ,这种方法的弊端太多,如果parameter是一个复合对像,那么在拼key时就比较麻烦。
我在以前的一片文章中讲过用annotation来标注复合对象中需要作为cache的子对象,能解决复合对象generate cachekey的问题,但这是一种侵入式的,需要加入额外的代码,真正的AOP cache应该式非侵入式的,就是cache的生效不需要其它代码有任何额外的工作。做function的程序员不需要关心cache的任何东西,cache对他们来说是透明的。
所以这里我想到了一种用HashCode来作为AOP cache的实现。这样不管参数的类型是什么,对于我generate cachekey 都没有影响。
具体实现类:

Key generate Interface

import java.io.Serializable;

import org.aopalliance.intercept.MethodInvocation;

/**
 * <p>
 * Generates a unique key based on the description of an invocation to an
 * intercepted method.
 * </p>
 * 
 * @author Elicer Zheng
 */
public interface CacheKeyGenerator {

  /**
   * Generates the key for a cache entry.
   * 
   * @param methodInvocation
   *          the description of an invocation to the intercepted method.
   * @return the created key.
   */
  Serializable generateKey(MethodInvocation methodInvocation);
}





CacheGenerate 实现类

import java.io.Serializable;
import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInvocation;



/**
 * <p>
 * Generates the key for a cache entry using the hashCode of the intercepted
 * method and its arguments.
 * </p>
 * 
 * @author Elicer Zheng
 */
public class HashCodeCacheKeyGenerator implements CacheKeyGenerator {

  /**
   * Flag that indicates if this generator should generate the hash code of the
   * arguments passed to the method to apply caching to. If <code>false</code>,
   * this generator uses the default hash code of the arguments.
   */
  private boolean generateArgumentHashCode;

  /**
   * Construct a <code>HashCodeCacheKeyGenerator</code>.
   */
  public HashCodeCacheKeyGenerator() {
    super();
  }

  /**
   * Construct a <code>HashCodeCacheKeyGenerator</code>.
   * 
   * @param generateArgumentHashCode
   *          the new value for the flag that indicates if this generator should
   *          generate the hash code of the arguments passed to the method to
   *          apply caching to. If <code>false</code>, this generator uses
   *          the default hash code of the arguments.
   */
  public HashCodeCacheKeyGenerator(boolean generateArgumentHashCode) {
    this();
    setGenerateArgumentHashCode(generateArgumentHashCode);
  }

  /**
   * @see CacheKeyGenerator#generateKey(MethodInvocation)
   */
  public final Serializable generateKey(MethodInvocation methodInvocation) {
    HashCodeCalculator hashCodeCalculator = new HashCodeCalculator();

    Method method = methodInvocation.getMethod();
    hashCodeCalculator.append(System.identityHashCode(method));

    Object[] methodArguments = methodInvocation.getArguments();
    if (methodArguments != null) {
      int methodArgumentCount = methodArguments.length;

      for (int i = 0; i < methodArgumentCount; i++) {
        Object methodArgument = methodArguments[i];
        int hash = 0;

        if (generateArgumentHashCode) {
          hash = ReflectionsUtility.reflectionHashCode(methodArgument);
        } else {
          hash = ObjectsUtility.nullSafeHashCode(methodArgument);
        }

        hashCodeCalculator.append(hash);
      }
    }

    long checkSum = hashCodeCalculator.getCheckSum();
    int hashCode = hashCodeCalculator.getHashCode();

    Serializable cacheKey = new HashCodeCacheKey(checkSum, hashCode);
    return cacheKey;
  }

  /**
   * Sets the flag that indicates if this generator should generate the hash
   * code of the arguments passed to the method to apply caching to. If
   * <code>false</code>, this generator uses the default hash code of the
   * arguments.
   * 
   * @param newGenerateArgumentHashCode
   *          the new value of the flag
   */
  public final void setGenerateArgumentHashCode(
      boolean newGenerateArgumentHashCode) {
    generateArgumentHashCode = newGenerateArgumentHashCode;
  }

}


import java.io.Serializable;

/**
 * <p>
 * Cache key which value is based on a pre-calculated hash code.
 * </p>
 * 
 * @author Elicer Zheng
 */
public final class HashCodeCacheKey implements Serializable {

  private static final long serialVersionUID = 3904677167731454262L;

  /**
   * Number that helps keep the uniqueness of this key.
   */
  private long checkSum;

  /**
   * Pre-calculated hash code.
   */
  private int hashCode;

  /**
   * Construct a <code>HashCodeCacheKey</code>.
   */
  public HashCodeCacheKey() {
    super();
  }

  /**
   * Construct a <code>HashCodeCacheKey</code>.
   * 
   * @param newCheckSum
   *          the number that helps keep the uniqueness of this key
   * @param newHashCode
   *          the pre-calculated hash code
   */
  public HashCodeCacheKey(long newCheckSum, int newHashCode) {
    this();
    setCheckSum(newCheckSum);
    setHashCode(newHashCode);
  }

  /**
   * @see Object#equals(Object)
   */
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof HashCodeCacheKey)) return false;

    HashCodeCacheKey other = (HashCodeCacheKey) obj;
    if (checkSum != other.checkSum) return false;
    if (hashCode != other.hashCode) return false;

    return true;
  }

  /**
   * @return the number that helps keep the uniqueness of this key
   */
  public long getCheckSum() {
    return checkSum;
  }

  /**
   * @return the pre-calculated hash code
   */
  public int getHashCode() {
    return hashCode;
  }

  /**
   * @see Object#hashCode()
   */
  public int hashCode() {
    return getHashCode();
  }

  /**
   * Sets the number that helps keep the uniqueness of this key.
   * 
   * @param newCheckSum
   *          the new number
   */
  public void setCheckSum(long newCheckSum) {
    checkSum = newCheckSum;
  }

  /**
   * Sets the pre-calculated hash code.
   * 
   * @param newHashCode
   *          the new hash code
   */
  public void setHashCode(int newHashCode) {
    hashCode = newHashCode;
  }

  /**
   * @see Object#toString()
   */
  public String toString() {
    return getHashCode() + "|" + getCheckSum();
  }
}


/**
 *
 *This class is a HashCode Calculator
 * 
 * @author Elicer Zheng
 */
public final class HashCodeCalculator {

  private static final int INITIAL_HASH = 17;

  private static final int MULTIPLIER = 37;

  private long checkSum;

  /**
   * Counts the number of times <code>{@link #append(int)}</code> is executed.
   * It is also used to build <code>{@link #checkSum}</code> and
   * <code>{@link #hashCode}</code>.
   */
  private int count;

  /**
   * Hash code to build;
   */
  private int hashCode;

  /**
   * Constructor.
   */
  public HashCodeCalculator() {
    super();
    hashCode = INITIAL_HASH;
  }

  /**
   * Recalculates <code>{@link #checkSum}</code> and
   * <code>{@link #hashCode}</code> using the specified value.
   *
   * @param value
   *          the specified value.
   */
  public void append(int value) {
    count++;
    int valueToAppend = count * value;

    hashCode = MULTIPLIER * hashCode + (valueToAppend ^ (valueToAppend >>> 16));
    checkSum += valueToAppend;
  }

  /**
   * @return the number that ensures that the combination hashCode/checSum is
   *         unique
   */
  public long getCheckSum() {
    return checkSum;
  }

  /**
   * @return the calculated hash code
   */
  public int getHashCode() {
    return hashCode;
  }
}



import java.util.HashSet;
import java.util.Set;

import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * <p>
 * Miscellaneous object utility methods.
 * </p>
 * 
 * @author Elicer Zheng
 */
public abstract class ObjectsUtility {

  private static final String ARRAY_ELEMENT_SEPARATOR = ", ";

  private static final String ARRAY_END = "}";

  private static final String ARRAY_START = "{";

  private static final String EMPTY_ARRAY = "{}";

  private static final int INITIAL_HASH = 7;

  private static final int MULTIPLIER = 31;

  private static final String NULL_ARRAY = "null";

  private static final Set primitivesAndWrappers;

  static {
    primitivesAndWrappers = new HashSet();
    primitivesAndWrappers.add(boolean.class);
    primitivesAndWrappers.add(Boolean.class);
    primitivesAndWrappers.add(byte.class);
    primitivesAndWrappers.add(Byte.class);
    primitivesAndWrappers.add(char.class);
    primitivesAndWrappers.add(Character.class);
    primitivesAndWrappers.add(double.class);
    primitivesAndWrappers.add(Double.class);
    primitivesAndWrappers.add(float.class);
    primitivesAndWrappers.add(Float.class);
    primitivesAndWrappers.add(int.class);
    primitivesAndWrappers.add(Integer.class);
    primitivesAndWrappers.add(long.class);
    primitivesAndWrappers.add(Long.class);
    primitivesAndWrappers.add(short.class);
    primitivesAndWrappers.add(Short.class);
  }

  /**
   * Returns the same value as <code>{@link Boolean#hashCode()}</code>.
   * 
   * @param bool
   *          the given <code>boolean</code>.
   * @return the hash code for the given <code>boolean</code>.
   * @see Boolean#hashCode()
   */
  public static int hashCode(boolean bool) {
    return bool ? 1231 : 1237;
  }

  /**
   * Returns the same value as <code>{@link Double#hashCode()}</code>.
   * 
   * @param dbl
   *          the given <code>double</code>.
   * @return the hash code for the given <code>double</code>.
   * @see Double#hashCode()
   */
  public static int hashCode(double dbl) {
    long bits = Double.doubleToLongBits(dbl);
    return hashCode(bits);
  }

  /**
   * Returns the same value as <code>{@link Float#hashCode()}</code>.
   * 
   * @param flt
   *          the given <code>float</code>.
   * @return the hash code for the given <code>float</code>.
   * @see Float#hashCode()
   */
  public static int hashCode(float flt) {
    return Float.floatToIntBits(flt);
  }

  /**
   * Returns the same value as <code>{@link Long#hashCode()}</code>.
   * 
   * @param lng
   *          the given <code>long</code>.
   * @return the hash code for the given <code>long</code>.
   * @see Long#hashCode()
   */
  public static int hashCode(long lng) {
    return (int) (lng ^ (lng >>> 32));
  }

  /**
   * <p>
   * Returns a <code>StringBuffer</code> containing:
   * <ol>
   * <li>the class name of the given object</li>
   * <li>the character '@'</li>
   * <li>the hex string for the object's identity hash code</li>
   * </ol>
   * </p>
   * <p>
   * This method will return an empty <code>StringBuffer</code> if the given
   * object is <code>null</code>.
   * </p>
   * 
   * @param obj
   *          the given object.
   * @return a <code>StringBuffer</code> containing identity information of
   *         the given object.
   */
  public static StringBuffer identityToString(Object obj) {
    StringBuffer buffer = new StringBuffer();
    if (obj != null) {
      buffer.append(obj.getClass().getName());
      buffer.append("@");
      buffer.append(ObjectUtils.getIdentityHexString(obj));
    }
    return buffer;
  }

  /**
   * Returns <code>true</code> if the given object is an array of primitives.
   * 
   * @param array
   *          the given object to check.
   * @return <code>true</code> if the given object is an array of primitives.
   */
  public static boolean isArrayOfPrimitives(Object array) {
    boolean primitiveArray = false;

    if (array != null) {
      Class clazz = array.getClass();

      primitiveArray = clazz.isArray()
          && clazz.getComponentType().isPrimitive();
    }

    return primitiveArray;
  }

  /**
   * Returns <code>true</code> if the given class is any of the following:
   * <ul>
   * <li><code>boolean</code></li>
   * <li>Boolean</li>
   * <li><code>byte</code></li>
   * <li>Byte</li>
   * <li><code>char</code></li>
   * <li>Character</li>
   * <li><code>double</code></li>
   * <li>Double</li>
   * <li><code>float</code></li>
   * <li>Float</li>
   * <li><code>int</code></li>
   * <li>Integer</li>
   * <li><code>long</code></li>
   * <li>Long</li>
   * <li><code>short</code></li>
   * <li>Short</li>
   * </ul>
   * 
   * @param clazz
   *          the given class.
   * @return <code>true</code> if the given class represents a primitive or a
   *         wrapper, <code>false</code> otherwise.
   */
  public static boolean isPrimitiveOrWrapper(Class clazz) {
    return primitivesAndWrappers.contains(clazz);
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>boolean</code> arrays <code>a</code> and <code>b</code>
   * such that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(boolean)
   */
  public static int nullSafeHashCode(boolean[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>byte</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(byte[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>char</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(char[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>double</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(double)
   */
  public static int nullSafeHashCode(double[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>float</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(float)
   */
  public static int nullSafeHashCode(float[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>int</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(int[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>long</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(long)
   */
  public static int nullSafeHashCode(long[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns the value of <code>{@link Object#hashCode()}</code>. If the
   * object is an array, this method will delegate to any of the
   * <code>nullSafeHashCode</code> methods for arrays in this class.
   * </p>
   * 
   * <p>
   * If the object is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param obj
   *          the object whose hash value to compute.
   * @return the hash code of the given object.
   * @see #nullSafeHashCode(boolean[])
   * @see #nullSafeHashCode(byte[])
   * @see #nullSafeHashCode(char[])
   * @see #nullSafeHashCode(double[])
   * @see #nullSafeHashCode(float[])
   * @see #nullSafeHashCode(int[])
   * @see #nullSafeHashCode(long[])
   * @see #nullSafeHashCode(Object[])
   * @see #nullSafeHashCode(short[])
   */
  public static int nullSafeHashCode(Object obj) {
    if (obj == null)
      return 0;

    if (obj instanceof boolean[]) {
      return nullSafeHashCode((boolean[]) obj);
    }
    if (obj instanceof byte[]) {
      return nullSafeHashCode((byte[]) obj);
    }
    if (obj instanceof char[]) {
      return nullSafeHashCode((char[]) obj);
    }
    if (obj instanceof double[]) {
      return nullSafeHashCode((double[]) obj);
    }
    if (obj instanceof float[]) {
      return nullSafeHashCode((float[]) obj);
    }
    if (obj instanceof int[]) {
      return nullSafeHashCode((int[]) obj);
    }
    if (obj instanceof long[]) {
      return nullSafeHashCode((long[]) obj);
    }
    if (obj instanceof short[]) {
      return nullSafeHashCode((short[]) obj);
    }
    if (obj instanceof Object[]) {
      return nullSafeHashCode((Object[]) obj);
    }

    return obj.hashCode();
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two arrays <code>a</code> and <code>b</code> such that
   * <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * <p>
   * The value returned by this method is equal to the value that would be
   * returned by <code>Arrays.asList(a).hashCode()</code>, unless
   * <code>array</code> is <code>null</code>, in which case <code>0</code>
   * is returned.
   * </p>
   * 
   * @param array
   *          the array whose content-based hash code to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(Object[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + nullSafeHashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>short</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * 
   * @param array
   *          the array whose hash value to compute
   * @return a content-based hash code for <code>array</code>
   */
  public static int nullSafeHashCode(short[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(boolean[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(byte[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(char[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append("'" + array[i] + "'");
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(double[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(float[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(int[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(long[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(Object[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(StringUtils.quoteIfString(array[i]));
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(short[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(String[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(StringUtils.quote(array[i]));
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }
}



import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import org.springframework.util.ReflectionUtils;



/**
 * <p>
 * Reflection-related utility methods,used to build the hash code for the input parameter.
 * </p>
 *
 * 
 * @author Elicer Zheng
 */
public abstract class ReflectionsUtility {

  private static final int INITIAL_HASH = 7;

  private static final int MULTIPLIER = 31;

  /**
   * <p>
   * This method uses reflection to build a valid hash code.
   * </p>
   *
   * <p>
   * It uses <code>AccessibleObject.setAccessible</code> to gain access to
   * private fields. This means that it will throw a security exception if run
   * under a security manager, if the permissions are not set up correctly. It
   * is also not as efficient as testing explicitly.
   * </p>
   *
   * <p>
   * Transient members will not be used, as they are likely derived fields,
   * and not part of the value of the <code>Object</code>.
   * </p>
   *
   * <p>
   * Static fields will not be tested. Superclass fields will be included.
   * </p>
   *
   * @param obj
   *          the object to create a <code>hashCode</code> for
   * @return the generated hash code, or zero if the given object is
   *         <code>null</code>
   */
  public static int reflectionHashCode(Object obj) {
    if (obj == null)
      return 0;

    Class targetClass = obj.getClass();
    if (ObjectsUtility.isArrayOfPrimitives(obj)
        || ObjectsUtility.isPrimitiveOrWrapper(targetClass)) {
      return ObjectsUtility.nullSafeHashCode(obj);
    }

    if (targetClass.isArray()) {
      return reflectionHashCode((Object[]) obj);
    }

    if (obj instanceof Collection) {
      return reflectionHashCode((Collection) obj);
    }

    if (obj instanceof Map) {
      return reflectionHashCode((Map) obj);
    }

		// determine whether the object's class declares hashCode() or has a
		// superClass other than java.lang.Object that declares hashCode()
		Class clazz = (obj instanceof Class)? (Class) obj : obj.getClass();
		Method hashCodeMethod = ReflectionUtils.findMethod(clazz,
				"hashCode", new Class[0]);

		if (hashCodeMethod != null) {
			return obj.hashCode();
		}

		// could not find a hashCode other than the one declared by java.lang.Object
		int hash = INITIAL_HASH;

    try {
      while (targetClass != null) {
        Field[] fields = targetClass.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);

        for (int i = 0; i < fields.length; i++) {
          Field field = fields[i];
          int modifiers = field.getModifiers();

          if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
            hash = MULTIPLIER * hash + reflectionHashCode(field.get(obj));
          }
        }
        targetClass = targetClass.getSuperclass();
      }
    } catch (IllegalAccessException exception) {
      // ///CLOVER:OFF
      ReflectionUtils.handleReflectionException(exception);
      // ///CLOVER:ON
    }

    return hash;
  }

  private static int reflectionHashCode(Collection collection) {
    int hash = INITIAL_HASH;

    for (Iterator i = collection.iterator(); i.hasNext();) {
      hash = MULTIPLIER * hash + reflectionHashCode(i.next());
    }

    return hash;
  }

  private static int reflectionHashCode(Map map) {
    int hash = INITIAL_HASH;

    for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
      Map.Entry entry = (Map.Entry) i.next();
      hash = MULTIPLIER * hash + reflectionHashCode(entry);
    }

    return hash;
  }

  private static int reflectionHashCode(Map.Entry entry) {
    int hash = INITIAL_HASH;
    hash = MULTIPLIER * hash + reflectionHashCode(entry.getKey());
    hash = MULTIPLIER * hash + reflectionHashCode(entry.getValue());
    return hash;
  }

  private static int reflectionHashCode(Object[] array) {
    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + reflectionHashCode(array[i]);
    }

    return hash;
  }
}


0
0
分享到:
评论

相关推荐

    AOP Cache源代码

    在IT行业中,Spring AOP(面向切面编程)和Ehcache是两个非常重要的概念,它们经常被结合在一起用于实现高效的应用程序缓存系统。在这个"AOP Cache源代码"项目中,我们可以看到如何利用这两者来提升应用性能。下面将...

    spring aop 自定义缓存实现

    本实例将介绍如何利用Spring AOP来实现自定义缓存功能。 首先,理解Spring AOP的基本概念。AOP是一种编程范式,它允许我们在不修改代码的情况下,为程序添加额外的功能,如日志记录、事务管理、安全检查等。在...

    Unity结合三导实现依赖注入跟AOP

    2. Unity AOP:Unity提供了对AOP的支持,可以通过拦截器(Interceptor)实现。拦截器是实现AOP的核心,它在方法调用前后执行自定义逻辑。 3. 创建拦截器:通过继承`IInterceptor`接口或使用`Unity.Interception`库...

    aop思想的java实现

    **AOP思想与Java实现** 面向切面编程(Aspect-Oriented Programming,简称AOP)是一种编程范式,它旨在解决传统面向对象编程中的横切关注点,如日志、事务管理、性能监控等,这些关注点往往分散在程序的各个角落,...

    使用Spring的注解方式实现AOP的细节

    本篇文章将深入探讨如何通过Spring的注解方式实现AOP的细节。 首先,我们需要了解AOP的基本概念。AOP的核心是切面(Aspect),它封装了跨越多个对象的行为或责任。切点(Pointcut)定义了哪些方法会被通知(Advice...

    基于注解实现SpringAop

    基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop

    SpringAop学习笔记以及实现Demo

    **Spring AOP 学习笔记及实现Demo** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。AOP的主要目的...

    Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现.doc

    Spring AOP 实现原理详解之 AOP 切面的实现 Spring AOP 是基于 IOC 的 Bean 加载来实现的,本文主要介绍 Spring AOP 原理解析的切面实现过程。AOP 切面的实现是将切面类的所有切面方法根据使用的注解生成对应 ...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    动态代理是实现AOP的一种常用技术,它允许在运行时创建代理对象,拦截对真实对象的调用,并在调用前后添加额外的行为。 在Java开发中,反射机制是实现动态代理的关键技术之一。反射提供了在运行时访问和操作类的...

    spring aop 拦截器简单实现

    本例提供了一个简单的AOP拦截器实现,我们可以从这个基础出发,深入理解和探讨AOP的核心概念、工作原理以及其在实际开发中的应用。 首先,AOP的主要目标是解决程序中的横切关注点,如日志记录、事务管理、性能监控...

    Spring Aop的简单实现

    在本项目中,我们将探讨如何通过配置文件实现Spring AOP,包括前置通知、后置通知以及拦截器的运用。 首先,我们需要理解Spring AOP的核心概念。切面(Aspect)是关注点的模块化,这些关注点定义了跨越多个对象的...

    利用C#实现AOP常见的几种方法详解

    在C#中,实现AOP的方法多种多样,以下将详细介绍几种常见的实现方式。 1. **静态织入**: 静态织入是在编译时完成的,它通过编译器或者编译插件(如PostSharp)在目标类的代码中插入拦截逻辑。这种方式的优点是...

    .net平台AOP的实现

    在.NET平台上实现AOP,我们可以借助于不同的库和技术,如PostSharp、Unity、Autofac等。下面我们将深入探讨.NET平台AOP的实现方法和应用。 首先,我们需要理解AOP的基本概念。AOP的核心是切面(Aspect),它封装了...

    Spring AOP 常用的四种实现方式的代码

    本篇文章将详细讲解Spring AOP的四种常见实现方式,以帮助开发者更好地理解和运用这一功能。 一、基于接口的代理(Interface-Based Proxy) 这是Spring AOP的默认实现方式,适用于目标对象实现了接口的情况。Spring...

    实战项目-AOP-cache

    在本实战项目"AOP-cache"中,我们将深入探讨如何利用面向切面编程(AOP)和Ehcache技术来实现高效的数据缓存处理。面向切面编程是一种编程范式,它允许开发者将关注点分离,比如日志、事务管理、性能监控等,从主...

    springAOP配置动态代理实现

    动态代理则是Spring AOP实现的核心技术之一,它允许我们在运行时创建具有额外行为的对象。下面将详细阐述Spring AOP的配置以及动态代理的实现。 一、Spring AOP基础知识 1. **什么是AOP**:AOP是一种编程范式,...

    springAop+自定义注解实现权限管理

    一个简单的采用自定义注解结合SpringAop实现方法执行的权限管理,这个demo中并没有涉及到与数据库的交互和业务代码,用户权限在登陆时采用简单的手动初始化。该demo用的jdk1.7编译,Spring4.0版本,只想通过这个demo...

    Spring AOP的简单实现

    在这个场景中,我们将使用Spring AOP来实现一个日志记录的功能,以追踪系统中各个方法的调用情况,包括访问时间以及传递的参数。下面将详细阐述如何实现这一目标。 首先,我们需要了解AOP的基本概念。AOP的核心是切...

    spring aop demo 两种实现方式

    本示例提供了一种通过注解和配置文件两种方式实现Spring AOP的方法。 首先,我们来详细讲解通过注解实现Spring AOP。在Spring中,我们可以使用`@Aspect`注解来定义一个切面,这个切面包含了多个通知(advice),即...

    基于AOP策略模式的实现机制

    本文首先将传统基于OOP策略模式的局限性进行分析说明,提出基本的策略模式以及“链式”策略模式基于AOP的具体实现,解决传统策略模式可能出现的代码分散、代码混乱问题;接着进行复杂度方面的实验对比分析;最后分析...

Global site tag (gtag.js) - Google Analytics