[英]Changing the value of an @Bean at runtime in Java Spring Boot
In Java
with Spring Boot
framework there is an @Bean
named DataSource
that is used to make connections to a database, and is used by another @Bean
called JdbcTemplate
that serves to perform actions on the database. 在带有
Spring Boot
框架的Java
,有一个名为DataSource
的@Bean
用于建立与数据库的连接,并由另一个名为JdbcTemplate
@Bean
使用,用于对数据库执行操作。 But, there is a problem, this @Bean
DataSource
, which serves to make the connection to the database, requires the properties for the connection to be preconfigured (url, username and password). 但是,有一个问题,这个用于建立与数据库连接的
@Bean
DataSource
需要预先配置连接属性(url,用户名和密码)。 The @Bean
DataSource
needs to start with an "empty" or "default" value at project startup, and at runtime it changes this value. @Bean
DataSource
需要在项目启动时以“空”或“默认”值开始,并且在运行时它会更改此值。 I want a certain Endpoint to execute the action of changing the value of @Bean
, to be more exact. 我希望某个端点执行更改
@Bean
值的@Bean
,更确切地说。 And with the change of the value of the @Bean
DataSource
the JdbcTemplate
, consequently, will be able to perform actions in several database. 因此,随着
@Bean
DataSource
值的更改, JdbcTemplate
将能够在多个数据库中执行操作。
Some details: 一些细节:
@Bean
DataSource
at runtime, maybe just override the @Bean
values that the Spring Boot itself already creates automatically. @Bean
DataSource
,也许只是覆盖Spring Boot本身已经自动创建的@Bean
值。 @Bean
DataSource
start with an "empty" value by making a method with the @Bean
annotation and that returns a DataSource
object that is literally this code: DataSourceBuilder.build().create();
@Bean
DataSource
通过与方法用一个“空”值开始@Bean
注释和返回一个DataSource
对象,它是从字面上此代码: DataSourceBuilder.build().create();
. DataSource
@Bean
code: DataSource
@Bean
代码:
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
Main class: 主要课程:
@SpringBootApplication(scanBasePackages = "br.com.b2code")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RunAdm extends SpringBootServletInitializer implements
CommandLineRunner {
public static final String URL_FRONTEND = "*";
/**
* Método main do módulo de Gestão.
*
* @param args argumentos de inicialização
* @throws Exception uma exception genérica
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(RunAdm.class, args);
}
@Override
protected SpringApplicationBuilder
configure(SpringApplicationBuilder application) {
return application.sources(RunAdm.class);
}
@Override
public void run(String... args) throws Exception {
}
}
A class to exemplify how I use JdbcTemplate
: 一个类来举例说明我如何使用
JdbcTemplate
:
@Repository
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ClienteQueryRepositoryImpl implements ClienteQueryRepository {
private final @NonNull
JdbcTemplate jdbc;
@Override
public List<Cliente> findAll() {
return jdbc.query(ClienteQuerySQL.SELECT_ALL_CLIENTE_SQL, new ClienteRowMapper());
}
}
I think as a general approach you might consider a Proxy Design Pattern for the actual DataSource Implementation. 我认为作为一种通用方法,您可以考虑实际数据源实现的代理设计模式。
Let's suppose the DataSource
is an interface that has getConnection
method by user and password (other methods are not really important because this answer is theoretical): 假设
DataSource
是一个具有用户和密码的getConnection
方法的接口(其他方法并不重要,因为这个答案是理论上的):
interface DataSource {
Connection getConnection(String user, String password);
}
Now, in order to maintain many databases you might want to provide an implementation of the datasource which will act as a proxy for other datasources that will be created on the fly (upon the endpoint call as you say). 现在,为了维护许多数据库,您可能希望提供数据源的实现,该实现将充当将动态创建的其他数据源的代理(如您所说,在端点调用时)。
Here is an example: 这是一个例子:
public class MultiDBDatasource implements DataSource {
private DataSourcesRegistry registry;
public Connection getConnection(String user, String password) {
UserAndPassword userAndPassword = new UserAndPassword(user, password);
registry.get(userAndPassword);
}
}
@Component
class DataSourcesRegistry {
private Map<UserAndPassword, DataSource> map = ...
public DataSource get(UserAndPassword a) {
map.get(a);
}
public void addDataSource(UserAndPassword cred, DataSource ds) {
// add to Map
map.put(...)
}
}
@Controller
class InvocationEndPoint {
// injected by spring
private DataSourcesRegistry registry;
@PostMapping ...
public void addNewDB(params) {
DataSource ds = createDS(params); // not spring based
UserAndPassword cred = createCred(params);
registry.addDataSource(cred, ds);
}
}
A couple of notes: 几个笔记:
You should "override" the bean of DataSource offered by spring - this can be done by defining your own bean with the same name in your own configuration that will take precedence over spring's definition. 你应该“覆盖”spring提供的DataSource bean - 这可以通过在你自己的配置中定义你自己的bean来完成,这个bean将优先于spring的定义。
Spring won't create Dynamic Data Source, they'll be created from the "invocation point" (controller in this case for brevity, in real life probably some service). Spring不会创建动态数据源,它们将从“调用点”创建(控制器在这种情况下为了简洁,在现实生活中可能是一些服务)。 in any case only Registry will be managed by spring, not the data sources.
在任何情况下,只有注册表将由spring管理,而不是数据源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.