Java Tips
JUL
现在大家大多都是用SLF4J,但其实JUL也很不错,最明显的好处就是你不用引用额外的包。
这里列出相关的配置
package org.yx.base;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.LogManager;
public class Config {
private static final String PROPERTY_FILE = "/properties/log.properties";
public void configLog() throws IOException {
LogManager manager = LogManager.getLogManager();
try (InputStream inputStream = this.getClass().getResourceAsStream(PROPERTY_FILE)) {
manager.readConfiguration(inputStream);
}
}
}
作为替代, 你也可以不用上面的Config类,你可以采用-Djava.util.logging.config.file=XXX 作为JVM的启动参数,但这种方式你就不能把properties文件打包到jar里了。 参考 Overview和LogManager
log.properties
-Your Project
-src
-main
+java
-resources
-properties
+log.properties
# 输出到文件和控制台
handlers=java.util.logging.FileHandler,java.util.logging.ConsoleHandler
# root日志输出级别 level
.level=ALL
# 控制台输出级别和格式
java.util.logging.ConsoleHandler.level=DEBUG
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
# 文件输出级别和地址
java.util.logging.FileHandler.level=INFO
java.util.logging.FileHandler.pattern=./server.log
#限制文件的大小(50000字节)
java.util.logging.FileHandler.limit=50000
#过滤,总共保存1个文件,接着猜覆盖
java.util.logging.FileHandler.count=1
#XMLFormatter是以xml样式输出,SimpleFormatter是以普通样式输出
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
#指定是否应该将 FileHandler 追加到任何现有文件上(false会覆盖,但默认为false)。
java.util.logging.FileHandler.append=true
使用
private static final Logger LOG = Logger.getLogger("");
public static void main(String[] args) throws IOException {
Config config = new Config();
config.configLog();//Config only once.
LOG.info("texting logging");
}
SLF4J
依赖
plugins {
id 'java'
}
group 'org.yx'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
// https://mvnrepository.com/artifact/org.postgresql/postgresql
implementation group: 'org.postgresql', name: 'postgresql', version: '42.3.1'
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.0-alpha5'
// https://mvnrepository.com/artifact/ch.qos.logback/logback-classic
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.3.0-alpha12'
}
jar {
manifest {
attributes["Main-Class"] = "org.yx.Main"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
logback.xml (放在resources目录下)
<configuration packagingData="true">
<shutdownHook/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{"yyyy-MM-dd'T'HH:mm:ss,SSSXXX"} [%thread] %p %c{1} [%t] %m%n</pattern>
</encoder>
</appender>
<appender name="AsyncLogFile" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="LogFile"/>
</appender>
<appender name="LogFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./server.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./server-%d{yyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{"yyyy-MM-dd'T'HH:mm:ss,SSSXXX"} [%thread] %p %c{1} [%t] %m%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="AsyncLogFile"/>
</root>
</configuration>
其中 packagingData="true"会把异常stacktrace 中 源文件所在包打印出来 参考
DataSource
通常使用数据库要获得Connection, 如果你不使用JPA,你可以用一下方式获得DataSource/Connection
//Postgresql
PGPoolingDataSource source = new PGPoolingDataSource();
source.setDataSourceName("A Data Source");
source.setServerName("127.0.0.1");
source.setDatabaseName("text");
source.setUser("user");
source.setPassword("pwd");
source.setMaxConnections(2);
source.getConnection();
//SAP hana
DataSourceSAP ds = new DataSourceSAP();
ds.setUrl("jdbc:sap://127.0.0.1:30010?reconnect=true");
ds.setUser("user");
ds.setPassword("pwd");
有时你可能希望运行一个sql文件的批处理,但注意,你只能一句一句的添加到Statement.addBatch,每一句都要是合法的SQL语句,而不能添加包含;分隔的一个sql文件的整个内容
package org.yx.base;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLBatch {
private static final Logger LOGGER = LoggerFactory.getLogger(SQLBatch.class);
private String sql;
public SQLBatch(String fileName) throws IOException {
sql = FileUtils.readFileToString(new File(fileName), StandardCharsets.UTF_8);
preProcessSql();
}
public SQLBatch(InputStream in) throws IOException {
sql = IOUtils.toString(in, StandardCharsets.UTF_8);
preProcessSql();
}
private void preProcessSql() {
sql = sql.replaceAll("\r", "");
sql = sql.replaceAll("\n", "");
}
public void exec() throws SQLException {
try (Connection con = DBConfig.getInstance().getConnection()) {
con.setAutoCommit(false);
try (Statement stmt = con.createStatement()) {
for (String one : sql.split(";")) {
stmt.addBatch(one);
}
stmt.executeBatch();
} catch (SQLException e) {
con.rollback();
LOGGER.error(e.getMessage(), e);
}
con.commit();
}
}
}
快速搭建微服务
下面利用Consul和Spring快速搭建一个微服务框架
安装好Consul后
启动Consul后访问 http://localhost:8500
consul agent -dev -data-dir=tmp
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.5'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
group 'org.example'
version '1.0'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2021.0.5")
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation(group: 'org.springframework.boot', name: 'spring-boot-starter-web')
//implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.9'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
Main.java
package org.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RestController
public class Main {
static Logger LOG = LoggerFactory.getLogger(Main.class);
private final RestTemplate restTemplate = new RestTemplate();
@Autowired
private DiscoveryClient discoveryClient;
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
@RequestMapping("/test")
public String home() {
return "Hello World!";
}
@RequestMapping("/remote")
public String remote() {
var list = discoveryClient.getInstances("myApp");
if (!CollectionUtils.isEmpty(list)) {
var str = list.get(0).getUri().toString();
LOG.info(str);
var ret = restTemplate.getForObject(str + "/test", String.class);
LOG.info("rest call [{}] return: [{}]", str, ret);
return ret;
}
return null;
}
}
application.yml
spring:
cloud:
service-registry:
auto-registration:
enabled: true
consul:
host: localhost
port: 8500
discovery:
healthCheckPath: /actuator/health
healthCheckInterval: 5s
application:
name: myApp-1
build另一个jar包之前把application.name改为myApp
java -Dserver.port=8889 -jar build/libs/test-Consul-1.0.jar
java -Dserver.port=8888 -jar build/libs/test-Consul-1.0.jar
然后访问http://localhost:8889/remote即可
Log如下
2022-11-23 13:46:15.606 INFO 364639 --- [nio-8889-exec-3] org.example.Main : http://192.168.75.128:8888
2022-11-23 13:46:15.655 INFO 364639 --- [nio-8889-exec-3] org.example.Main : rest call [http://192.168.75.128:8888] return: [Hello World!]

浙公网安备 33010602011771号