0808 ~ 0814
# 0808 ~ 0814
# 0808 - Procedure์ Function ์ฐจ์ด
# [ Procedure ํ๋ก์์ ๋? ]
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ผ๋ จ์ ์์ ์ ์ ๋ฆฌํ ์ ์ฐจ๋ฅผ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ฆฌ ์์คํ ์ ์ ์ฅํ ๊ฒ์ผ๋ก ์๊ตฌ์ ์ฅ๋ชจ๋(Persistent Storage Module)์ด๋ผ๊ณ ๋ถ๋ฆฐ๋ค.
์ผ๋ จ์ ์ฟผ๋ฆฌ๋ฅผ ๋ง์น ํ๋์ ํจ์์ฒ๋ผ ์คํํ๊ธฐ ์ํ ์ฟผ๋ฆฌ์ ์งํฉ์ด๋ค.
์ฆ, ํ๋์ ์์ ์ ์ํํ๊ธฐ ์ํ ์ฟผ๋ฆฌ์ ๋ชจ์์ด๋ค.
CALL ํ๋ก์์ ๋ช
(INํ๋ผ๋ฏธํฐ๋ช
, @OUTํ๋ผ๋ฏธํฐ๋ช
)
EXECUTE ํ๋ก์์ ๋ช
(INํ๋ผ๋ฏธํฐ๋ช
, @OUTํ๋ผ๋ฏธํฐ๋ช
)
---
CREATE OR REPLACE PROCEDURE ํ๋ก์์ ธ์ด๋ฆ (ํ๋ผ๋ฏธํฐ1,ํ๋ผ๋ฏธํฐ2...);
IS
๋ณ์
BEGIN
์ฟผ๋ฆฌ๋ฌธ
END ํ๋ก์์ ธ ์ด๋ฆ;
---
CREATE OR REPLACE PROCEDURE GET_TIER(in_name IN VARCHAR2,out_tier OUT VARCHAR2)
IS
BEGIN
SELECT TIER INTO out_tier FROM SUMMONER_TB WHERE NAME = in_name;
EXCEPTION
--์ํ์ฌ๋ฅผ ์ฐพ์ ์ ์์ ๋
WEHN NO_DATA_FOUND THEN
out_tier:='NO_SUMMONER_FOUND';
END GET_TIER;
# [ Function ํจ์๋? ]
ํ๋์ ํน๋ณํ ๋ชฉ์ ์ ์์ ์ ์ํํ๊ธฐ ์ํด ๋ ๋ฆฝ์ ์ผ๋ก ์ค๊ณ๋ ์ฝ๋์ ์งํฉ.
์ฆ, ํจ์๊ฐ ์ฌ๋ฌ ์์ ์ ์ํ ๊ธฐ๋ฅ์ด๋ผ๋ฉด ํ๋ก์์ ๋ ์์ ์ ์ ๋ฆฌํ ์ ์ฐจ์ด๋ค.
๋ณดํต ๋ก์ง์ ๋์์ฃผ๋ ์ญํ ์ด๋ฉฐ, ๊ฐ๋จํ ๊ณ์ฐ, ์์น ๋ฑ์ ๋ํ๋ผ ๋ ์ฌ์ฉํ๋ค.
SELECT ํจ์๋ช
(IN ํ๋ผ๋ฏธํฐ๋ช
) FROM DUAL;
---
CREATE OR REPLACE FUNCTION ํจ์์ด๋ฆ(ํ๋ผ๋ฏธํฐ1์ด๋ฆ ํ์
, ํ๋ผ๋ฏธํฐ2์ด๋ฆ ํ์
...)
RETURN ๋ฐํํ ํ์
IS
๋ณ์ ์ ์ธ
BEGIN
์คํ๋ฌธ ์์ฑ
RETURN ๋ฐํํ ๊ฐ
END;
---
CREATE OR REPLACE FUNCTION SUM_TWICE(n1 NUMBER, n2 NUMBER)
RETURN NUMBER
IS
twice_sum NUMBER := 0;
BEGIN
twice_sum := (n1 + n2)*2;
RETURN twice_sum;
END;
# [ ํจ์์ ํ๋ก์์ ์ ์ฐจ์ด ]
ํ๋ก์์ ๋ํ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ ์ฌ๋ฌ ์์ ์ ์ํํ์ฌ ๊ฐ์ ๋ฐํํ ์ ์๊ณ , ํจ์ ๋ํ ๋งค๊ฒจ๋ณ์๋ฅผ ๋ฐ์ ์ฌ๋ฌ ์์ ์ ์ํํ์ฌ ๊ฐ์ ๋ฐํํ ์ ์๋ค.
# ๋งค๊ฐ๋ณ์
- ํ๋ก์์ ๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๋ ฅ, ์ถ๋ ฅ, ์ ์ถ๋ ฅ ํ์์ผ๋ก ๋ฐ์ ์ ์๋ค.
- ํจ์๋ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๋ ฅ ํ์์ผ๋ก๋ง ๋ฐ์ ์ ์๋ค.
# ๋ฐํ๊ฐ
- ํ๋ก์์ ๋ ๋ฐํ๊ฐ์ ๊ฐ์ง ์ ๋ ์๊ณ ๊ฐ์ง์ง ์์ ์๋ ์๋ค.
- ํจ์๋ ๋ฐํ๊ฐ์ ๋ฐ๋์ ๊ฐ์ ธ์ผ ํ๋ค.
# ์ฟผ๋ฆฌ๋ฌธ ๋ด์์ ์คํ๊ฐ๋ฅ
- ํ๋ก์์ ๋ SELECT, WHERE ๋ฌธ๋ฑ์์ ์ฌ์ฉ ๋ถ๊ฐํ๋ค.
- ํจ์๋ SELECT, WHERE ๋ฌธ ๋ฑ์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
# ์ฒ๋ฆฌ ์ฅ์
- ํ๋ก์์ ๋ ํด๋ผ์ด์ธํธ(ํ๋ฉด)์์ ๊ฐ์ ๊ฑด๋ค๋ฐ์ ์๋ฒ์์ ์์ ์ ํ ๋ค ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌํ๋ค. ์ฆ, ์๋ฒ์์ ์คํ์ด ๋์ด ์๋๋ฉด์์ ๋น ๋ฅธ ์ฑ๋ฅ์ ๋ณด์ฌ์ค๋ค.
- ํจ์๋ ํด๋ผ์ด์ธํธ(ํ๋ฉด)์์ ์คํ์ด ๋์ด ํ๋ก์์ ๋ณด๋ค ์๋๊ฐ ๋๋ฆฌ๋ค.
# 0809 - Feign Client
ํ์ธ์ ๋ทํ๋ฆญ์ค์์ ๊ฐ๋ฐํ ์น ์๋น์ค ํด๋ผ์ด์ธํธ ๋๊ตฌ(Http Client ๋ชจ๋)๋ก ์ ๋ ธํ ์ด์ ์ ํ ํ๋ฆฟํ๋ ์์ฒญ์ผ๋ก ์ฒ๋ฆฌํด ๋์ํ๋ HTTP ํด๋ผ์ด์ธํธ ๋ฐ์ธ๋๋ค. ๊ธฐ์กด HTTP client ์์ฑ์ ์ฝ๊ฒ ๋ง๋ค์ด์ฃผ๋ฉฐ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค๊ณ ์ ๋ ธํ ์ด์ ์ ๋ถ์ด๋ ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์ ์๋ ์ฅ์ ์ด ์๋ค.
# Feign ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
# [ ์์กด์ฑ์ฃผ์ ]
- maven
<properties>
<spring.cloud-version>Hoxton.SR8</spring.cloud-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- gradle
buildscript {
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:1.0.10.RELEASE"
}
}
ext {
set('springCloudVersion', "Hoxton.SR8")
}
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
# [ Application ]
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@EnableFeignClients ์ด๋ ธํ ์ด์ ์ด ์ง์ ๋ package๋ค์ ๋์๋ค๋๋ฉด์ @FeignClient ์ด๋ ธํ ์ด์ ์ ์ฐพ์ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ค์ด ์ค๋ค.
# [ Interface ์์ฑ ]
@FeignClient(name = "stores", configuration = FooConfiguration.class, url = "${feign.url}")
public interface StoreClient {
@RequestMapping(method = RequestMethod.GET, value = "/stores")
List<Store> getStores();
@RequestMapping(method = RequestMethod.GET, value = "/stores")
Page<Store> getStores(Pageable pageable);
@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
Store update(@PathVariable("storeId") Long storeId, Store store);
}
- @FeignClent ์ด๋ ธํ ์ด์ ์ ํตํด feign์ ์ฌ์ฉํ๋ ์ธํฐํ์ด์ค๋ผ๊ณ ์๋ฆฐ๋ค.
- configuration ์ต์ ์ ํตํด default ๊ฐ์ override ํ ์ ์๋ค.
- url ์ต์ ์ ํตํด ๋ถ๋ฌ์ฌ url์ ์ธํ ํ๋ค.
# [ Service ์์ฑ ]
@Service
public class StoreService {
private final StoreClient storeClient;
public StoreService(StoreClient storeClient) {
this.storeClient = storeClient;
}
public List<Store> getStores() {
return storeClient.getStores();
}
}
- getStores()๋ฅผ ํธ์ถํ์ฌ FeignClient๋ฅผ ํธ์ถํ๋ค.
# 0811 - jenkins pipeline
์นํ ์์ด ๊ธฐ๋ณธ์ ์ด pipeline์ผ๋ก ํด๋ก , ๋น๋, ๋ฐฐํฌ๊น์ง๋ง ์งํํ๋ ๋ฐฉ๋ฒ
# [ Credentials ์ธํ ]
- Jenkins ๊ด๋ฆฌ -> Manage Credentials -> Add Credentials
- Jenkins ๊ด๋ฆฌ -> ์์คํ ์ค์ -> GitHub -> ์๋ฒ๋ฑ๋ก
# [ Git Parameter ]
- Git Parameter Plug-In ์ค์น
- ํ์ดํ๋ผ์ธ -> ๋งค๊ฐ๋ณ์ ์ค์
# [ SSH ์๋ฒ๋ก ํ์ผ์ ์ก ]
- publish over ssh ํ๋ฌ๊ทธ์ธ ์ค์น
- Jenkins ๊ด๋ฆฌ -> ์์คํ ์ค์ -> ์๊ฒฉ ์๋ฒ ์ค์
# [ ํ์ดํ ๋ผ์ธ ์์ฑ ]
- ์๋ก์ด item -> ํ์ดํ๋ผ์ธ ์์ฑ
- Pipeline Syntaxํตํด ์ค๋ํซ ์ค์
pipeline {
agent any
parameters {
gitParameter branchFilter: 'origin/(.*)', defaultValue: 'develop', name: 'BRANCH', type: 'PT_BRANCH'
}
stages {
stage('github clone') {
steps {
git branch: "${params.BRANCH}", credentialsId: 'jaesungahn91', url: 'https://github.com/wiiee-kr/wiiee-server.git'
}
}
stage('build'){
steps{
sh'''
./gradlew api:clean api:bootJar
'''
}
}
stage('publish on ssh'){
steps{
sshPublisher(
publishers:
[
sshPublisherDesc(
configName: 'wiiee-api-test',
transfers:
[
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: 'sh /home/ec2-user/deploy.sh',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: './',
remoteDirectorySDF: false,
removePrefix: 'api/build/libs/',
sourceFiles: 'api/build/libs/*.jar')
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: true)
]
)
}
}
}
}
# 0813 - Git Submodule
credential ํ์ผ ๊ด๋ฆฌ๋ฅผ ์ํ ๋ฐฉ๋ฒ์ค ํ๋๋ก ์ฌ์ฉํ๊ณ ์๋ Git Submodule์ ๋ํด ํ์ตํ์.
- git submodule
- ์ค์ ํ์ผ ์ํธํ
- Jasypt ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- Spring Cloud Config๋ฅผ ํตํ ์ค์ ํ์ผ ๋ถ๋ฆฌ
# [ Git Submodule์ด๋ ]
๋ฉ์ธ ๋ ํฌ์งํ ๋ฆฌ์ ํ์ ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ๋๊ณ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋๊ตฌ์ด๋ค. ํ๋์ ํ๋ก์ ํธ์์ ๋ค๋ฅธ ํ๋ก์ ํธ๋ฅผ ํจ๊ป ์ฌ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ ์ฃผ๋ก ์ฌ์ฉํ๋ค. ์ฆ, Git ์ ์ฅ์ ์์ ๋ค๋ฅธ Git ์ ์ฅ์๋ฅผ ๋๋ ํ ๋ฆฌ๋ก ๋ถ๋ฆฌํด ๋ฃ๋ ๊ฒ์ด ์๋ธ๋ชจ๋์ด๋ค. ๋ค๋ฅธ ๋ ๋ฆฝ๋ Git ์ ์ฅ์๋ฅผ Clone ํด์ ๋ด Git ์ ์ฅ์ ์์ ํฌํจํ ์ ์์ผ๋ฉฐ ๊ฐ ์ ์ฅ์์ ์ปค๋ฐ์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ๋ค.
# [ Git Submodule ์ฌ์ฉ๋ฐฉ๋ฒ ]
# ์๋ธ ๋ชจ๋์ถ๊ฐ
- git submodule add {URL}
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
- ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ธ๋ชจ๋์ ํ๋ก์ ํธ ์ ์ฅ์์ ์ด๋ฆ์ผ๋ก ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ ๋ค. ๋๋ ํ ๋ฆฌ ์ด๋ฆ์ผ๋ก ์๋ธ๋ชจ๋์ ์ถ๊ฐํ ์๋ ์๋ค.
# ์๋ธ๋ชจ๋ ํ์ธ
- git status
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: DbConnector
- .gitmodules
[submodule "DbConnector"]
path = DbConnector
url = https://github.com/chaconinc/DbConnector
- git diff
$ git diff --cached DbConnector
diff --git a/DbConnector b/DbConnector
new file mode 160000
index 0000000..c3f01dc
--- /dev/null
+++ b/DbConnector
@@ -0,0 +1 @@
+Subproject commit c3f01dc8862123d317dd46284b05b6892c7b29bc
- Git์ DbConnector ๋๋ ํ ๋ฆฌ๋ฅผ ์๋ธ๋ชจ๋๋ก ์ทจ๊ธํ๊ธฐ ๋๋ฌธ์ ํด๋น ๋๋ ํ ๋ฆฌ ์๋์ ํ์ผ ์์ ์ฌํญ์ ์ง์ ์ถ์ ํ์ง ์๋๋ค. ๋์ ์๋ธ๋ชจ๋ ๋๋ ํ ๋ฆฌ๋ฅผ ํต์งธ๋ก ํน๋ณํ ์ปค๋ฐ์ผ๋ก ์ทจ๊ธํ๋ค.
$ git diff --cached --submodule
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..71fc376
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "DbConnector"]
+ path = DbConnector
+ url = https://github.com/chaconinc/DbConnector
Submodule DbConnector 0000000...c3f01dc (new submodule)
- git commit & git push
$ git commit -am 'added DbConnector module'
[master fb9093c] added DbConnector module
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 DbConnector
DbConnector ๋๋ ํ ๋ฆฌ ๋ชจ๋๋ 160000์ด๋ค. git์๊ฒ ์์ด 160000๋ชจ๋๋ ์ผ๋ฐ์ ์ธ ํ์ผ์ด๋ ๋๋ ํ ๋ฆฌ๊ฐ ์๋๋ผ ํน๋ณํ๋ค๋ ์๋ฏธ์ด๋ค.
$ git push origin master
# ์๋ธ๋ชจ๋ ํฌํจํ ํ๋ก์ ํธ Clone
$ git clone https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
$ cd MainProject
$ ls -la
total 16
drwxr-xr-x 9 schacon staff 306 Sep 17 15:21 .
drwxr-xr-x 7 schacon staff 238 Sep 17 15:21 ..
drwxr-xr-x 13 schacon staff 442 Sep 17 15:21 .git
-rw-r--r-- 1 schacon staff 92 Sep 17 15:21 .gitmodules
drwxr-xr-x 2 schacon staff 68 Sep 17 15:21 DbConnector
-rw-r--r-- 1 schacon staff 756 Sep 17 15:21 Makefile
drwxr-xr-x 3 schacon staff 102 Sep 17 15:21 includes
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 scripts
drwxr-xr-x 4 schacon staff 136 Sep 17 15:21 src
$ cd DbConnector/
$ ls
$
- ํ๋ก์ ํธ๋ฅผ Cloneํ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ธ๋ชจ๋ ๋๋ ํ ๋ฆฌ๋ ๋น ๋๋ ํ ๋ฆฌ์ด๋ค.
- ์ดํ์
git submodule init
๋ช ๋ น์ ์คํํ๋ฉด ์๋ธ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ก์ปฌ ํ๊ฒฝ์ค์ ํ์ผ์ด ์ค๋น๋๋ค. ์ดํgit submodule update
๋ช ๋ น์ผ๋ก ์๋ธ๋ชจ๋์ ๋ฆฌ๋ชจํธ ์ ์ฅ์์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์๋ธ๋ชจ๋์ ํฌํจํ ํ๋ก์ ํธ์ ํ์ฌ ์ค๋ ์ท์์ Checkout ํด์ผ ํ ์ปค๋ฐ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ ์๋ธ๋ชจ๋ ํ๋ก์ ํธ์ ๋ ํ Checkout์ ํ๋ค.
$ git submodule init
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
$ git submodule update
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
- DbConnector ๋๋ ํ ๋ฆฌ๋ ๋ง์ง๋ง์ผ๋ก ์ปค๋ฐ์ ํ๋ ์ํ๋ก ๋ณต์๋๋ค.
- ๋ฐฉ๊ธ ๊ณผ์ ์ ๋ฉ์ธ ํ๋ก์ ํธ๋ฅผ Clone ํ ๋ git clone ๋ช
๋ น ๋ค์
--recurse-submodules
์ต์ ์ ๋ถ์ด๋ฉด ์๋ธ๋ชจ๋์ ์๋์ผ๋ก ์ด๊ธฐํํ๊ณ ์ ๋ฐ์ดํธํ๋ค.
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'
๋ฉ์ธ ํ๋ก์ ํธ์ submodule์ด ์ด๋ฏธ ์๊ณ , ํ์ ํ๋ก์ ํธ์ ์๋ก์ด ์ปค๋ฐ์ ๊ฐ์ ธ์์ผ ํ๋ ์ํฉ์์ update ๋ช ๋ น์ด๋ฅผ ํ์ฉํ๋ค. ์ด ๋ช ๋ น์ด๋ก ๋ฉ์ธ ํ๋ก์ ํธ์์ submodule์ ์ปค๋ฐ์ ๊ฐ์ ธ์ค๋ฉด, ์ด์ ์ ๋ดค๋ ๊ฒ์ฒ๋ผ ์๋ก ์ปค๋ฐํด์ผ ํ๋ ํ์ผ์ด ์๊ธด๋ค. ์์ ํ๊ฒ๊ณผ ๋์ผํ๊ฒ ํด๋น ํ์ผ์ add, commit, pushํด์ ๋ก์ปฌ๊ณผ ์๊ฒฉํ๋ก์ ํธ์ ๋ฐ์ํ๋ค.
$ git submodule update --remote --merge
// .gitmodules ํ์ผ์ ์ ์๋์ด ์๋ ๋ธ๋์น(default๋ main ๋๋ master)์ ์ต์ ๋ฒ์ ์ผ๋ก ์
๋ฐ์ดํธ
// $ git submodule update --remote
// ๋ก์ปฌ์์ ์์
์ค์ธ ๋ถ๋ถ๊ณผ ์๊ฒฉ์ ์์
๋ ๋ถ๋ถ์ด ๋ค๋ฅธ ๊ฒฝ์ฐ ๋จธ์ง๊น์ง ์งํ
// $ git submodule update --remote --merge
# 0814 - ์ ๋ ธํ ์ด์ ํ๋ก์ธ์(Annotation Processor)
# Annotation Processor๋?
โAnnotation Processingโ is a hook into the compile process of the java compiler, to analyse the source code for user defined annotations and handle then (by producing compiler errors, compiler warning, emitting source code, byte code โฆ).
Annotation Processor๋ ์ปดํ์ผ ๋จ๊ณ์์ Annotation์ ์ ์๋ ์ผ๋ ฌ์ ํ๋ก์ธ์ค๋ฅผ ๋์ํ๊ฒ ํ๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ปดํ์ผ ๋จ๊ณ์์ ์คํ๋๊ธฐ ๋๋ฌธ์, ๋น๋ ๋จ๊ณ์์ ์๋ฌ๋ฅผ ์ถ๋ ฅํ๊ฒ ํ ์ ์๊ณ ์์ค์ฝ๋ ๋ฐ ๋ฐ์ดํธ ์ฝ๋๋ฅผ ์์ฑํ ์๋ ์๋ค.
์ฌ์ฉํ๋ ์๋ก ์๋ฐ์ @Override๊ฐ ์์ผ๋ฉฐ, Lombok(๋กฌ๋ถ) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ํฌํจ๋์ด ์๋ ์ด๋
ธํ
์ด์
์ด ์๋๋ฉด annotationProcessor๋ฅผ ํตํด ์ถ๊ฐํด์ค์ผ ํ๋ค.
# Lombok๊ณผ Annotation Processor
Lombok์ด๋ @Getter, @Setter, @Builder ๋ฑ์ Annotation๊ณผ Annotation Processor๋ฅผ ์ ๊ณตํ์ฌ ํ์ค์ ์ผ๋ก ์์ฑํด์ผ ํ ์ฝ๋๋ฅผ ๊ฐ๋ฐ์ ๋์ ์์ฑํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค.
์ปดํ์ผ ์์ ์ Annotation Processor๋ฅผ ์ฌ์ฉํ์ฌ abstract syntaxtree๋ฅผ ์กฐ์ํ๋ค.
# ์๋์๋ฆฌ
# Moja Interface
@Magic
public interface Moja {
String pullOut();
}
# Magic ์ ๋ ธํ ์ด์
- Target์ TYPE์ผ๋ก ์ง์ ํ๋ฉด, ์ธํฐํ์ด์ค, ํด๋์ค, ENUM์ ์ง์ ์ด ๊ฐ๋ฅํ๋ค.
- Rentention์ ๋ณด๋ฅผ ์์ค๋ ๋ฒจ ๊น์ง๋ง ์ ์งํ๊ณ , ์ปดํ์ผ ์์ ์ ์ ํ ๋ค์ด์ ํ๋ก์ธ์๋ฅผ ์ฌ์ฉํด MagicMoja๋ฅผ ์์ฑํ๋ค.
@Target(ElementType.TYPE) // TYPE ์ผ๋ก ์ง์ ํ๋ฉด, ์ธํฐํ์ด์ค ,ํด๋์ค, enum์ ์ง์ ์ด ๊ฐ๋ฅํจ.
@Retention(RetentionPolicy.SOURCE) // ์์ค๋ ๋ฒจ์์ ๋ง ์ ์งํ๊ณ , ์ปดํ์ผ์ ์ ๋
ธํ
์ด์
ํ๋ก์ธ์๋ก ์์ค์ฝ๋๋ฅผ ์์ฑํ ๊ฒ์
public @interface Magic {
}
public class App {
public static void main( String[] args ) {
// MagicMoja ๊ฐ ์ ๋
ธํ
์ด์
ํ๋ก์ธ์๋ฅผ ์ฌ์ฉํด์์์ฑํ ํด๋์ค์ด๋ค.
Moja moja = new MagicMoja();
System.out.println(moja.pullOut());
}
}
- ์ ๋ ธํ ์ด์ ํ๋ก์ธ์๋ฅผ ์ฌ์ฉํ์ฌ, @Magic ์ ๋ ธํ ์ด์ ์ด ์ ์ฉ๋ ์ธํฐํ์ด์ค๊ฐ ์กด์ฌํ๋ฉด, MagicMoja ๋ผ๋ ํด๋์ค๋ฅผ ์์ฑํ๋ค.
# MagicMojaProcessor
/**
* Process ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด๋ ๋์ง๋ง, ์๋ฐ์์ ์ ๊ณตํ๋ AbstractProcessor ์ถ์ํด๋์ค๋ฅผ ๊ตฌํํด๋ ๋๋ค.
* Process ์์ ๊ตฌํํด์ผํ๋ ์ฌ๋ฌ ๋ฉ์๋๋ค์ ๊ตฌํํด์ฃผ๊ณ ์๋ค.
*/
public class MagicMojaProcessor extends AbstractProcessor {
/**
* ์ด ํ๋ก์ธ์๊ฐ ์ด๋ค ์ ๋
ธํ
์ด์
๋ค์ ์ฒ๋ฆฌํ ๊ฒ์ธ์ง ์ค์ ํ๋ ๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋ฉ.
*
* Element๋ ?
* - ํจํค์ง
* - ํด๋์ค
* - ๋ฉ์๋
* ์์ค์ฝ๋์ ๊ตฌ์ฑ์์๋ฅผ ์๋ฆฌ๋จผํธ๋ผ๊ณ ๋ถ๋ฅธ๋ค
* ๊ฐ ์๋ฆฌ๋จผํธ๋ค์ด ํ๋ก์ธ์ค๋ฅผ ํ ๋ ์ฐธ์กฐํ ์ ์๋ค.
* @return
*/
@Override
public Set<String> getSupportedAnnotationTypes() {
return Set.of(Magic.class.getName());
}
/**
* ๋ช ๋ฒ์ ์ ์์ค์ฝ๋๋ฅผ ์ง์ํ๋์ง ์ค์ .
* - ์ต์ ๋ฒ์ ์ง์ํ๋๋ก ์ค์
* @return
*/
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
/**
* ์ ๋
ธํ
์ด์
ํ๋ก์ธ์๋ ๋ผ์ด๋ ๋ผ๋ ๊ฐ๋
์ผ๋ก ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
* - ์ฌ๋ฌ ๋ผ์ด๋์ ๊ฑฐ์ณ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
* - ๊ฐ ๋ผ์ด๋๋ง๋ค ํ๋ก์ธ์์๊ฒ ํน์ ์ ๋
ธํ
์ด์
์ ๊ฐ์ง๊ณ ์๋ ์๋ฆฌ๋จผํธ๋ฅผ ์ฐพ์ผ๋ฉด ์ฒ๋ฆฌ๋ฅผ ์์ฒญํ๋ค.
* - ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ๊ฐ ๋ค์ ๋ผ์ด๋์๊ฒ ์ ๋ฌ๋ ์ ์๋ค.
* - Filter Chaining ๊ณผ ์ด์ฐ๋ณด๋ฉด ๋น์ทํ ๋๋์ด๋ค.
*
* ๋ง์ฝ ์ฌ๊ธฐ์ true๋ฅผ ๋ฆฌํดํ๋ฉด, ์ ๋
ธํ
์ด์
ํ๋ก์ธ์๊ฐ ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ์ด๋ค.
* true๋ฅผ ๋ฆฌํดํ๋ฉด, ๋ค๋ฅธ ํ๋ก์ธ์๊ฐ ์ด๋ฅผ ์ฒ๋ฆฌํ์ง ์๋๋ค.
* @param annotations
* @param roundEnv
* @return
*/
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
/* ์ ์ ํ ์์น์ ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํ๋์ง ์ฒดํฌ */
/* ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํ ์๋ฆฌ๋จผํธ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ์ ์๋ค.*/
Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(Magic.class);
for (Element element : elementsAnnotatedWith) {
/* ์ ๋
ธํ
์ด์
์ด ์ธํฐํ์ด์ค ์๋๊ณณ์ ์ฌ์ฉํ์ ๊ฒฝ์ฐ */
if (element.getKind() != ElementKind.INTERFACE) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@Magic ์ ๋
ธํ
์ด์
์ Interface๋ง ์ง์ํ๋ ์ ๋
ธํ
์ด์
์
๋๋ค.");
} else {
// ๋ก๊น
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Processing " + element.getSimpleName());
}
}
return true;
}
}
- Processor Interface๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง, ์๋ฐ์์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ AbstractProcessor ์ถ์ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ค.
- ์ธํฐํ์ด์ค์์ ๊ธฐ๋ณธ์ผ๋ก ๊ตฌํํด์ผํ ๊ฒ๋ค์ ์ด๋์ ๋ ๊ตฌํํ๊ณ ์๋ค.
์ฃผ์ ๋ฉ์๋
- getSupportedAnnotationTypes : ์ด ํ๋ก์ธ์๊ฐ ์ฒ๋ฆฌํ ์ ๋ ธํ ์ด์ ๋ค์ ์ง์ ํ๋ค.
- getSupportedSourceVersion : ์์ค์ฝ๋ ๋ฒ์ ์ ๋ช๊น์ง ์ง์ํ ๊ฒ์ธ์ง ์ง์ ํ๋ค.
- process : ์ ๋
ธํ
์ด์
ํ๋ก์ธ์๊ฐ ์ ๋
ธํ
์ด์
ํ๋ก์ธ์๊ฐ ์ฒ๋ฆฌํ ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํ๊ณ ์๋ ์๋ฆฌ๋จผํธ ๋ค์ ์ฐธ์กฐํ ์ ์๋ค.
- ์๋ฆฌ๋จผํธ๋? ์์ค์ฝ๋์ ๊ตฌ์ฑ์์๋ค์ ์๋ฆฌ๋จผํธ๋ผ๊ณ ํ๋ค(ํจํค์ง ์๋ฆฌ๋จผํธ, ํด๋์ค ์๋ฆฌ๋จผํธ, ๋ฉ์๋ ์๋ฆฌ๋จผํธ)
- ๊ฐ ์๋ฆฌ๋จผํธ๋ค์ ํ๋ก์ธ์คํ ๋ ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ค.