写JavaFX时需要动态切换数据源,因此产生这个需求。
工具类,用于在代码中获取spring的上下文:
@Component
public class Spring implements ApplicationContextAware {
public static AnnotationConfigApplicationContext APP;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(Spring.APP == null) {
Spring.APP = (AnnotationConfigApplicationContext) applicationContext;
}
}
}
下面这个类展示如何实现代码方式注册Bean:
package com.abc.gen.service;
import com.abc.gen.util.Spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.sql.SQLRecoverableException;
/**
* create by: CaiBaoHong
* create date: 2018/2/2 0002
*/
@Component
public class DatabaseService {
private final Logger logger = LoggerFactory.getLogger(getClass());
private static final String JDBC_TEMPLATE_BEAN = "jdbcTemplate";
/**
* 每次调用此方法,都会新创建一个JdbcTemplate并注入到Spring上下文中
* @param host
* @param port
* @param username
* @param password
* @return
* @throws SQLException
*/
public JdbcTemplate newJdbcTemplate(String host, String port, String username, String password) throws SQLException {
//创建一个新的JdbcTemplate
DataSource dataSource = DataSourceBuilder.create()
.driverClassName("com.mysql.jdbc.Driver")
.url("jdbc:mysql://" + host + ":" + port + "?useUnicode=true&characterEncoding=utf-8&useSSL=false")
.username(username)
.password(password)
.build();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
//判断
if (Spring.APP.containsBeanDefinition(JDBC_TEMPLATE_BEAN)){
//如果Spring上下文已存在Bean,先删除
Spring.APP.removeBeanDefinition(JDBC_TEMPLATE_BEAN);
}else{
//如果不存在,创建
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JdbcTemplate.class);
Spring.APP.registerBeanDefinition(JDBC_TEMPLATE_BEAN,builder.getBeanDefinition());
}
//注入JdbcTemplate实例
Spring.APP.getBeanFactory().registerSingleton(JDBC_TEMPLATE_BEAN,jdbcTemplate);
//打印测试:
logger.info("set dataSource : "+dataSource);
logger.info("set jdbcTemplate : "+jdbcTemplate);
logger.info("set jdbcTemplate.dataSource : "+jdbcTemplate.getDataSource());
return jdbcTemplate;
}
}
调用DatabaseService的类中可以拿到动态注入的JdbcTemplate:
@Component
public class RootLayoutController {
@Autowired
private DatabaseService databaseService;
@Lazy
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 用户点击“连接”
* @throws SQLException
*/
@FXML
private void handleConfirmConnection() throws SQLException {
String host = hostField.getText();
String port = portField.getText();
String username = usernameField.getText();
String password = passwordField.getText();
//检查连接参数
String connParamsError = checkService.checkConnectionParams(host, port, username, password);
if (connParamsError!=null){
alertService.error(connParamsError);
return ;
}
//初始化Datasource和JdbcTemplate
databaseService.newJdbcTemplate(host, port, username, password);
//尝试连接
try {
jdbcTemplate.getDataSource().getConnection();
} catch (SQLException e) {
alertService.error("连接失败:"+e.getMessage());
return;
}
alertService.info("连接成功!");
}
@FXML
private void handleTest(){
System.out.println("jdbcTemplate : "+jdbcTemplate);
}
}