Spring boot - Maven - build, deploy - run with dynamic classpath
Hi anh em,
Bữa trước có bài hướng dẫn xây dựng Web service với Spring boot:
Hi all, Hôm nay rãnh rỗi, làm cái tutorial tạo web API bằng Spring boot hướng dẫn anh em. Trước hết, mình dùng maven để built project nên ai thiếu maven thì cài vào, maven - eclipse trong dạy nhau học đã có topic hướng dẫn anh em tìm setup xem nhé. Mình dùng eclipse và Ubuntu nhưng nó cũng tương tự với window,nên không vấn đề gi. Đầu tiên, tạo maven project, nếu bạn không có plugin maven hoặc muốn dùng command line thì gõ lệnh như sau: mvn archetype:generate -DgroupId=com.canh -DartifactI…
Hôm nay, mình hướng dân tiếp với phần build deploy và run trên máy khác (ở đây mình dùng ubuntu)
Giả sử sau khi xây dựng xong, ta muốn đóng gói web service với cấu trúc thư mục bên dưới
classes --chua file Jar chính mà ta đã implement
lib -- các thư viện mà app dùng (được khai báo trong pom.xml)
logs -- log khi start server
pid -- chứa java proccess khi start server
properties -- config file
scripts -- shell script dùng để start/stop server
Cấu trúc project hiện tại
├── pom.xml
└── src
├── main
│ ├── assembly
│ │ └── assembly.xml
│ ├── java
│ │ └── com
│ │ └── canh
│ │ ├── App.java
│ │ ├── config
│ │ │ └── WebConfig.java
│ │ ├── dto
│ │ │ └── UserDto.java
│ │ ├── services
│ │ │ ├── ExampleServicesImpl.java
│ │ │ └── ExampleServices.java
│ │ └── web
│ │ └── api
│ │ └── ExampleController.java
│ ├── resources
│ │ └── application.properties
│ └── script
│ ├── startServer.sh
│ ├── startServer.sh~
│ ├── stopServer.sh
│ └── stopServer.sh~
└── test
└── java
└── com
└── canh
└── AppTest.java
Để build ra cấu trúc thư mục ở trên, ta chỉ cần config ở 2 file : pom.xml và assembly.xml
assembly.xml:
<assembly>
<id>run_dir</id>
<includeBaseDirectory>false</includeBaseDirectory>
<!-- Specifies that our binary distribution is a zip package -->
<formats>
<format>tar.gz</format>
</formats>
<!-- Adds the dependencies of our application to the lib directory -->
<dependencySets>
<dependencySet>
<!-- Project artifact is not copied under library directory since it is
added to the root directory of the zip package. -->
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
<fileSets>
<!-- Adds startup scripts to the root directory of zip package. The startup
scripts are copied from the src/main/scripts directory. -->
<fileSet>
<directory>src/main/script</directory>
<outputDirectory>script</outputDirectory>
<includes>
<include>*.*</include>
</includes>
<fileMode>0777</fileMode>
</fileSet>
<!-- Adds the jar file of our example application to the root directory
of the created zip package. -->
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>classes</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>./</directory>
<outputDirectory>logs</outputDirectory>
<excludes>
<exclude>*/**</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>properties</outputDirectory>
<includes>
<include>*.*</include>
</includes>
</fileSet>
<fileSet>
<directory>./</directory>
<outputDirectory>pid</outputDirectory>
<excludes>
<exclude>*/**</exclude>
</excludes>
</fileSet>
</fileSets>
</assembly>
trong đó :
<formats>
<format>tar.gz</format>
</formats>
là type nén: ở đây mình dùng tar.gz , nếu muốn là zip file thì sửa lai là zip.
<dependencySets>
<dependencySet>
<!-- Project artifact is not copied under library directory since it is
added to the root directory of the zip package. -->
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
dùng để copy tất cả các gói jar dependency (khái báo trong pom file) vào thư mục lib
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>classes</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</fileSet>
dùng để copy file jar mà ta đã implement vào trong thư mục classes, tương tự như vậy đối với các thư mục log, pid, properties.
Tiêp theo là config trong file pom.xml
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</configuration>
<executions>
<execution>
<id>create-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
trong tag build thêm plugin maven-assembly-plugin và trỏ đến đướng dẫn file assembly.xml mà bạn đã cần config. vậy là xong, khi dùng lệnh :
mvn clean install
project của ta sẽ được đóng gói trong tar.gz với cấu trúc thư mục đã định nghĩa.
JavaSpring-1.0-SNAPSHOT-run_dir.tar.gz
giờ thêm phần config clashpath là bạn sẽ có 1 standalone application để có thể chạy trên máy khác.
do máy mình dùng là unbuntu, nên mình viết trên shell script đễ config classpath, bạn nào dùng win thì tìm hiểu bat và vbs để viết script nhé.
mình viết 2 script: startServer.sh: vừa config classpath và start server, và stopServer.sh.
startServer.sh:
CLASSPATH=
for file in `ls ../lib/*.jar`
do
CLASSPATH=${CLASSPATH}:${file}
done
for f in `ls ../classes/*.jar`
do
CLASSPATH=${CLASSPATH}:${f}
done
echo $CLASSPATH
java -cp ":${CLASSPATH}"
com.canh.App --spring.config.location=../properties/application.properties > ../logs/server.log & echo "$!" > ../pid/myjavaprogram.pid
i=0
while [ $i -lt 5 ]
do
if grep -q "Started App" ../logs/server.log;
then
echo "Started app"
echo "process id:$!"
break
else
echo "waiting..."
fi
sleep 5
done
Trong java classpath được dùng để liệt kê các gói jar/thư viện để JRE tìm kiếm classes file trong đó.
đoạn script trên dùng để lấy đường dẫn file jar trong thư mục classes và lib vào 1 string, và khi run với lệnh :
java -cp ":${CLASSPATH}"
com.canh.App --spring.config.location=../properties/application.properties > ../logs/server.log & echo "$!" > ../pid/myjavaprogram.pid
JRE sẽ biết được các thư viện được đặt ở đây và tìm chính xác.
--spring.config.location=../properties/application.properties
khi chạy trên máy khác, có thể cần config lại port, hay thông số gì đó, ta chỉ cần chỉnh trong file này để server nhận biết.
stoppServer.sh: đơn giản là kill proccess đang chạy thôi.
#!/bin/sh
kill -9 `cat ../pid/myjavaprogram.pid`
vây là xong, giờ chỉ cần đến thư mục script run file startServer.sh
sh startServer.sh
chú ý là cần phải có set JAVA_HOME và PATH đến thư mục cài đặt java nhé.
trên unbutu có thể cài đặt cho user đang dùng như sau:
cd ~/
ls -a
lúc này sẽ thấy file .profile
thêm như bên dưới
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
export PATH=$JAVA_HOME/bin:$PATH
load lại profile:
. .profile
vậy là xong. có thể run được rồi, kết qua giông như bên dưới
github: https://github.com/nguyenhuuca/JavaSpringBootExample
Chúc anh em cuối tuần vui