Restart/Reload Spring 数据 MongoDB
Restart/Reload Spring Data MongoDB
在我的项目中,我使用 属性 占位符来读取 属性 文件,其中包含我的数据库连接的配置。在我的初始设置和稍后某个时间点的重新配置期间,我希望能够更改数据库主机的详细信息。
我尝试使用在当前应用程序上下文中调用的 refresh() 方法,但不知何故 Spring 数据 Bean 没有重新加载,我收到 Spring 数据发出的 IllegalStateException:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: open
Exception report: Message: Request processing failed; nested exception is java.lang.IllegalStateException: open description: The server encountered an internal error that prevented it from fulfilling this request. exception: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: open
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
root cause: java.lang.IllegalStateException: open
org.bson.util.Assertions.isTrue(Assertions.java:36)
com.mongodb.DBTCPConnector.getPrimaryPort(DBTCPConnector.java:408)
com.mongodb.DBCollectionImpl.update(DBCollectionImpl.java:263)
com.mongodb.DBCollection.update(DBCollection.java:191)
com.mongodb.DBCollection.save(DBCollection.java:975)
com.mongodb.DBCollection.save(DBCollection.java:934)
org.springframework.data.mongodb.core.MongoTemplate.doInCollection(MongoTemplate.java:950)
org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:410)
org.springframework.data.mongodb.core.MongoTemplate.saveDBObject(MongoTemplate.java:945)
org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:885)
org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:833)
org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:73)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:442)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:427)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.data.repository.core.support.RepositoryFactorySupport$DefaultMethodInvokingMethodInterceptor.invoke(RepositoryFactorySupport.java:512)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy2987.save(Unknown Source)
de.steilerdev.myVerein.server.controller.InitController.initSuperAdmin(InitController.java:158)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
不幸的是,我对 bean 及其生命周期不是很有信心,所以我需要帮助重新加载适当的 bean。我也同意重新启动 Spring 应用程序本身的可能性,即使这将是一项昂贵的操作。因为很少需要它,所以我可以接受它的费用。
我不确定您需要哪部分代码,但这里是 Github 存储库的 link。 (抱歉,文档不完善,仍处于项目开始阶段)
谢谢!
编辑:一些 类 参与了这个过程:
de.steilerdev.myVerein.server.controller.InitController(接收相关请求,将设置存储到我的SettingsRepository)
@Controller
@RequestMapping("/init")
public class InitController
{
@Autowired
private SettingsRepository settingsRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private DivisionRepository divisionRepository;
@Autowired
private ReloadableResourceBundleMessageSource messageSource;
private static Logger logger = LoggerFactory.getLogger(InitController.class);
@RequestMapping(value = "settings")
public ResponseEntity<String> initSettings(@RequestParam String clubName,
@RequestParam String databaseHost,
@RequestParam String databasePort,
@RequestParam String databaseUser,
@RequestParam String databasePassword,
@RequestParam String databaseCollection,
@RequestParam String rememberMeTokenKey,
Locale locale)
{
logger.debug("Starting initial configuration");
if(!settingsRepository.isInitSetup())
{
logger.warn("An initial setup API was used, even though the system is already configured.");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.notAllowed", null, "You are not allowed to perform this action at the moment", locale), HttpStatus.BAD_REQUEST);
} else if(clubName.isEmpty() || rememberMeTokenKey.isEmpty())
{
logger.warn("The club name or remember me key is not present");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.noKeyOrName", null, "The club name and remember me key is required", locale), HttpStatus.BAD_REQUEST);
} else
{
int databasePortInt = 27017;
if(databaseHost.isEmpty())
{
logger.warn("The database host is empty, using default value.");
databaseHost = "localhost";
}
if(databasePort.isEmpty())
{
logger.warn("The database port is empty, using default value.");
databasePort = "27017";
} else
{
try
{
databasePortInt = Integer.parseInt(databasePort);
} catch (NumberFormatException e)
{
logger.warn("The database port seems not to be a number " + databasePort);
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.dbPortNoNumber", null, "The database port needs to be a number", locale), HttpStatus.BAD_REQUEST);
}
}
if(databaseCollection.isEmpty())
{
logger.warn("The database collection name is empty, using default value");
databaseCollection = "myVerein";
}
if(!mongoIsAvailable(databaseHost, databasePortInt, databaseUser, databasePassword, databaseCollection))
{
logger.warn("The stated MongoDB is not available");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.mongoNotAvailable", null, "The stated MongoDB is not available", locale), HttpStatus.BAD_REQUEST);
}
try
{
logger.debug("Temporarily storing information");
settingsRepository.setClubName(clubName);
settingsRepository.setDatabaseHost(databaseHost);
settingsRepository.setDatabasePort(databasePort);
settingsRepository.setDatabaseUser(databaseUser);
settingsRepository.setDatabasePassword(databasePassword);
settingsRepository.setDatabaseName(databaseCollection);
settingsRepository.setRememberMeKey(rememberMeTokenKey);
} catch (IOException e)
{
logger.warn("Unable to save settings.");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.savingSettingsError", null, "Unable to save settings, please try again", locale), HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.savingSettingsSuccess", null, "Successfully saved settings", locale), HttpStatus.OK);
}
}
@RequestMapping(value = "superAdmin")
public ResponseEntity<String> initSuperAdmin(@RequestParam String firstName,
@RequestParam String lastName,
@RequestParam String email,
@RequestParam String password,
@RequestParam String passwordRe,
Locale locale)
{
if(!settingsRepository.isInitSetup())
{
logger.warn("An initial setup API was used, even though the system is already configured.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.notAllowed", null, "You are not allowed to perform this action at the moment", locale), HttpStatus.BAD_REQUEST);
} else if(firstName.isEmpty() || lastName.isEmpty() || email.isEmpty() || password.isEmpty() || passwordRe.isEmpty())
{
logger.warn("A required parameter of the super admin is empty or missing during initial configuration");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.missingParameter", null, "A required parameter is empty or missing", locale), HttpStatus.BAD_REQUEST);
} else if(!password.equals(passwordRe))
{
logger.warn("The password and the re-typed password do not match!");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.passwordMatchError", null, "The password and the re-typed password do not match", locale), HttpStatus.BAD_REQUEST);
} else
{
logger.debug("Creating a new initial user.");
User superAdmin = new User();
superAdmin.setFirstName(firstName);
superAdmin.setLastName(lastName);
superAdmin.setEmail(email);
superAdmin.setPassword(password);
logger.debug("Creating a new initial root division.");
Division rootDivision = new Division(settingsRepository.getClubName(), null, superAdmin, null);
//Saving changes and restarting context
try
{
settingsRepository.setInitSetup(false);
//This call is restarting the application.
settingsRepository.saveSettings(superAdmin);
} catch (IOException e)
{
logger.warn("Unable to save settings.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.savingSettingsError", null, "Unable to save settings, please try again", locale), HttpStatus.INTERNAL_SERVER_ERROR);
}
try
{
userRepository.save(superAdmin);
divisionRepository.save(rootDivision);
} catch (ConstraintViolationException e)
{
logger.warn("A database constraint was violated while saving the new super admin.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.constraintViolation", null, "A database constraint was violated while saving the new super admin", locale), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.savingAdminSuccess", null, "Successfully saved the new super admin. The settings are now being saved and the application is restarted.", locale) , HttpStatus.OK);
}
}
private boolean mongoIsAvailable(String databaseHost, int databasePort, String databaseUser, String databasePassword, String databaseCollection)
{
logger.debug("Creating mongo client to test connection");
List<MongoCredential> credential = null;
MongoClient mongoClient = null;
if(!databaseUser.isEmpty() && !databasePassword.isEmpty())
{
credential = Arrays.asList(MongoCredential.createMongoCRCredential(databaseUser, databaseCollection, databasePassword.toCharArray()));
}
try
{
mongoClient = new MongoClient(new ServerAddress(databaseHost, databasePort),credential);
//Checking if connection REALLY works
List<String> databases = mongoClient.getDatabaseNames();
if(databases == null)
{
logger.warn("The list of databases is null");
return false;
} else if(databases.isEmpty())
{
logger.info("The databases are empty");
return true;
} else
{
logger.debug("The database connection seems okay.");
return true;
}
} catch (UnknownHostException e)
{
logger.warn("Unable to resolve mongoDB host: " + e.getMessage());
return false;
} catch (MongoException e)
{
logger.warn("Unable to receive list of present databases: " + e.getMessage());
return false;
} finally
{
if(mongoClient != null)
{
mongoClient.close();
}
}
}
}
de.steilerdev.myVerein.server.model.SettingsRepository(在属性文件中检索和存储永久设置,以及在设置更改时重新启动应用程序)
public class SettingsRepository
{
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private SimpleMongoDbFactory mongoDbFactory;
@Autowired
private ApplicationContext applicationContext;
private Properties settings;
private Resource settingsResource;
private final static String settingsFileName = "myVerein.properties";
//Property names
private final static String databaseName = "dbName";
private final static String databaseHost = "dbHost";
private final static String databasePort = "dbPort";
private final static String databaseUser = "dbUser";
private final static String databasePassword = "dbPassword";
private final static String rememberMeKey = "rememberMeKey";
private final static String clubName = "clubName";
private final static String initSetup = "initSetup";
private boolean changed;
private boolean databaseChanged;
private static Logger logger = LoggerFactory.getLogger(SettingsRepository.class);
public Properties loadSettings() throws IOException
{
if(settings == null)
{
logger.debug("Loading settings file from classpath");
settingsResource = new ClassPathResource(settingsFileName);
changed = false;
databaseChanged = false;
return (settings = PropertiesLoaderUtils.loadProperties(settingsResource));
} else
{
return settings;
}
}
//Getter and setter removed
public void saveSettings(User currentUser) throws IOException
{
saveSettings(loadSettings(), currentUser);
}
public void saveSettings(Properties settings, User currentUser) throws IOException
{
if(changed)
{
logger.debug("Saving settings to " + settingsResource.getFile().getAbsolutePath());
settings.store(new FileOutputStream(settingsResource.getFile()), "Settings last changed " + (currentUser != null ? ("by " + currentUser.getEmail() + " (" + LocalDateTime.now().toString() + ")") : LocalDateTime.now().toString()));
if(databaseChanged)
{
try
{
mongoDbFactory.destroy();
} catch (Exception e)
{
System.err.println("Problem destroying factory");
}
((ConfigurableApplicationContext) applicationContext).refresh();
}
this.settings = null;
} else
{
logger.debug("No need to save the settings");
}
}
}
在InitController的第178行抛出异常,这意味着在重新加载之后和将对象保存到新控制器期间userRepository.save(superAdmin);
很难说,为什么重新加载不起作用,基于普通的异常,但这里有一些提示:
关于重启应用上下文,有一篇很好的文章
http://jroller.com/Solomon/entry/reloading_a_spring_web_application
你可以从那里得到一些关于它为什么会出现故障的线索。
使用上下文重新加载时,您需要小心地在应用程序关闭时正确关闭所有打开的资源。
检查您是否在应用程序上下文中正确关闭了 Mongo 连接。
What is the correct way to close the mongo connection using spring-mongo?
添加代码后。很难理解,你想用这个来完成什么。这将需要您付出很多努力才能使其正常工作,而且大部分努力都是徒劳的。
您不能重新加载 Spring 上下文中的特定 bean,但您可以通过调用 ApplicationContext refresh() 重新加载整个上下文,之后将重新创建所有 bean,包括您的控制器 bean。所以这至少应该是一个单独的控制器,没有额外的功能。此外,您似乎假设您可以更改 mongo 配置,并在同一调用中使用旧引用向 mongo 写入一些内容……这不是 spring 中的工作方式。所以别这样。
在我的项目中,我使用 属性 占位符来读取 属性 文件,其中包含我的数据库连接的配置。在我的初始设置和稍后某个时间点的重新配置期间,我希望能够更改数据库主机的详细信息。
我尝试使用在当前应用程序上下文中调用的 refresh() 方法,但不知何故 Spring 数据 Bean 没有重新加载,我收到 Spring 数据发出的 IllegalStateException:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: open
Exception report: Message: Request processing failed; nested exception is java.lang.IllegalStateException: open description: The server encountered an internal error that prevented it from fulfilling this request. exception: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: open
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
root cause: java.lang.IllegalStateException: open
org.bson.util.Assertions.isTrue(Assertions.java:36)
com.mongodb.DBTCPConnector.getPrimaryPort(DBTCPConnector.java:408)
com.mongodb.DBCollectionImpl.update(DBCollectionImpl.java:263)
com.mongodb.DBCollection.update(DBCollection.java:191)
com.mongodb.DBCollection.save(DBCollection.java:975)
com.mongodb.DBCollection.save(DBCollection.java:934)
org.springframework.data.mongodb.core.MongoTemplate.doInCollection(MongoTemplate.java:950)
org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:410)
org.springframework.data.mongodb.core.MongoTemplate.saveDBObject(MongoTemplate.java:945)
org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:885)
org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:833)
org.springframework.data.mongodb.repository.support.SimpleMongoRepository.save(SimpleMongoRepository.java:73)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:442)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:427)
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.data.repository.core.support.RepositoryFactorySupport$DefaultMethodInvokingMethodInterceptor.invoke(RepositoryFactorySupport.java:512)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
com.sun.proxy.$Proxy2987.save(Unknown Source)
de.steilerdev.myVerein.server.controller.InitController.initSuperAdmin(InitController.java:158)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:139)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
不幸的是,我对 bean 及其生命周期不是很有信心,所以我需要帮助重新加载适当的 bean。我也同意重新启动 Spring 应用程序本身的可能性,即使这将是一项昂贵的操作。因为很少需要它,所以我可以接受它的费用。
我不确定您需要哪部分代码,但这里是 Github 存储库的 link。 (抱歉,文档不完善,仍处于项目开始阶段)
谢谢!
编辑:一些 类 参与了这个过程:
de.steilerdev.myVerein.server.controller.InitController(接收相关请求,将设置存储到我的SettingsRepository)
@Controller
@RequestMapping("/init")
public class InitController
{
@Autowired
private SettingsRepository settingsRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private DivisionRepository divisionRepository;
@Autowired
private ReloadableResourceBundleMessageSource messageSource;
private static Logger logger = LoggerFactory.getLogger(InitController.class);
@RequestMapping(value = "settings")
public ResponseEntity<String> initSettings(@RequestParam String clubName,
@RequestParam String databaseHost,
@RequestParam String databasePort,
@RequestParam String databaseUser,
@RequestParam String databasePassword,
@RequestParam String databaseCollection,
@RequestParam String rememberMeTokenKey,
Locale locale)
{
logger.debug("Starting initial configuration");
if(!settingsRepository.isInitSetup())
{
logger.warn("An initial setup API was used, even though the system is already configured.");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.notAllowed", null, "You are not allowed to perform this action at the moment", locale), HttpStatus.BAD_REQUEST);
} else if(clubName.isEmpty() || rememberMeTokenKey.isEmpty())
{
logger.warn("The club name or remember me key is not present");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.noKeyOrName", null, "The club name and remember me key is required", locale), HttpStatus.BAD_REQUEST);
} else
{
int databasePortInt = 27017;
if(databaseHost.isEmpty())
{
logger.warn("The database host is empty, using default value.");
databaseHost = "localhost";
}
if(databasePort.isEmpty())
{
logger.warn("The database port is empty, using default value.");
databasePort = "27017";
} else
{
try
{
databasePortInt = Integer.parseInt(databasePort);
} catch (NumberFormatException e)
{
logger.warn("The database port seems not to be a number " + databasePort);
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.dbPortNoNumber", null, "The database port needs to be a number", locale), HttpStatus.BAD_REQUEST);
}
}
if(databaseCollection.isEmpty())
{
logger.warn("The database collection name is empty, using default value");
databaseCollection = "myVerein";
}
if(!mongoIsAvailable(databaseHost, databasePortInt, databaseUser, databasePassword, databaseCollection))
{
logger.warn("The stated MongoDB is not available");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.mongoNotAvailable", null, "The stated MongoDB is not available", locale), HttpStatus.BAD_REQUEST);
}
try
{
logger.debug("Temporarily storing information");
settingsRepository.setClubName(clubName);
settingsRepository.setDatabaseHost(databaseHost);
settingsRepository.setDatabasePort(databasePort);
settingsRepository.setDatabaseUser(databaseUser);
settingsRepository.setDatabasePassword(databasePassword);
settingsRepository.setDatabaseName(databaseCollection);
settingsRepository.setRememberMeKey(rememberMeTokenKey);
} catch (IOException e)
{
logger.warn("Unable to save settings.");
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.savingSettingsError", null, "Unable to save settings, please try again", locale), HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>(messageSource.getMessage("init.message.settings.savingSettingsSuccess", null, "Successfully saved settings", locale), HttpStatus.OK);
}
}
@RequestMapping(value = "superAdmin")
public ResponseEntity<String> initSuperAdmin(@RequestParam String firstName,
@RequestParam String lastName,
@RequestParam String email,
@RequestParam String password,
@RequestParam String passwordRe,
Locale locale)
{
if(!settingsRepository.isInitSetup())
{
logger.warn("An initial setup API was used, even though the system is already configured.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.notAllowed", null, "You are not allowed to perform this action at the moment", locale), HttpStatus.BAD_REQUEST);
} else if(firstName.isEmpty() || lastName.isEmpty() || email.isEmpty() || password.isEmpty() || passwordRe.isEmpty())
{
logger.warn("A required parameter of the super admin is empty or missing during initial configuration");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.missingParameter", null, "A required parameter is empty or missing", locale), HttpStatus.BAD_REQUEST);
} else if(!password.equals(passwordRe))
{
logger.warn("The password and the re-typed password do not match!");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.passwordMatchError", null, "The password and the re-typed password do not match", locale), HttpStatus.BAD_REQUEST);
} else
{
logger.debug("Creating a new initial user.");
User superAdmin = new User();
superAdmin.setFirstName(firstName);
superAdmin.setLastName(lastName);
superAdmin.setEmail(email);
superAdmin.setPassword(password);
logger.debug("Creating a new initial root division.");
Division rootDivision = new Division(settingsRepository.getClubName(), null, superAdmin, null);
//Saving changes and restarting context
try
{
settingsRepository.setInitSetup(false);
//This call is restarting the application.
settingsRepository.saveSettings(superAdmin);
} catch (IOException e)
{
logger.warn("Unable to save settings.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.savingSettingsError", null, "Unable to save settings, please try again", locale), HttpStatus.INTERNAL_SERVER_ERROR);
}
try
{
userRepository.save(superAdmin);
divisionRepository.save(rootDivision);
} catch (ConstraintViolationException e)
{
logger.warn("A database constraint was violated while saving the new super admin.");
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.constraintViolation", null, "A database constraint was violated while saving the new super admin", locale), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(messageSource.getMessage("init.message.admin.savingAdminSuccess", null, "Successfully saved the new super admin. The settings are now being saved and the application is restarted.", locale) , HttpStatus.OK);
}
}
private boolean mongoIsAvailable(String databaseHost, int databasePort, String databaseUser, String databasePassword, String databaseCollection)
{
logger.debug("Creating mongo client to test connection");
List<MongoCredential> credential = null;
MongoClient mongoClient = null;
if(!databaseUser.isEmpty() && !databasePassword.isEmpty())
{
credential = Arrays.asList(MongoCredential.createMongoCRCredential(databaseUser, databaseCollection, databasePassword.toCharArray()));
}
try
{
mongoClient = new MongoClient(new ServerAddress(databaseHost, databasePort),credential);
//Checking if connection REALLY works
List<String> databases = mongoClient.getDatabaseNames();
if(databases == null)
{
logger.warn("The list of databases is null");
return false;
} else if(databases.isEmpty())
{
logger.info("The databases are empty");
return true;
} else
{
logger.debug("The database connection seems okay.");
return true;
}
} catch (UnknownHostException e)
{
logger.warn("Unable to resolve mongoDB host: " + e.getMessage());
return false;
} catch (MongoException e)
{
logger.warn("Unable to receive list of present databases: " + e.getMessage());
return false;
} finally
{
if(mongoClient != null)
{
mongoClient.close();
}
}
}
}
de.steilerdev.myVerein.server.model.SettingsRepository(在属性文件中检索和存储永久设置,以及在设置更改时重新启动应用程序)
public class SettingsRepository
{
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private SimpleMongoDbFactory mongoDbFactory;
@Autowired
private ApplicationContext applicationContext;
private Properties settings;
private Resource settingsResource;
private final static String settingsFileName = "myVerein.properties";
//Property names
private final static String databaseName = "dbName";
private final static String databaseHost = "dbHost";
private final static String databasePort = "dbPort";
private final static String databaseUser = "dbUser";
private final static String databasePassword = "dbPassword";
private final static String rememberMeKey = "rememberMeKey";
private final static String clubName = "clubName";
private final static String initSetup = "initSetup";
private boolean changed;
private boolean databaseChanged;
private static Logger logger = LoggerFactory.getLogger(SettingsRepository.class);
public Properties loadSettings() throws IOException
{
if(settings == null)
{
logger.debug("Loading settings file from classpath");
settingsResource = new ClassPathResource(settingsFileName);
changed = false;
databaseChanged = false;
return (settings = PropertiesLoaderUtils.loadProperties(settingsResource));
} else
{
return settings;
}
}
//Getter and setter removed
public void saveSettings(User currentUser) throws IOException
{
saveSettings(loadSettings(), currentUser);
}
public void saveSettings(Properties settings, User currentUser) throws IOException
{
if(changed)
{
logger.debug("Saving settings to " + settingsResource.getFile().getAbsolutePath());
settings.store(new FileOutputStream(settingsResource.getFile()), "Settings last changed " + (currentUser != null ? ("by " + currentUser.getEmail() + " (" + LocalDateTime.now().toString() + ")") : LocalDateTime.now().toString()));
if(databaseChanged)
{
try
{
mongoDbFactory.destroy();
} catch (Exception e)
{
System.err.println("Problem destroying factory");
}
((ConfigurableApplicationContext) applicationContext).refresh();
}
this.settings = null;
} else
{
logger.debug("No need to save the settings");
}
}
}
在InitController的第178行抛出异常,这意味着在重新加载之后和将对象保存到新控制器期间userRepository.save(superAdmin);
很难说,为什么重新加载不起作用,基于普通的异常,但这里有一些提示:
关于重启应用上下文,有一篇很好的文章
http://jroller.com/Solomon/entry/reloading_a_spring_web_application
你可以从那里得到一些关于它为什么会出现故障的线索。
使用上下文重新加载时,您需要小心地在应用程序关闭时正确关闭所有打开的资源。
检查您是否在应用程序上下文中正确关闭了 Mongo 连接。
What is the correct way to close the mongo connection using spring-mongo?
添加代码后。很难理解,你想用这个来完成什么。这将需要您付出很多努力才能使其正常工作,而且大部分努力都是徒劳的。
您不能重新加载 Spring 上下文中的特定 bean,但您可以通过调用 ApplicationContext refresh() 重新加载整个上下文,之后将重新创建所有 bean,包括您的控制器 bean。所以这至少应该是一个单独的控制器,没有额外的功能。此外,您似乎假设您可以更改 mongo 配置,并在同一调用中使用旧引用向 mongo 写入一些内容……这不是 spring 中的工作方式。所以别这样。