shiro realm 注解失败问题解决过程

做为一名在.net混了八九年的老兵油子,转战java时间并不长,刚开始做项目完全是凭借对C#的认识来做,虽然遇到一些问题,但实际结果显示C#在语言上和java还是有很大相似度,而且微软的MVC与Spring MVC也是那么的神似,这也是为什么我在做项目前并未对java进行系统的学习也能做项目的原因。最近稍微有些空闲时间,所以决定从基础开始系统的学习java,这里并没有太多高深技术可分享的,本篇给大家分享我解决问题的一个经验:触类旁通或者叫举一反三,对了还有一点,对于存在可优化点的部分要不轻言放弃。
 
  困扰以久的问题:

项目中应用shiro进行登录权限认证,在Realm实现类中注解服务不成功,得到的实例是null。网上遇到同类问题的还不少,可能每个人的项目情况不同,我并未从中得到正确的解决方案。

@Autowired
 private ISecurityService securityService;

有两种方法可以解决:

  • 通过ApplicationContext动态获取实例
private ISecurityService securityService;

    private void initSecurityService() {
        if (null == this.securityService) {
            ApplicationContext appCtx = ApplicationContextUtils.getApplicationContext();
            this.securityService = appCtx.getBean(ISecurityService.class);

        }
    }
  • 通过静态属性注解,这个方法可以用来调试spring是否有对这个属性进行过注解。为什么下面代码中的变量是静态的呢?当不是静态类型时,调试过程中的确有进行过注解,而且是注解成功的,但当程序执行后,shiro获取到的实例为null,并不是之前注解过的实例,将这个变量修改为静态的之后运行成功。
private static ISecurityService securityService;
    @Autowired
    public void setSecurityService(ISecurityService securityService) {
        securityService = securityService;
    }

以上两种写法都比较恶心,但当时对于spring类扫描的不了解,也只能做罢。在知识不够的情况下,如果一味的去钻也许不一定会有完美的结果,所以我选择暂时放弃。

项目中遇到过使用数据库事务不生效的情况,当时同事的解释是spring扫描的问题,在加载事务配置时,不能扫描Controller。后来有时间研究了下,由于我们使用了spring mvc,而且在web.xml中采用了非常经典的Application Context +DispatcherServlet Context结构。而有意思的是我们并没有给Application Context配置有关资源扫描以及Bean加载的信息,只有一个shiro配置文件的加载,结果就是项目所有的bean加载都集中在DispatherServlet这个MVC的配置文件中。

也有说如果只存在一个Servlet,那么可以选择只使用一个Context,这样也可以避免误使用双亲上下文所带来的问题,这个做法我还没有尝试,有时间研究下。

Application Context是什么?
  它是应用程度级别的一个上下文,这个上下文其中一个重要功能就是负责提供对访问数据库事务,数据层以及其它一些你想通过应用程序访问的需求(这里也许描述的不够准确,有兴趣的可上官方网站上去看文档)。比如上面的方法一,获取bean就是通过这个上下文对象动态获取得到。

DispatcherServlet Context是什么?
  一个应用程序可以定义多个Servlet,每个Servlet都有一个属于自己的上下文,我们项目中只有一个Servlet。

Application Context与DispatcherServlet Context的关系?
  DispatcherServlet Context的父级是Application Context,会继承所有Application Context所定义的内容。这里推荐两个贴子,说的挺清楚的。

  1. http://stackoverflow.com/questions/3652090/difference-between-applicationcontext-xml-and-spring-servlet-xml-in-spring-frame
  2. http://stackoverflow.com/questions/18578143/about-multiple-containers-in-spring-framework/18580299#18580299

为什么在加载数据库事务配置前,不能扫描Controller?这个我目前并不知道明细的原因,只大概知道是Spring设计规则问题,DispatherServlet中如果在数据库事务配置加载前扫描了包含Controller在类的命名空间,结果就是事务并不具备事务能力。所以我们在DispatherServlet配置文件中会出现两段扫描代码:

  • 先只扫描Controller
<context:component-scan base-package="cn.wanmei.party" use-default-filters="false">
        <context:include-filter expression="org.springframework.web.bind.annotation.Controller" type="annotation"/>
    </context:component-scan>
  • 。。。。。扫描加载其它配置
  • 加载数据库配置,由于事务的存在,这里在扫描时需要去掉对于Service的扫描,避免二次重复扫描产生不可预期的结果。
<context:component-scan base-package="cn.wanmei.party">
        <context:exclude-filter expression="org.springframework.web.bind.annotation.RestController" type="annotation"/>
    </context:component-scan>
    <import resource="mybatis.xml"/>

上面这种将几乎所有配置全部写在DispatherServlet配置文件中的做法有缺点:

  • 架空了原本为Application Context配置的root-context配置文件(只有一个shiro配置文件,不包含任何bean加载相关的内容)
  • 将原本属于Application Context做的事情转交给DispatherServlet,会造成扫描问题
  • 配置会显得复杂,我个人的意见是DispatherServlet尽量只配置与Servlet自身相关的,而像数据库配置最好放在root-context这个Application级别的配置中

以上大部分都是在描述事务不生效的问题,那与我文前提到的Realm实现类中通过Autowired注解服务失败有什么关联呢?之前提到了Application Context主要功能之一就是提供应用程序对于事务,数据层以及其它类实例的访问,那么在Realm实现类中提供类的注解实例当然是在职责范围内,为此我们需要对配置文件做变更:

  • root-context,增加包扫描,将数据库配置转移到进来
 <context:component-scan base-package="cn.wanmei.party">
    </context:component-scan>
     <import resource="mybatis.xml"/>
     <import resource="redis-context.xml"/>
    <import resource="spring-shiro-web.xml" /> 
  • DispatherServlet:只加载与Servlet相关的配置,在扫描类配置上需要删除对Service的扫描,避免二次扫描问题。
 <context:component-scan base-package="cn.wanmei.party">
         <context:exclude-filter expression="org.springframework.stereotype.Service" type="annotation"/>
    </context:component-scan>


  解决后:
  1:root-context饱满了
  2:Application Conext 有活干了,事务呀什么的应有的它都有了
  3:DispatherServlet的配置清爽了

经过测试,事务正常,Realm中的注解正常,从此再也不需要使用文前提到的那两种恶心的方式了。本文通过项目中事务不生效的问题,联想到Realm实现类注解失败与之存在关联,最后通过实践进一步证实推测,也进一步了解了Spring的上下文知识。

时间: 2024-10-29 10:46:32

shiro realm 注解失败问题解决过程的相关文章

记录sqoop同步失败问题解决过程,过程真的是很崎岖。(1月6日解决)

记录sqoop同步失败问题解决过程,过程真的是很崎岖.事发原因:最近突然出现sqoop export to mysql时频繁出错.看了下日志是卡在某条数据过不去了,看异常.看sqoop生成的mr并未发现问题.最后把要export的原始数据拿notepad++打开发现中断的数据是奇怪的乱码,查了一下是二进制的数据. 乱码数据生成原因:我理解,api接口时接收流数据时长度和实际长度不符. 解决办法:两块要解决,一是接口时做好容错,二是同步时还是要对这种二进制做兼容,因为谁也无法保证二进制数据不会再出

解决自定义Shiro.Realm扩展类不能用注解(@Resource或@Autowire)自动装配的问题

问题产生原因:加载Realm时其他Spring配置文件(xml)尚未加载,导致注入失败. 解决方法:编写一个设置类把注入工作提前完成. package com.xkt.shiro import org.apache.shiro.realm.Realm; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.BeansException; import org.spri

springboot + shiro 权限注解、请求乱码解决、统一异常处理

springboot + shiro 权限注解.请求乱码解决.统一异常处理 前篇 后台权限管理系统 相关: spring boot + mybatis + layui + shiro后台权限管理系统 springboot + shiro之登录人数限制.登录判断重定向.session时间设置 springboot + shiro 动态更新用户信息 基于前篇,新增功能: 新增shiro权限注解: 请求乱码问题解决: 统一异常处理. 源码已集成到项目中: github源码: https://githu

大道至简 第五章 失败的过程也是过程 读后感

今天该写一写大道至简第五章读后感了. 首先是“做过程不是做工程”,过程是为了实现某种目的而经历的一些事情,过程有很多种,虽然经历了某种过程,但不一定能实现某种功能.做完过程的每一个阶段,并不等于做工程.做过程不是做工程的精义,也不是最终目的. 然后是“做过场”,做过场就好像是一种形式一样,做了没必要做的事情,就是浪费时间. 我们为什么做工程,不要忘了最终目的.目的,是实现客户的要求,工程只是一种实现的途径.最初做开发的前辈们,不用什么工程或者过程,也一样编出了程序,也一样解决了问题,也一样实现了

大道至简--失败的过程也是过程

大道至简进行到第5章,随着工程的进行,我们可能会有成功也可能会有失败,可能会遇到各种各样的问题,下面我将就失败的过程来谈一谈,我对“失败的过程也是过程的理解”. 首先我们谈谈做过程吧.上世纪60年代软件工程提出一个瀑布模型,这标志着软件工程走向成熟.瀑布模型将开发过程分成需求.分析.设计.开发和测试等五个阶段.可是如果真的只是按照过程来进行程序的开发,我们做的那就只能是过程,而不是工程,做工程不是过程,也不是目的. 做过场.首先我想解释一下什么是走过场,在新华词典的含义是:形容只是在形式上过一下

读《大道至简——失败的过程也是过程》有感

再次怀着热情读了大道至简的第五章——失败的过程也是过程.作者首先告诉我们: 做过程不是做工程 .为什么这么说?作者讲到,按照模型,做完过程的每一个阶段, 并不等于做工程.或者说,工程并不是这样就可以做成功的.如果工程可以做成的话,只需要有模型就足够了.因此做过程并不是做工程的精义, 也不是目的.也就是 “过程”是一个确定的模板,而“工程”是有一个目的的实现在里面. "做过程不是做工程"讲述了软件工程自提出以来的一些进步(软件工程的瀑布模型,瀑布模型将软件开发的过程分成需求.分析. 设计

读《大道至简》第五章“失败的过程也是过程 ”有感

      <大道至简>讲述了软件工作者如何思考的问题,“失败的过程也是过程 ”就讲述了软件工程师在做项目甚至是工程时应该拿出一种总样的态度和行为来实现它.        "做过程不是做工程"讲述了软件工程自提出以来的一些进步(软件工程的瀑布模型,瀑布模型将软件开发的过程分成需求.分析. 设计.开发和测试等 5 个主要阶段)以及这些进步带来的”模式化“的弊端 (用 RAD 模型 RUP 模型来做工 程,即使是亦步亦趋,也做不好工程. )所以作者抛出这样一句话”做过程并不是做

CrossApp 0.3.1示例编译问题解决过程

1 AlertTest.h找不到 问题成因:HelloCpp工程中头文件搜索路径没有增加Classes目录,需要自己加进去.(另外由于这些文件都是在子目录中,用递归模式也行,逐个子目录添加也行) 2 CrossApp lib编译错误. (1) Unknown register name 'q0' in asm 按照网上说法,把对应的#if defined(__ARM_NEON__)替换成 #if defined(_ARM_ARCH_7)即可. (2) "Cast from pointer to

org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set. Authorization cache cannot be obtained.

项目中用spring shiro来处理权限的问题,但是启动的时候会打印如下日志 org.apache.shiro.realm.AuthorizingRealm - No cache or cacheManager properties have been set. Authorization cache cannot be obtained. 检查了basicRelam配置如下 <bean id="basicRealm" class="com.ebon.platform