1、問題拋出
今天在做springboot和shiro集成時,發(fā)現(xiàn)一個嚴重的問題。部分service的緩存和事務(wù)失效,debug代碼時,發(fā)現(xiàn)這些有問題的service實例都不是代理生成的,所以事務(wù)和緩存就失效了(事務(wù)和緩存依賴代理類實現(xiàn))。繼續(xù)查問題,發(fā)現(xiàn)這些有問題的service全部被shiro的realm所依賴,所以懷疑是shiro影響了
所以做一下測試:
shiro中用到的resourceservice
1
2
3
4
5
|
public class localrealmservice extends realmservice { @autowired private resourceservice resourceservice; ... } |
controller也調(diào)用resourceservice
1
2
3
4
5
6
7
8
|
@restcontroller @requestmapping (value = "/test" ) public class cachecontroller { private logger logger = loggerfactory.getlogger( this .getclass()); @autowired private resourceservice resourceservice; } |
結(jié)果發(fā)現(xiàn)resourceservice的實例如圖:
發(fā)現(xiàn)問題:resourceservice的實例不是代理即緩存注解和事務(wù)全部生效(緩存和事務(wù)都是代理完成的)
當(dāng)我把resourceservice從realm依賴中刪除時,在controller引用時resourceservice的實例就是“代理”即緩存和事務(wù)生效
結(jié)論:只要被shiro的realm所依賴的service,代理會全部失效(暫時沒擼源碼,還不知原理,知道的童鞋可以說下,謝了)
2、解決的方案
常用的解決方式有三種:
第一種:這是網(wǎng)上比較多的
就是realm中不要依賴service,依賴dao
第二種:在依賴的service上添加@lazy注解
延遲加載,就是在實例化shiro的realm時,不去實例化service的bean,等到用的時候再從spring容器中去取對應(yīng)的bean
1
2
3
4
5
6
7
|
public class localrealmservice extends realmservice { @lazy @autowired private resourceservice resourceservice; ... } |
這種解決方案讓我感覺到:這里是不是存在多個上下文,或者不是spring?這里有待后續(xù)考證。。。
第三種:shiro在實例化securitymanager時,先不設(shè)置realm,等到容器加載完再設(shè)置
這種方式與第二種類似,只不過無需在每個service屬性上增加@lazy注解
securitymangaerd的實例化
1
2
3
4
5
6
7
8
9
10
11
|
/** * 注釋掉realm */ @bean ( "securitymanager" ) public defaultwebsecuritymanager securitymanager( /*@qualifier("realm") bootrealm bootrealm,*/ sessionmanager sessionmanager, cachemanager shirocachemanager) { defaultwebsecuritymanager manager = new defaultwebsecuritymanager(); //注釋掉 //manager.setrealm(hybootrealm); } |
容器加載完設(shè)置realm:這里有多重方案,主要列舉兩種
i、利用spring監(jiān)聽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import org.springframework.context.applicationevent; import org.springframework.context.applicationlistener; @component public class shirorealmlistener implements applicationlistener { @autowired private defaultwebsecuritymanager securitymanager; @autowired private hybootrealm realm; @override public void onapplicationevent(applicationevent event) { securitymanager.setrealm(realm); } } |
ii、利用springboot的applicationrunner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import com.chyjr.hyboot.security.shiro.realm.hybootrealm; import org.apache.shiro.web.mgt.defaultwebsecuritymanager; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.applicationarguments; import org.springframework.boot.applicationrunner; public class shirorealmrunner implements applicationrunner { @autowired private defaultwebsecuritymanager securitymanager; @autowired private hybootrealm realm; @override public void run(applicationarguments args) throws exception { securitymanager.setrealm(realm); } } |
注意:shirorealmrunner必須是spring的bean,所以在配置管理類中要添加:
1
2
3
4
|
@bean public shirorealmrunner shirorealmrunner(){ return new shirorealmrunner(); } |
總結(jié):
上述就是常用的解決方案,至于原理后續(xù)會抽時間研究....
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:https://www.cnblogs.com/liruiloveparents/p/9392159.html