我需要你在这个问题上给我建议,在一个spring boot应用程序中,我从数据库加载一些属性,比如(cron periods,email data),我需要在应用程序上下文中导出这些属性,以便用加载的数据来spring构建相应的beans。我怎么能这样做?
您可以根据需要手动使用数据库值配置bean(这样您可以利用Spring CDI和引导数据库配置)。
以设置会话超时为例:
@SpringBootApplication
public class MySpringBootApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
@Bean
public HttpSessionListener httpSessionListener(){
return new MyHttpSessionListener();
}
}
然后是用于配置bean的bean定义:
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener {
@Autowired
private MyRepository myRepository;
@Override
public void sessionCreated(HttpSessionEvent se) {
se.getSession().setMaxInactiveInterval(this.myRepository.getSessionTimeoutSeconds());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// Noop
}
}
注意:您可以将数据库调用移动到一个< code>@PostConstruct方法中,以避免在每个会话中都进行调用。
我认为使用BeanPostProcencer和Binder是个好主意,这样您就不需要列出所有要读取的属性。以下代码引用了ConfigurationProperty tiesBindingPostProczer。
public class PropertiesInsideDatabaseInitializer implements BeanPostProcessor, InitializingBean, ApplicationContextAware {
private JdbcTemplate jdbcTemplate;
private ApplicationContext applicationContext;
private BeanDefinitionRegistry registry;
private Map<String, Object> systemConfigMap = new HashMap<>();
private final String propertySourceName = "propertiesInsideDatabase";
public PropertiesInsideDatabaseInitializer(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
bind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));
return bean;
}
private void bind(ConfigurationPropertiesBean propertiesBean) {
if (propertiesBean == null || hasBoundValueObject(propertiesBean.getName())) {
return;
}
Assert.state(propertiesBean.getBindMethod() == ConfigurationPropertiesBean.BindMethod.JAVA_BEAN, "Cannot bind @ConfigurationProperties for bean '"
+ propertiesBean.getName() + "'. Ensure that @ConstructorBinding has not been applied to regular bean");
try {
Bindable<?> target = propertiesBean.asBindTarget();
ConfigurationProperties annotation = propertiesBean.getAnnotation();
BindHandler bindHandler = new IgnoreTopLevelConverterNotFoundBindHandler();
MutablePropertySources mutablePropertySources = new MutablePropertySources();
mutablePropertySources.addLast(new MapPropertySource(propertySourceName, systemConfigMap));
Binder binder = new Binder(ConfigurationPropertySources.from(mutablePropertySources), new PropertySourcesPlaceholdersResolver(mutablePropertySources),
ApplicationConversionService.getSharedInstance(), getPropertyEditorInitializer(), null);
binder.bind(annotation.prefix(), target, bindHandler);
}
catch (Exception ex) {
throw new BeanCreationException("", ex);
}
}
private Consumer<PropertyEditorRegistry> getPropertyEditorInitializer() {
if (this.applicationContext instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) this.applicationContext).getBeanFactory()::copyRegisteredEditorsTo;
}
return null;
}
private boolean hasBoundValueObject(String beanName) {
return this.registry.containsBeanDefinition(beanName) && this.registry
.getBeanDefinition(beanName).getClass().getName().contains("ConfigurationPropertiesValueObjectBeanDefinition");
}
@Override
public void afterPropertiesSet() {
String sql = "SELECT key, value from system_config";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
for (Map<String, Object> map : maps) {
String key = String.valueOf(map.get("key"));
Object value = map.get("value");
systemConfigMap.put(key, value);
}
this.registry = (BeanDefinitionRegistry) this.applicationContext.getAutowireCapableBeanFactory();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
还可以实现在环境中修改属性资源。BeanPostProcessor接口被实现为在创建Bean之前对其进行初始化
public class PropertiesInsideDatabaseInitializer implements BeanPostProcessor, InitializingBean, EnvironmentAware {
private JdbcTemplate jdbcTemplate;
private ConfigurableEnvironment environment;
private final String propertySourceName = "propertiesInsideDatabase";
public PropertiesInsideDatabaseInitializer(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
@Override
public void afterPropertiesSet() {
if(environment != null){
Map<String, Object> systemConfigMap = new HashMap<>();
String sql = "SELECT key, value from system_config";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
for (Map<String, Object> map : maps) {
String key = String.valueOf(map.get("key"));
Object value = map.get("value");
systemConfigMap.put(key, value);
}
environment.getPropertySources().addFirst(new MapPropertySource(propertySourceName, systemConfigMap));
}
}
@Override
public void setEnvironment(Environment environment) {
if(environment instanceof ConfigurableEnvironment){
this.environment = (ConfigurableEnvironment) environment;
}
}
}
对于那些需要在应用程序启动前从数据库加载属性,并让@Value可以在项目中的任何地方访问这些属性的人,只需添加这个处理器。
public class ReadDbPropertiesPostProcessor implements EnvironmentPostProcessor {
/**
* Name of the custom property source added by this post processor class
*/
private static final String PROPERTY_SOURCE_NAME = "databaseProperties";
private String[] KEYS = {
"excel.threads",
"cronDelay",
"cronDelayEmail",
"spring.mail.username",
"spring.mail.password",
"spring.mail.host",
"spring.mail.port",
"spring.mail.properties.mail.transport.protocol",
"spring.mail.properties.mail.smtp.auth",
"spring.mail.properties.mail.smtp.starttls.enabled",
"spring.mail.properties.mail.debug",
"spring.mail.properties.mail.smtp.starttls.required",
"spring.mail.properties.mail.socketFactory.port",
"spring.mail.properties.mail.socketFactory.class",
"spring.mail.properties.mail.socketFactory.fallback",
"white.executor.threads",
"white.search.threads",
"lot.sync.threads",
"lot.async.threads",
"lot.soap.threads",
"excel.async.threads",
"kpi.threads",
"upload.threads"
};
/**
* Adds Spring Environment custom logic. This custom logic fetch properties from database and setting highest precedence
*/
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Map<String, Object> propertySource = new HashMap<>();
try {
// Build manually datasource to ServiceConfig
DataSource ds = DataSourceBuilder
.create()
.username(environment.getProperty("spring.datasource.username"))
.password(environment.getProperty("spring.mail.password"))
.url(environment.getProperty("spring.datasource.url"))
.driverClassName("com.mysql.jdbc.Driver")
.build();
// Fetch all properties
Connection connection = ds.getConnection();
JTrace.genLog(LogSeverity.informational, "cargando configuracion de la base de datos");
PreparedStatement preparedStatement = connection.prepareStatement("SELECT value FROM config WHERE id = ?");
for (int i = 0; i < KEYS.length; i++) {
String key = KEYS[i];
preparedStatement.setString(1, key);
ResultSet rs = preparedStatement.executeQuery();
// Populate all properties into the property source
while (rs.next()) {
propertySource.put(key, rs.getString("value"));
}
rs.close();
preparedStatement.clearParameters();
}
preparedStatement.close();
connection.close();
// Create a custom property source with the highest precedence and add it to Spring Environment
environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
} // class ReadDbPropertiesPostProcessor end
为了能够连接到数据库,application.properties中必须存在数据源数据。
然后在META-INF文件夹中创建一个名为spring的文件。那里的工厂有以下几行:
org.springframework.boot.env.EnvironmentPostProcessor=test.config.ReadDbPropertiesPostProcessor
就这样,任何地方都可以访问检索到的属性。
我有三个类具有类层次结构 > < Li > < p > < code > parent class . Java 具有用于此ChildClass1的属性,它还使用来自父类的一些常见属性 < code>ChildClass2扩展ParentClass 具有用于此子类2的属性,它还使用父类中的一些公共属性 所有这些属性都包含在两列表中 现在我不确定如何从Hibernate继承加载它们? 为愚蠢的问题道
在我的项目中,我想使用特定于环境的属性文件。例如,如果我在开发中运行它,它应该使用应用程序。dev.properties,对于生产,它应该使用应用程序。产品属性等等。 我有下面两个文件在我的资源文件夹。 application.properties(用于生产) application.dev.properties(用于开发) 我有一个属性像下面的每个文件。 为了刺激 给德夫 我有一门课,如下所示
我想在应用程序启动时使用Spring ehCache将数据从数据库加载到缓存中,即在调用任何其他方法之前服务器启动时。我不想使用构造函数。请帮帮我。
我在src/main/resources下创建了2个文件: 应用程序。属性 第一个具有从env变量中获取值的属性,而后者具有固定值。 根据这里的具体情况,我以这样的方式推出了Spring靴: 然而,不会产生任何影响,并且应用程序是局部的。属性似乎被忽略。 有什么提示吗?
> 该服务使用SpringBoot、Maven、MongoDB和Ehcache。 服务需要一个快速且频繁缓存的服务器,所以最终,我选择了Ehcache。 所有缓存都将以几乎相同的频率调用,因此在这种情况下没有热数据或冷数据。 MongoDB中的原始数据每天都会被定时器服务更新,所以我每天要做的就是将所有更新的数据加载到Ehcache中。 这些数据中的每一项都彼此有联系,就像您使用一个来查找另一个的
我正在将一个非常基本的web应用程序部署到Google应用程序引擎。我使用的是Springboot,我可以在本地很好地运行应用程序,但当我部署到Google时,应用程序引擎不会启动实例。我在启动时配置了一个云SQL数据源。 我有云sql配置属性配置src/main/Resources/application.properties.App Engine似乎找不到这些属性,所以它无法正确设置Cloud