Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 327|回复: 0

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

[复制链接]
  • TA的每日心情
    奋斗
    8 小时前
  • 签到天数: 776 天

    [LV.10]以坛为家III

    2046

    主题

    2104

    帖子

    71万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    714508
    发表于 2021-5-22 21:32:01 | 显示全部楼层 |阅读模式

      做为一名在.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的上下文知识。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-8-15 21:36 , Processed in 0.067264 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表