项目背景:

服务基于springboot搭建,shiro做认证鉴权,本地启动正常,打包正常,服务器启动正常,采用jenkins打包部署服务,偶尔出现问题

原因分析:

因为问题是偶现的,当时觉得是环境问题导致,有的服务器可以启动,有的服务器无法启动,报错是偶现的

初步排查了环境,jdk,port,mvn,jenkins服务器配置,都没问题

排查日志:

2020-05-13 22:07:48.066  INFO 876 --- [main] com.*.SpringBootApplication               : Starting SpringBootApplication v1.0.0.0-SNAPSHOT on server with PID 876 (/opt/server/ms-server.jar started by root in /opt/server)
2020-05-13 22:07:48.072 DEBUG 876 --- [main] com.*.SpringBootApplication               : Running with Spring Boot v2.2.2.RELEASE, Spring v5.2.2.RELEASE
2020-05-13 22:07:48.072  INFO 876 --- [main] com.*.SpringBootApplication               : The following profiles are active: dev
2020-05-13 22:07:51.969  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2020-05-13 22:07:51.976  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Elasticsearch repositories in DEFAULT mode.
2020-05-13 22:07:52.113  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 114ms. Found 0 Elasticsearch repository interfaces.
2020-05-13 22:07:52.134  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2020-05-13 22:07:52.134  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Reactive Elasticsearch repositories in DEFAULT mode.
2020-05-13 22:07:52.177  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 42ms. Found 0 Reactive Elasticsearch repository interfaces.
2020-05-13 22:07:52.240  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2020-05-13 22:07:52.284  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2020-05-13 22:07:52.357  INFO 876 --- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 44ms. Found 0 Redis repository interfaces.
2020-05-13 22:07:53.633  INFO 876 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'webConfig' of type [com.*.config.WebConfig$$EnhancerBySpringCGLIB$$323d34e4] 
																							is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-13 22:07:54.038  INFO 876 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] 
																							is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-13 22:07:54.442  INFO 876 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'redisConfig' of type [com.*.base.redis.RedisConfig$$EnhancerBySpringCGLIB$$4b225e87
 is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-13 22:07:54.479  INFO 876 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'shiroConfig' of type [com.*.config.ShiroConfig$$EnhancerBySpringCGLIB$$e73c6be1]
 is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-05-13 22:07:54.543  WARN 876 --- [main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: 
org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'objectMapperConfigurer' defined in class path resource [springfox/documentation/spring/web/SpringfoxWebMvcConfiguration.class]: 
						BeanPostProcessor before instantiation of bean failed;
 						nested exception is org.springframework.beans.factory.BeanCreationException:
 						Error creating bean with name 'druidConfig' defined in URL [jar:file:/opt/server/ms-server.jar!/BOOT-INF/classes!/com/*/config/DruidConfig.class]: 
 						BeanPostProcessor before instantiation of bean failed; 
 						nested exception is org.springframework.beans.factory.BeanCreationException: 
 						Error creating bean with name 'authorizationAttributeSourceAdvisor' defined in class path resource [com/*/config/ShiroConfig.class]: 
 						Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: 
 						Failed to instantiate [org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor]: 
 						Factory method 'authorizationAttributeSourceAdvisor' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: 
 						Error creating bean with name 'securityManager' defined in class path resource [com/*/config/ShiroConfig.class]: 
 						Bean instantiation via factory method failed; 
 						nested exception is org.springframework.beans.BeanInstantiationException: 
 						Failed to instantiate [org.apache.shiro.mgt.SecurityManager]:
 						Factory method 'securityManager' threw exception; 
 						nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
 						Error creating bean with name 'customRealm': 
 						Unsatisfied dependency expressed through field 'managerBiz'; 
 						nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: 
 						Error creating bean with name 'shirFilter' defined in class path resource [com/*/config/ShiroConfig.class]: 
 						Unsatisfied dependency expressed through method 'shirFilter' parameter 0; 
 						nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
 						Error creating bean with name 'securityManager': Requested bean is currently in creation: 
 						Is there an unresolvable circular reference?
2020-05-13 22:07:54.556  INFO 876 --- [main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-05-13 22:07:54.571 ERROR 876 --- [main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   objectMapperConfigurer defined in class path resource [springfox/documentation/spring/web/SpringfoxWebMvcConfiguration.class]
      ↓
   druidConfig defined in URL [jar:file:/opt/server/ms-server.jar!/BOOT-INF/classes!/com/*/config/DruidConfig.class]
      ↓
   authorizationAttributeSourceAdvisor defined in class path resource [com/*/config/ShiroConfig.class]
┌─────┐
|  securityManager defined in class path resource [com/*/config/ShiroConfig.class]
↑     ↓
|  customRealm (field private com.*.basic.biz.IXBiz com.*.basic.security.BaseAuthRealm.managerBiz)
↑     ↓
|  shirFilter defined in class path resource [com/*/config/ShiroConfig.class]
└─────┘


排查发现 虽然是偶现的打包问题 本地起服务虽然可以起来 但这里报循环依赖问题 查看日志发现

Failed to instantiate [org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor]: 
Factory method 'authorizationAttributeSourceAdvisor' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'securityManager' defined in class path resource [com/*/config/ShiroConfig.class]: 

┌─────┐
|  securityManager defined in class path resource [com/*/config/ShiroConfig.class]
↑     ↓
|  customRealm (field private com.*.basic.biz.IXBiz com.*.basic.security.BaseAuthRealm.managerBiz)
↑     ↓
|  shirFilter defined in class path resource [com/*/config/ShiroConfig.class]
└─────┘

在此处创建Bean失败了~

 

问题定位:

附上问题代码:

package com.*.config;

import com.*.basic.security.BaseAuthRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

	@Value("${path}")
	private String path;

	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
		shiroFilterFactoryBean.setLoginUrl(path + "/index");
		// 设置无权限时跳转的 url;
		shiroFilterFactoryBean.setUnauthorizedUrl(path + "/404.html");

		// 设置拦截器
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		// 游客,开发权限
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/html/**", "anon");
		// 开放登陆接口
		filterChainDefinitionMap.put(path + "/index", "anon");
		// 其余接口一律拦截
		// 主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
		filterChainDefinitionMap.put(path + "/**", "authc");

		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}


	/**
	 * 注入 securityManager
	 */
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 设置realm
		securityManager.setRealm(customRealm());
		return securityManager;
	}


    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

	/**
	 * 自定义身份认证 realm;
	 * 必须写这个类,并加上 @Bean 注解,目的是注入 自定义Realm, 否则会影响 自定义Realm类 中其他类的依赖注入
	 */
	@Bean
	public BaseAuthRealm customRealm() {
		return new BaseAuthRealm();
	}
}

此处问题代码:

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

原因分析:

这个bean注册时,调用了securityManager()方法,此处这个方法被多次调用,原则上应该是引用而不是新建一个Bean,此处Bean应该是单例的

代码修复:

    @Bean
    @ConditionalOnMissingBean
    public AuthorizationAttributeSourceAdvisor     
    authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new 
    AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

附上修复后的代码:

package com.*.config;

import com.*.basic.security.BaseAuthRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

	@Value("${path}")
	private String path;

	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
		shiroFilterFactoryBean.setLoginUrl(path + "/index");
		// 设置无权限时跳转的 url;
		shiroFilterFactoryBean.setUnauthorizedUrl(path + "/404.html");

		// 设置拦截器
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		// 游客,开发权限
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/html/**", "anon");
		// 开放登陆接口
		filterChainDefinitionMap.put(path + "/index", "anon");
		// 其余接口一律拦截
		// 主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
		filterChainDefinitionMap.put(path + "/**", "authc");

		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}


	/**
	 * 注入 securityManager
	 */
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 设置realm
		securityManager.setRealm(customRealm());
		return securityManager;
	}


    @Bean
	@ConditionalOnMissingBean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

	/**
	 * 自定义身份认证 realm;
	 * 必须写这个类,并加上 @Bean 注解,目的是注入 自定义Realm, 否则会影响 自定义Realm类 中其他类的依赖注入
	 */
	@Bean
	public BaseAuthRealm customRealm() {
		return new BaseAuthRealm();
	}
}

问题解决     jenkins部署/本地打包/mvn都不会出现问题了~

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐