吃透Shiro源码2----PrincipalCollection、ThreadState

技术手法

(1)工厂返回单例与多例

创建内部实例对象,如果是单例对象,那么就把创建出来的对象塞到singletonInstance中并返回这个单例对象。如果不是,那么就创建一个新对象给调用者

public abstract class AbstractFactory<T> 
           implements Factory<T> ...
   
    @Override
    public T getInstance() {
        T instance;
        if (isSingleton()) {
            //如果是单例的,创建单例对象
            if (this.singletonInstance == null) {
                this.singletonInstance = createInstance();
            }
            instance = this.singletonInstance;

        } else {
            //如果不是单例的,创建一个实例对象
            instance = createInstance();
        }

        //我自己写的时候,没有想到这一步
        //大佬的心思真细腻,再来一次健壮性判断
        //异常用了IllegalStateException
        if (instance == null) {
            String msg = "工厂返回了一个空的对象";
            throw new IllegalStateException(msg);
        }

        return instance;
    }

    protected abstract T createInstance();
}

(2)备忘录:如何保住旧对象状态?

如何保住对象的状态呢?备忘录设计模式的精髓就在于保住以前对象的状态。这里大佬提供了较为完整的实现代码,学到了。

public interface ThreadState {

    /**
     * 保存当前线程数据
     */
    void bind();

    /**
     * 恢复数据
     */
    void restore();

    /**
     * 清空数据
     */
    void clear();
}
public class SubjectThreadState implements ThreadState ...
    /**
     * 保存以前的Subject与SecurityManager
     * 然后把这个类中的Subject与SecurityManager绑定到当前线程
     */
    @Override
    public void bind() {
        SecurityManager securityManager = this.securityManager;
        if (securityManager == null) {
            //防止为空,从当前线程中再拿一次
            securityManager = ThreadContext.getSecurityManager();
        }
        //绑定当前线程中的Subject与SecurityManager到originResources
        this.originResources = ThreadContext.getResources();
        //清空当先线程
        ThreadContext.remove();

        //重新绑定
        ThreadContext.bind(this.subject);
        if (securityManager != null) {
            ThreadContext.bind(securityManager);
        }
    }
    @Override
    public void restore() {
        //先清空
        ThreadContext.remove();

        if(!CollectionUtils.isEmpty(this.originResources)){
             //把之前保存的对象再重新设置到当前线程中
            ThreadContext.setResources(this.originResources);
        }

    }

(3)集合如何懒加载

某个对象内部有一个private Map<String, Set> realmPrincipals;属性。需要在第一次添加数据的时候创建Set集合。这里提供了一种懒加载机制,非常值得借鉴

/**
     * 创建 realmName - Set 这种对象关联关系并添加进内部Map中
     * 最后返回Set对象引用方便操作
     * 添加新凭证到Set中
     *
     * @param realmName realmName
     * @return realmName对应的Set对象引用
     */
    protected Set getPrincipalsLazy(String realmName) {

        Set principalsFromRealm = this.realmPrincipals.get(realmName);

        if (principalsFromRealm == null) {
            principalsFromRealm = new LinkedHashSet();
            this.realmPrincipals.put(realmName, principalsFromRealm);
        }
        //返回此Set集合引用给调用者
        return principalsFromRealm;
    }

重点研究类

public interface ThreadState {


    /**
     * 绑定任何状态,应该可以在一个线程的执行
     */
    void bind();

    /**
     * 恢复一个线程绑定之前其状态
     */
    void restore();

    /**
     * Completely clears/removes the {@code ThreadContext} state
     */
    void clear();
}
package com.wise.security.subject.support;

import com.wise.security.mgt.SecurityManager;
import com.wise.security.subject.Subject;
import com.wise.security.util.CollectionUtils;
import com.wise.security.util.ThreadContext;
import com.wise.security.util.ThreadState;

import java.util.Map;

/**
 *
 * 当前类的作用:
 * 首先通过构造函数创建此对象,构造函数封装一个Subject对象
 * 通过Subject对象又拿到SecurityManager对象
 * 通过bind()将这组对象存放到此此对象的originResources中
 * 通过restore()清除ThreadContext中的resources,然后把originResources重新塞到ThreadContext中
 * 通过clear()方法删除ThreadContext中的Subject与SecurityManager对象
 *
 */
public class SubjectThreadState implements ThreadState {

    private final Subject subject;

    private SecurityManager securityManager;

    private Map<Object, Object> originResources;


    public SubjectThreadState(Subject subject) {


        if (subject == null) {
            throw new IllegalArgumentException("Subject参数不能为空");
        }

        this.subject = subject;

        SecurityManager securityManager = null;

        //todo:从Subject中生产SecurityManager
//        if ( subject instanceof DelegatingSubject) {
//            securityManager = ((DelegatingSubject)subject).getSecurityManager();
//        }

        if (securityManager == null) {
            securityManager = ThreadContext.getSecurityManager();
        }

        this.securityManager = securityManager;
    }

    /**
     * 保存以前的Subject与SecurityManager
     * 然后把这个类中的Subject与SecurityManager绑定到当前线程
     */
    @Override
    public void bind() {
        SecurityManager securityManager = this.securityManager;

        if (securityManager == null) {
            //防止为空,从当前线程中再拿一次
            securityManager = ThreadContext.getSecurityManager();
        }
        //绑定当前线程中的Subject与SecurityManager到originResources
        this.originResources = ThreadContext.getResources();
        //清空当先线程
        ThreadContext.remove();

        //重新绑定
        ThreadContext.bind(this.subject);
        if (securityManager != null) {
            ThreadContext.bind(securityManager);
        }
    }


    /**
     * 之前的Subject与SecurityManager被存放到了originResources里面
     * 如果没有originResources,说明之前就没调用bind()方法绑定
     * @see #bind()
     */
    @Override
    public void restore() {
        //先清空
        ThreadContext.remove();

        if(!CollectionUtils.isEmpty(this.originResources)){
            ThreadContext.setResources(this.originResources);
        }

    }

    /**
     * 清除当前线程中存放的SecurityManager与Subject
     */
    @Override
    public void clear() {
        ThreadContext.remove();
    }

    protected Subject getSubject() {
        return this.subject;
    }
}

package com.wise.security.subject;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Set;

public interface PrincipalCollection extends Iterable, Serializable {

    /**
     * 返回主凭证
     * <p>
     * 返回主应用程序主要用来唯一地标识拥有账户或Subject
     *
     * @return
     */
    Object getPrimaryPrincipal();

    /**
     * 返回指定类型的第一个凭证,返回指定类型
     *
     * @param type 指定类型
     * @param <T>  泛型
     * @return 指定类型的凭证
     */
    <T> T oneByType(Class<T> type);

    /**
     * 返回指定类型的所有凭证
     *
     * @param type 指定类型
     * @param <T>  泛型
     * @return 指定类型的所有凭证
     */
    <T> Collection<T> byType(Class<T> type);


    /**
     * 所有凭证作为List
     *
     * @return 所有凭证
     */
    List asList();

    /**
     * 所有凭证作为Set
     *
     * @return 所有凭证
     */
    Set asSet();


    /**
     * 从指定Realm中返回主凭证
     *
     * @param realName realm名称
     * @return 主凭证
     */
    Collection fromRealm(String realName);

    /**
     * 返回提供了凭证的Realm对象们的Names
     *
     * @return 提供了凭证的Realm对象们的Names
     */
    Set<String> getRealmNames();


    /**
     * 是否有凭证
     *
     * @return 是否有凭证
     */
    boolean isEmpty();

}

package com.wise.security.subject;

import java.util.Collection;

/**
 * 可变的凭证集合
 */
public interface MutablePrincipalCollection extends PrincipalCollection {


    /**
     * 添加一个凭证
     *
     * @param principal 凭证对象
     * @param realmName realmName
     */
    void add(Object principal, String realmName);


    /**
     * 添加所有的凭证
     *
     * @param principals
     */
    void addAll(PrincipalCollection principals);

    /**
     * 添加所有的凭证集合
     *
     * @param principals 凭证集合
     * @param realmName  这些凭证的realm来源
     */
    void addAll(Collection principals, String realmName);

    /**
     * 删除所有凭证
     */
    void clear();
}

package com.wise.security.subject;

import com.wise.security.util.CollectionUtils;

import java.util.*;

@SuppressWarnings({"unchecked"})
public class SimplePrincipalCollection implements MutablePrincipalCollection {

    /**
     * 字符串(realm)对应一批Set (Principal)
     */
    private Map<String, Set> realmPrincipals;

    private String cachedToString;

    public SimplePrincipalCollection() {

        //fromRealm()方法可能报空指针,因此用这个
        realmPrincipals = new LinkedHashMap<>();
    }

    public SimplePrincipalCollection(Object principal, String realmName) {
        if (principal == null) {
            throw new IllegalArgumentException("principal is null");
        }

        if (realmName == null) {
            throw new IllegalArgumentException("realmName is null");
        }

        add(principal, realmName);
    }

    public SimplePrincipalCollection(Collection principals, String realmName) {
        addAll(principals, realmName);
    }

    public SimplePrincipalCollection(PrincipalCollection principals) {
        addAll(principals);
    }


    @Override
    public Object getPrimaryPrincipal() {
        if (isEmpty()) {
            return null;
        }

        return iterator().next();
    }

    @Override
    public <T> T oneByType(Class<T> type) {
        if (type == null) {
            return null;
        }
        //获取所有凭证
        List principals = asList();
        for (Object principal : principals) {
            if (type.isAssignableFrom(principal.getClass())) {
                return (T) principal;
            }
        }
        return null;
    }

    @Override
    public <T> Collection<T> byType(Class<T> type) {
        if (type == null) {
            return null;
        }
        //获取所有凭证
        List principals = asList();

        LinkedHashSet result = new LinkedHashSet();
        for (Object principal : principals) {
            if (type.isAssignableFrom(principal.getClass())) {
                result.add(principal);
            }
        }
        return result;
    }

    @Override
    public List asList() {
        Set allPrincipals = asSet();
        if (CollectionUtils.isEmpty(allPrincipals)) {
            return Collections.EMPTY_LIST;
        }

        return Collections.unmodifiableList(new ArrayList(allPrincipals));

    }

    @Override
    public Set asSet() {

        if (this.realmPrincipals == null || this.realmPrincipals.isEmpty()) {
            return Collections.EMPTY_SET;
        }

        //获取Map中所有的凭证Set集合
        Collection<Set> allPrincipalSet = this.realmPrincipals.values();

        Set result = new LinkedHashSet();
        for (Set principals : allPrincipalSet) {
            result.addAll(principals);
        }

        if (result.isEmpty()) {
            return Collections.EMPTY_SET;
        }
        //返回不可修改的视图
        return Collections.unmodifiableSet(result);
    }

    @Override
    public Collection fromRealm(String realName) {

        if (CollectionUtils.isEmpty(this.realmPrincipals)) {
            return Collections.EMPTY_SET;
        }

        Set principals = this.realmPrincipals.get(realName);
        //如果是空,返回空集合。
        if (CollectionUtils.isEmpty(principals)) {
            principals = Collections.EMPTY_SET;
        }
        //返回一个不可修改的凭证视图
        return Collections.unmodifiableSet(principals);
    }

    @Override
    public Set<String> getRealmNames() {

        if (CollectionUtils.isEmpty(this.realmPrincipals)) {
            return Collections.EMPTY_SET;
        }

        return Collections.unmodifiableSet(this.realmPrincipals.keySet());
    }

    @Override
    public boolean isEmpty() {
        return this.realmPrincipals == null || this.realmPrincipals.isEmpty();
    }

    @Override
    public Iterator iterator() {
        return asSet().iterator();
    }

    @Override
    public void add(Object principal, String realmName) {
        if (principal == null) {
            throw new IllegalArgumentException("principal is null");
        }

        if (realmName == null) {
            throw new IllegalArgumentException("realmName is null");
        }

        //???
        this.cachedToString = null;

        //内部的realmPrincipals Map 可能没有初始化.
        Set principals = getPrincipalsLazy(realmName);
        principals.add(principal);
    }

    @Override
    public void addAll(PrincipalCollection principals) {
        //获取所有的realmNames
        Set<String> realmNames = principals.getRealmNames();

        for (String realmName : realmNames) {
            //找到此realm对应的Set凭证
            Collection set = fromRealm(realmName);
            addAll(set, realmName);
        }
    }

    @Override
    public void addAll(Collection principals, String realmName) {

        if (realmName == null) {
            throw new IllegalArgumentException("realmName is null");
        }

        if (principals == null) {
            throw new IllegalArgumentException("principals is null");
        }

        if (principals.isEmpty()) {
            throw new IllegalArgumentException("principals is empty collection");
        }

        //???
        this.cachedToString = null;

        Set principalSet = getPrincipalsLazy(realmName);
        principalSet.addAll(principals);
    }

    @Override
    public void clear() {
        this.cachedToString = null;
        if (!CollectionUtils.isEmpty(this.realmPrincipals)) {
            //realmPrincipals是一个map集合,调用clear方法清空数据
            this.realmPrincipals.clear();
            this.realmPrincipals = null;
        }
    }

    /**
     * 创建 realmName - Set 这种对象关联关系并添加进内部Map中
     * 最后返回Set对象引用方便操作
     * 添加新凭证到Set中
     *
     * @param realmName realmName
     * @return realmName对应的Set对象引用
     */
    protected Set getPrincipalsLazy(String realmName) {

        Set principalsFromRealm = this.realmPrincipals.get(realmName);

        if (principalsFromRealm == null) {
            principalsFromRealm = new LinkedHashSet();
            this.realmPrincipals.put(realmName, principalsFromRealm);
        }
        //返回此Set集合引用给调用者
        return principalsFromRealm;
    }
}

posted @ 2022-07-17 12:14  小大宇  阅读(161)  评论(0编辑  收藏  举报