Coin163

首页 > Shiro源码分析-初始化-SecurityManager

Shiro源码分析-初始化-SecurityManager

相关标签: shiro

2020腾讯云双十一活动,全年最低!!!(领取3500元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1074

【阿里云】双十一活动,全年抄底价,限时3天!(老用户也有),
入口地址https://www.aliyun.com/1111/home

相关推荐:linux调度器源码分析 - 初始化(二)

转载: http://blog.chinaunix.net/uid/26772321.html 引言   上期文章linux调度器源码分析 - 概述(一)已经把调度器相关的数据结构介绍了一遍,本篇着重通过代码说明调度器在系统启动初始化阶段是如何初始化和工作的。通过上期文章我们知道,在多核CPU和SMP

源码分析的第一篇以SecurityManager的初始化为题。 
根据ini配置文件初始化shiro的代码主要为两段: 

//解析ini文件为Ini对象
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
        "classpath:shiro-config.ini");
//根据Ini对象初始化SecurityManager对象
SecurityManager securityManager = factory.getInstance();

ini文件格式说明请参考: 
http://zh.wikipedia.org/wiki/INI%E6%AA%94%E6%A1%88  
java解析ini的方式也比较多,有兴趣可以参考: 
http://my.oschina.net/tinyframework/blog/214309  
一、Shiro解析ini的步骤如下: 
1、org.apache.shiro.config.IniSecurityManagerFactory类构造方法:  
public IniSecurityManagerFactory(String iniResourcePath) {
        this(Ini.fromResourcePath(iniResourcePath));
    }
将ini文件解析交给Ini的静态方法fromResourcePath完成。并把解析后的Ini对象设置由自身持有 
public IniSecurityManagerFactory(Ini config) {
        setIni(config);
    }
2、org.apache.shiro.config.Ini类解析逻辑:  
public static Ini fromResourcePath(String resourcePath) throws ConfigurationException {
    if (!StringUtils.hasLength(resourcePath)) {
      throw new IllegalArgumentException("Resource Path argument cannot be null or empty.");
    }
    //此处新建Ini对象
    Ini ini = new Ini();
    ini.loadFromPath(resourcePath);
    return ini;
  }

  //根据资源路径获取输入流,交给load方法进行处理
  public void loadFromPath(String resourcePath) throws ConfigurationException {
    InputStream is;
    try {
      is = ResourceUtils.getInputStreamForPath(resourcePath);
    } catch (IOException e) {
      throw new ConfigurationException(e);
    }
    load(is);
  }
ResourceUtils.getInputStreamForPath(resourcePath);这里支持三种获取资源的方式:
classpath shiro-config.ini 从类路径中查找ini配置 url http://....../shiro-config.ini 从指定的url获取ini配置 file D:\shiro-config.ini 从指定的文件路径获取ini配置 3、对获取的资源输入流最终交给文本扫描器Scaner,执行过程代码片段:  
public void load(Scanner scanner) {

    String sectionName = DEFAULT_SECTION_NAME;
    StringBuilder sectionContent = new StringBuilder();

    while (scanner.hasNextLine()) {

      String rawLine = scanner.nextLine();
      String line = StringUtils.clean(rawLine);
      //此处跳过ini文件格式的注释及空值
      if (line == null || line.startsWith(COMMENT_POUND) || line.startsWith(COMMENT_SEMICOLON)) {
        //skip empty lines and comments:
        continue;
      }
      //此处主要获取section部分,根据[]规则
      String newSectionName = getSectionName(line);
      if (newSectionName != null) {
        //此处代码主要用于构造Section对象,并放进sections集合中
        addSection(sectionName, sectionContent);

        //reset the buffer for the new section:
        sectionContent = new StringBuilder();

        sectionName = newSectionName;

        if (log.isDebugEnabled()) {
          log.debug("Parsing " + SECTION_PREFIX + sectionName + SECTION_SUFFIX);
        }
      } else {
        //normal line - add it to the existing content buffer:
        sectionContent.append(rawLine).append("\n");
      }
    }

    //finish any remaining buffered content:
    addSection(sectionName, sectionContent);
  }
上段代码主要是组装ini文件中的section。细心的同学会发现Section、Ini都是实现了Map接口。Section持有的LinkedHashMap容器实际上是当前section中的所有键值对,而Ini持有的LinkedHashMap容器实际上是所有section名称与section对象的键值对。 
至此,ini文件的解析已经完成,其ini中的内容已全部以map的形式存放在Ini实例中。 
至于保存的结果是什么样的呢?以下面的一段配置为例: 
[main]
#authenticator
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
authenticationStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
authenticator.authenticationStrategy=$authenticationStrategy
securityManager.authenticator=$authenticator
Ini的sections属性[key=main,value=Section对象],此Section对象内部的props保存了所有main部分key-value映射。目前都是String类型,实例化在下一步完成的。 
二、由Ini实例构造SecurityManager对象 
SecurityManager securityManager = factory.getInstance();
IniSecurityManagerFactory的继承关系为: 
IniSecurityManagerFactory->IniFactorySupport->AbstractFactory->Factory 
这里的getInstance方法由最上级的抽象类:org.apache.shiro.util.AbstractFactory提供,源码如下: 
//该方法只是用于判断是否单例(默认为单例)
  public T getInstance() {
    T instance;
    if (isSingleton()) {
      if (this.singletonInstance == null) {
        this.singletonInstance = createInstance();
      }
      instance = this.singletonInstance;
    } else {
      instance = createInstance();
    }
    if (instance == null) {
      String msg = "Factory 'createInstance' implementation returned a null object.";
      throw new IllegalStateException(msg);
    }
    return instance;
  }
  //由子类IniFactorySupport创建实例
  protected abstract T createInstance();
IniFactorySupport的createInstance实现如下(省略了无关紧要的日志、判断代码): 
public T createInstance() {
    //此处获取解析ini文件产生的Ini对象
    Ini ini = resolveIni();
    T instance;
    if (CollectionUtils.isEmpty(ini)) {
      //如果ini为空,则创建默认实例
      instance = createDefaultInstance();
    } else {
      //根据ini对象创建实例
      instance = createInstance(ini);
    }
    return instance;
  }
  protected abstract T createInstance(Ini ini);

  protected abstract T createDefaultInstance();
上面两个抽象方法,则交给实现类IniSecurityManagerFactory完成了。 
先阅读createDefaultInstance方法源码 
protected SecurityManager createDefaultInstance() {
        return new DefaultSecurityManager();
    }

终于在这个不起眼的地方,看到了初始化最核心的接口SecurityManager了。稍微暂停一下,发个SecurityManager的类图: 


相关推荐:Nouveau源码分析(七): 各SUBDEV/ENGINE初始化 (1)

Nouveau源码分析(七) 虽然各个SUBDEV/EGINE的初始化实际还是在nouveau_drm_load里,但还是换个标题吧. 等把各个SUBDEV/ENGINE之类的说完再换回去. 上次已经按着初始化的顺序介绍了一下各个subdev的用途,现在按顺序,首先来看VBIOS的ctor函数: [cpp]  view plain

由此图可以看出来,SecurityManager继承了三个接口(认证、授权、session管理),认证授权是安全框架最核心的功能,而shiro提供了自身的session管理机制(这也是shiro的一大亮点)。图中除了DefaultSecurityManager,其它所有类都是抽象类,由此可看出,DefaultSecurityManager是作为默认的安全管理器。 
再来看new DefaultSecurityManager();做的事情 

public DefaultSecurityManager() {
        super();
        this.subjectFactory = new DefaultSubjectFactory();
        this.subjectDAO = new DefaultSubjectDAO();
    }
这里暂时不深究每个构造器所做的具体事情。有兴趣的同学,可一直观察DefaultSecurityManager的所有父类构造器的处理逻辑。 
类名称 构造方法创建的默认对象 DefaultSecurityManager DefaultSubjectFactory,DefaultSubjectDAO SessionsSecurityManager DefaultSessionManager AuthorizingSecurityManager ModularRealmAuthorizer AuthenticatingSecurityManager ModularRealmAuthenticator RealmSecurityManager 无 CachingSecurityManager 无 在上面的表格中已经清晰的描述了各个类所设置的默认对象,至于用途后面再讲解。

原文

源码分析的第一篇以SecurityManager的初始化为题。  根据ini配置文件初始化shiro的代码主要为两段:  //解析ini文件为Ini对象Factory<SecurityManager> factory = new IniSecurityManagerFacto

------分隔线----------------------------