springboot高级特性之修改配置文件

应用场景:

想动态调整Spirngboot的yml配置文件内容。比如数据库链接信息,或者说mq链接信息、监听队列的调整。

本人这里以rabbitmq消息队列为例,@RabbitListener(queues = "xxx") 监听者的这个队列名,每次在修改消息队列名称时都要手动调整yml然后重启项目,为了解决这个问题看了两天的源码才知道可以这样调整。

1、将mq的所有信息都保存在数据库里,项目初始化的时候从数据库读取。在Springboot中,需要通过ApplicationListener 接口来获取配置信息,onApplicationEvent这个方法执行的时候所有信息都是空的,所以需要在此方法里进行数据库连接。

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;

import javax.annotation.PostConstruct;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Map;
import java.util.Properties;

@Configuration
public class RabbitMqConfig  implements ApplicationListener {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    private String host;
    private String port;
    private String username;
    private String password;

    @PostConstruct
    public void init() {
        SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession();
        YumingMapper mapper = sqlSession.getMapper(YumingMapper.class);
        Map config = mapper.queryRabbitMqConfigInfo();
        host = config.get("host");
        port = config.get("port");
        username = config.get("username");
        password = config.get("password");
	}


	@Bean
    public ConnectionFactory connectionFactory() {
    	// 重置yml 里的配置文件
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(host);
        connectionFactory.setPort(Integer.parseInt(port));
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        return connectionFactory;
    }


	@Override
	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {

		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		// 获取spring Environment
		MutablePropertySources propertySources = event.getEnvironment().getPropertySources();
		// 配置放在了application-pro或者是application-dev 中 赋值复制需要在其中赋值
		for (PropertySource propertySource : propertySources) {
			boolean applicationConfig = propertySource.getName().contains("application");
			if (!applicationConfig) {
				continue;
			}
			// 获取上文的application集合中获取数据库连接
			Map dataBaseSource =
					(Map)propertySource.getSource();
//			String driverClass = String.valueOf(dataBaseSource.get("spring.datasource.driver-class-name").getValue());
			String url = String.valueOf(dataBaseSource.get("spring.datasource.url").getValue());
			String user = String.valueOf(dataBaseSource.get("spring.datasource.username").getValue());
			String password = String.valueOf(dataBaseSource.get("spring.datasource.password").getValue());
			// 因为在spring初始化之前 所有不能使用注解 所以需要jdbc直接连接数据库 首先建立驱动
			try {
				Class.forName("com.mysql.cj.jdbc.Driver");
				conn = DriverManager.getConnection(url, user, password);
				// 1、获取连接对象
				// 2、创建statement类对象,用来执行SQL语句!!
				st = conn.createStatement();
				// 3、创建sql查询语句
				String sql = "select * from jl_config";
				// 4、执行sql语句并且换回一个查询的结果集
				rs = st.executeQuery(sql);
				while (rs.next()) {
					// 获取数据库中的数据
					String jlappid = rs.getString("jlappid");
					int jlstore_id = rs.getInt("jlstore_id");

					String goodsQueneName = "goods_list_" + jlappid;
					String orderQueneName = "xxxie_store_gongban" + jlstore_id;
					String orderRoutingKey = "order_" + jlstore_id;

					ConfigurableEnvironment environment = event.getEnvironment();
					Properties props = new Properties();
					props.put("mq.goods.queneName", goodsQueneName);
					props.put("mq.order.queneName", orderQueneName);
					props.put("mq.order.routingKey", orderRoutingKey);
					environment.getPropertySources().addFirst(new PropertiesPropertySource("decrypted_properties", props));
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}
}

2、新建resources/META_INF/下新建spring.factories文件,输入以下内容.就是类路径。

org.springframework.context.ApplicationListener = xxxx.RabbitMqConfig

3、重启项目就能达到通过数据获取覆盖Springbootymp配置文件的覆盖操作。

你可能感兴趣的:(spring,boot,rabbitmq,后端)