前兩天測試一個寫事務,發現這個事務出現異常不會回滾了,一直在事務上找問題,一直沒有找到,結果發現是shiro
的bean
先於Spring
事務將userService
實例化了,結果致使spring
事務初始化時好沒法掃描到該bean
,致使這個bean
上沒有綁定事務,致使事務無效java
經過百度
發現,你們都有如下幾個緣由致使事務失效web
innoDB
@EnableTransactionManagement
註解 public
Exception
等checked
異常 通過排查,發現以上緣由都經過了,那麼應該不是寫的問題。spring
在上面4個緣由檢查時,發現將已有的service
類 copy下如今有兩個除了名字其餘都如出一轍的類,這時運行下發現,在原來的類中@Transational
失效,在新copy中的類中@Transational
就起效了,這個問題好莫名奇妙,什麼都沒改就一個有效一個無效,如今的思路就是比較下這兩個類在運行時有什麼不一樣數據庫
經過log發現打出了一下信息,說是jdbc
的connection
不是Spring
管的
apache
而正常回歸的service類則是,調用了 JtaTransactionManager
類,並且 spring
是管理jdbc
的connection
的
springboot
經過這個分析,能夠知道這spring
對於這兩個類的處理是不同的,應該是spring代理或者初始化的問題,翻了下log
發現service
在ProxyTransactionManagementConfiguration
配置以前就被建立了,那應該是這裏的問題了,這裏就要分析下service
爲啥提早被建立了,發如今開始啓動的是shiro
,而shiro
中有個realm
中引用了這些服務,因此這些服務在Transaction
建立掃描以前建立了
session
致使問題的真正緣由是bean
建立順序問題,解決問題方法就是,在Transaction
以後建立service
。
ps:呵呵,可是我仍是不知道咋樣才能解決建立順序問題,繼續百度
之,關鍵詞shiro 致使 事務不生效
果真有解決方案spring-boot
通過百度找到了如下的解決方法,和如下解釋測試
在realm
引用的service
服務上加@lazy
註解,可是這個方法我測試了下並無起效!!!spa
把在 ShiroConfig
裏面初始化的Realm
的bean
和securityManager
的bean
方法移動到一個新建的ShiroComponent
中,利用監聽器中去初始化,主要配置以下,其中ShiroComponent
中UserNamePassWordRealm
和WeiXinRealm
是我自定義的兩個Realm
,換成本身的就好,
ShiroConfig.java
import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.DispatcherType; import javax.servlet.Filter; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.DelegatingFilterProxy; /** * 自定義繼承shiro 沒有使用shiro-spring-boot-web-starter 的shiro 套件 * * @author gaoxiuya * */ @Configuration public class ShiroConfig { /** * FilterRegistrationBean * * @return */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); filterRegistration.setEnabled(true); filterRegistration.addUrlPatterns("/*"); filterRegistration.setDispatcherTypes(DispatcherType.REQUEST); return filterRegistration; } /** * @param securityManager * @see org.apache.shiro.spring.web.ShiroFilterFactorupload.visit.pathyBean * @return */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(securityManager); bean.setLoginUrl("/"); bean.setSuccessUrl("/index"); bean.setUnauthorizedUrl("/403"); Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("permsc", new CustomPermissionsAuthorizationFilter()); bean.setFilters(filters); Map<String, String> chains = new LinkedHashMap<>(); chains.put("/favicon.ico", "anon"); bean.setFilterChainDefinitionMap(chains); return bean; } @Bean public EhCacheManager cacheManager() { EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml"); return cacheManager; } /** * @see DefaultWebSessionManager * @return */ @Bean(name = "sessionManager") public DefaultWebSessionManager defaultWebSessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setCacheManager(cacheManager()); sessionManager.setGlobalSessionTimeout(1800000); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionValidationSchedulerEnabled(true); sessionManager.setDeleteInvalidSessions(true); return sessionManager; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } }
ShiroComponent.java
import java.util.ArrayList; import java.util.List; import org.apache.shiro.authc.Authenticator; import org.apache.shiro.authc.pam.FirstSuccessfulStrategy; import org.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.session.mgt.SessionManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class ShiroComponent { @Bean public Realm userNamePassWordRealm(CacheManager cacheManager) { UserNamePassWordRealm userNamePassWordRealm = new UserNamePassWordRealm(); userNamePassWordRealm.setCacheManager(cacheManager); return userNamePassWordRealm; } @Bean public Realm myWeiXinRealm(CacheManager cacheManager) { WeiXinRealm weiXinRealm = new WeiXinRealm(); weiXinRealm.setCacheManager(cacheManager); return weiXinRealm; } @Bean(name = "securityManager") public DefaultWebSecurityManager securityManager(Authenticator modularRealmAuthenticator, CacheManager cacheManager, SessionManager defaultWebSessionManager) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setAuthenticator(modularRealmAuthenticator); manager.setCacheManager(cacheManager); manager.setSessionManager(defaultWebSessionManager); return manager; } @Bean public Authenticator modularRealmAuthenticator() { ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator(); modularRealmAuthenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy()); return modularRealmAuthenticator; } @EventListener public void handleContextRefresh(ContextRefreshedEvent event) { ApplicationContext context = event.getApplicationContext(); DefaultWebSecurityManager manager = (DefaultWebSecurityManager) context.getBean("securityManager"); Realm userNamePassWordRealm = (Realm) context.getBean("userNamePassWordRealm"); Realm myWeiXinRealm = (Realm) context.getBean("myWeiXinRealm"); ModularRealmAuthenticator modularRealmAuthenticator = (ModularRealmAuthenticator) context .getBean("modularRealmAuthenticator"); List<Realm> realms = new ArrayList<>(); realms.add(userNamePassWordRealm); realms.add(myWeiXinRealm); modularRealmAuthenticator.setRealms(realms); manager.setAuthenticator(modularRealmAuthenticator); manager.setRealms(realms); } }
之後須要補課的地方