关于自定义程序打包成jar包,并读取配置
前言
在实际开发过程中,我们有时候有把你编写的一段程序打成jar包的需求,而一些配置是需要去配置文件里面读取关于这项目的一些配置,本人在网络上查询了众多的资料,总的来说可以归为3类
1.从数据库读取配置
老生常谈,在dao层从数据库获取配置信息,然后返回到Service层进行业务逻辑处理
2.在每次调用这个jar的时候通过关键字去读取配置
在这一类中,方法有很多,不过大体都是
InputStream ins = getClass().getResourceAsStream("/resource/dbconfig.properties");
通过IO流对配置文件进行读取,然后再从 InputStream 流中读取数据,没什么技术含量,便不多讲
例如以下例子,就是通过Properties流来读取配置
/**
* 读取配置文件属性
* @param path 配置文件路径
* @return
* @throws IOException
*/
public Map readerConfigurationFile(String path) throws IOException {
/**
* 使用Properties读取配置文件并获取配置信息
*/
Properties properties = new Properties();
InputStream input = new BufferedInputStream(new FileInputStream(path));
properties.load(input);
/**
* 将获取到的配置信息转存到map集合
*/
Map map = new HashMap();
for (Object key : properties.keySet()) {
if (properties.get(key) != null && !properties.get(key).toString().trim().equals("")){
map.put(key,properties.get(key));
}
}
return map;
}
3.通过Spring 自动装配,在项目启动时就把配置信息发送到jar包里面(强烈推荐)
这个方法虽然前期建立的时候比较繁琐,但是完成之后简直方便到飞起
首先,建立一下格式的结构,方便我们后面能够快捷找到要编写的文件
实际上DemoApplication.java 是可以去掉的,只是个人为了方便测试写的代码,看是否有bug就留下来启动项目用的
最最最重要的pom.xml文件应该这样写:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-->--------------------这里是自己jar的情况,自己编写--------- -------<-->
<modelVersion>4.0.0</modelVersion> <groupId>com.transfer</groupId> <artifactId>DataTransferService</artifactId> <version>0.0.1-SNAPSHOT</version> <name>DataTransferService</name> <description>DataTransferService</description> <properties> <spring-boot.version>2.6.13</spring-boot.version> </properties>
<!-->---------------------------------------------------------------<-->
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- 自动配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <!-- 配置属性 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional><!-- 依赖不传递 --> </dependency> <!--Lombok依赖--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!--mysql数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> <scope>runtime</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> </project>
在config包里面,我们要建立几个配置文件:
UserConfiguration.java
@Slf4j @Configuration @ConditionalOnExpression("${enabled:true}") @EnableConfigurationProperties(UserConfiguration .class) public class UserConfiguration { @Bean @Primary public UserConfig getConfigValue(UserProperties properties){ if (properties.getLog()){ log.info("数据库中转服务API组件 ——> 开启组件"); } return new UserConfig() .setOtherDataSourcesMap(properties.getOtherDataSourcesMap()) .setLog(properties.getLog()); } }
UserConfig.java
@Data @Accessors(chain = true) public class UserConfig implements Serializable { private Map<String,Map<String,Map<String,Object>>> otherDataSourcesMap; /** 是否打印操作日志 */ private Boolean log = true; }
UserProperties.java
@Data @ConfigurationProperties(prefix = "User") public class UserProperties implements Serializable { private Map<String,Map<String,Map<String,Object>>> otherDataSourcesMap; /** 是否开启 */ boolean enabled = true; /** 是否打印操作日志 */ private Boolean log = false; }
请注意:这里的@ConfigurationProperties 注解里面的 prefix 参数指的是在配置文件中你自己定义的标识符
UserBeanInject.java
public class UserBeanInject { /** * 注入配置Bean * * @param config 配置对象 */ @Autowired(required = false) public void setConfig(UserConfig config){ UserSpi.setConfig(config); } }
当然,还有重要的一步,那就是在resources文件夹下创建一个Spring自动装配的约定文件,使得我们这几个java配置文件能够生效
spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
自己定义的包路径.configuration.UserConfiguration, \
自己定义的包路径.configuration.UserBeanInject
然后,我们要暴露这个接口
UserSpi.Java
@Slf4j
public class UserSpi{
public volatile static UserConfig config;
public static void setConfig(UserConfig config){
UserSpi.config = config;
if (config.getLog()){
log.info("数据库中转服务API组件 ——> 打印配置信息\n", JSONUtil.toJsonStr(UserSpi.config));
}
}
// =================== 获取Api 相关 ===================
public static IUserService api = new UserServiceImpl();
}
这样基本上完成jar自动装配外部配置文件的配置,业务逻辑什么的看个人习惯自己去编写
感言
- 从数据库里面读取配置信息方便时挺方便的,但是在高并发与高请求的项目中并不适用,而每次调用这个jar的时候通过关键字去读取配置会造成内存资源不断被刷新,容易内存爆炸,个人推荐第3种方式。
- 还有,每次该改写完代码,一定要重新构建项目,重新编译一下,不然你打出来的Jar包,永远都是你改写之前的代码,改写之后的代码不会写入到Jar包里面!!!!
- 对了,直接把配置文件里面的值直接传递到jar包里面也是一种方法,但是要是被半路拦截,岂不是直接泄露数据,故不提倡,还有一点,就是代码的可维护性会变得很低