@Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof SimpleSession) {
            SimpleSession other = (SimpleSession) obj;
            Serializable thisId = getId();
            Serializable otherId = other.getId();
            if (thisId != null && otherId != null) {
                return thisId.equals(otherId);
            } else {
                //fall back to an attribute based comparison:
                return onEquals(other);
            }
        }
        return false;
    }
Returns {@code true} if the specified argument is an {@code instanceof} {@code SimpleSession} and both
{@link #getId() id}s are equal.  If the argument is a {@code SimpleSession} and either 'this' or the argument
does not yet have an ID assigned, the value of {@link #onEquals(SimpleSession) onEquals} is returned, which
does a necessary attribute-based comparison when IDs are not available.
<p/>
Do your best to ensure {@code SimpleSession} instances receive an ID very early in their lifecycle to
avoid the more expensive attributes-based comparison.

@param obj the object to compare with this one for equality.
@return {@code true} if this object is equivalent to the specified argument, {@code false} otherwise.
core/src/main/java/org/apache/shiro/session/mgt/SimpleSession.java