Bei der Verarbeitung von Einstellungswerten in Spring Framework können Einstellungswerte in Eigenschaftendateien, Systemeigenschaften (durch -D angegebene Werte), Betriebssystemumgebungsvariablen, JNDI (nur Webanwendungsumgebung) usw. und auf der Anwendungsseite angegeben werden Es kann über "@ Value" oder "Environment" bezogen werden.
Zum Beispiel sieht es wie folgt aus.
Beispiel für die Einstellung der Wertespezifikation(Eigenschaftendatei)
services.user.url=http://user.service.com/{id}
services.company.url=http://company.service.com/{id}
Referenzbeispiel für Einstellwert
@Service
public class MyService {
private final RestTemplate restTemplate = new RestTemplate();
private final Environment environment;
@Value("${services.user.url}") //Injizieren Sie den Einstellwert beim Generieren der Bean
private String userServiceUrl;
public MyService(Environment environment) {
this.environment = environment;
}
public User getUser(String id) {
User user = restTemplate.getForObject(userServiceUrl, User.class, id);
return user;
}
public Company getCompany(String id) {
String companyServiceUrl = environment.getProperty("services.company.url"); //Holen Sie sich den eingestellten Wert zur Laufzeit
Company company = restTemplate.getForObject(companyServiceUrl, User.class);
return company;
}
}
In Spring Boot anstelle von "@ Value" "[Typensichere Konfigurationseigenschaften](https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#" Ich denke, es ist üblich, "boot-features-external-config-typesafe-configuration-properties" zu verwenden, aber hier wird ** absichtlich ** "
@ Value"als Eigenschaftsplatzhalter verwendet (" Gibt an, dass $ {...}
)) verwendet werden soll. (Obwohl ich es nicht erklären werde, gilt die hier vorgestellte Methode auch für "typsichere Konfigurationseigenschaften".)
Spring Framwork (leider?) Bietet keine Klasse zum Abrufen der Einstellungen aus der Datenbank, aber das Speicherziel der Einstellungen wird von einer Klasse namens "PropertySource" abstrahiert, sodass die Einstellungen aus der Datenbank stammen. Wenn Sie eine "PropertySource" erstellen, um die zu erhalten und auf die "Umgebung" anzuwenden, können Sie in der Anwendung darauf verweisen.
Versuchen Sie, eine Klasse zu erstellen, die beim Start den Einstellungswert aus der Datenbank abruft, zwischenspeichert und den Cache jederzeit aktualisiert (obwohl ich der Meinung bin, dass die Thread-Sicherheit verdächtig ist ...).
package com.example.demo;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class JdbcPropertySource extends EnumerablePropertySource<DataSource> implements InitializingBean {
private final JdbcTemplate jdbcTemplate;
private final String[] tableNames;
private Map<String, Object> properties = Collections.emptyMap();
public JdbcPropertySource(String name, DataSource dataSource, String... tableNames) {
super(name, dataSource);
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.tableNames = tableNames.length == 0 ? new String[]{"t_properties"} : tableNames;
}
@Override
public String[] getPropertyNames() {
return properties.keySet().toArray(new String[0]);
}
@Override
public Object getProperty(String name) {
Map<String, Object> currentProperties = properties;
return currentProperties.get(name);
}
@Override
public void afterPropertiesSet() {
load();
}
public void load() {
Map<String, Object> loadedProperties = Stream.of(tableNames)
.flatMap(tableName -> jdbcTemplate.queryForList("SELECT name, value FROM " + tableName).stream())
.collect(Collectors.toMap(e -> (String) e.get("name"), e -> e.get("value")));
this.properties = loadedProperties;
}
}
package com.example.actuatordemo;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
@Configuration
public class MyConfiguration {
//DataSource-Einstellungen
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("demo")
.addScript("classpath:init-db.sql")
.build();
}
//Diesmal wurde die Einstellung von JdbcPropertySource erstellt
@Bean
JdbcPropertySource jdbcPropertySource(DataSource dataSource) {
return new JdbcPropertySource("jdbcProperties", dataSource);
}
//Bean-Definition zum Anwenden der diesmal erstellten JdbcPropertySource auf Environment
@Bean
static BeanFactoryPostProcessor environmentPropertySourcesCustomizer() {
return bf -> {
ConfigurableEnvironment environment = bf.getBean(ConfigurableEnvironment.class);
JdbcPropertySource propertySource = bf.getBean(JdbcPropertySource.class);
//Anwendung gemäß der folgenden Priorität von Betriebssystemumgebungsvariablen (Priorität wird gemäß den Anforderungen bestimmt)
environment.getPropertySources()
.addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, propertySource);
};
}
//Bean-Definition zum Aktivieren von Eigenschaftsplatzhaltern
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Dieses Mal habe ich es mit dem Mechanismus von "BeanFactoryPostProcessor" auf "Umgebung" angewendet. Ist dies die beste Methode? Ist nicht sehr zuversichtlich. Ich würde mich freuen, wenn Sie kommentieren könnten, ob es einen besseren Weg gibt.
Da dieser Eintrag die eingebettete Datenbank verwendet, bereiten Sie die SQL für die Eingabe der Tabelle und der Daten vor.
src/main/resources/init-db.sql
drop table t_properties if exists;
create table t_properties (
name varchar(512) not null primary key,
value text
);
insert into t_properties (name, value) values ('services.user.url','http://dev01/services/user/{id}');
insert into t_properties (name, value) values ('services.company.url','http://dev01/services/company/{id}');
In dem Fall, an dem ich gerade arbeite (Nicht-Spring-Boot-Fall ...), müssen möglicherweise (möglicherweise) einige Einstellungswerte in der Datenbank vorhanden sein (aus Sicht des Systembetriebs). Was kann ich also technisch tun? Ich habe darüber nachgedacht und einen Prototyp gemacht. Es scheint Verbesserungspotenzial zu geben, beispielsweise die Gewährleistung der Thread-Sicherheit, aber ich bin erleichtert zu wissen, dass dies mithilfe der Erweiterungspunkte von Spring Framework realisiert werden kann.
Recommended Posts