0130 ~ 0205


# 0130 ~ 0205

# 0201 - API Gateway

# [ API Gateway ๋ž€? ]

์„œ๋น„์Šค๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ชจ๋“  API ์š”์ฒญ์˜ ๊ด€๋ฌธ ์—ญํ• ์„ ํ•˜๋Š” ์„œ๋ฒ„. ์‹œ์Šคํ…œ์˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋‚ด๋ถ€๋กœ ์ˆจ๊ธฐ๊ณ  ์™ธ๋ถ€์˜ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต๋งŒ์„ ์ ์ ˆํ•œ ํ˜•ํƒœ๋กœ ์‘๋‹ต (ํ”„๋ก์‹œ ์—ญํ• )

API Gateway๋Š” ๋ชจ๋“  ์„œ๋ฒ„๋กœ์˜ ์š”์ฒญ์„ ๋‹จ์ผ์ง€์ ์„ ๊ฑฐ์ณ์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ณตํ†ต๋œ ๋กœ์ง ์ฒ˜๋ฆฌ๋‚˜ ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ์ฒ˜๋ฆฌ, ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋“ฑ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

# [ ์ธ์ฆ/์ธ๊ฐ€์— ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ ]

  • ์—”๋“œํฌ์ธํŠธ๋ณ„ API ํ˜ธ์ถœ ์ธ์ฆ
  • ์—”๋“œํฌ์ธํŠธ๋ณ„ API ์š”์ฒญ ์ธ๊ฐ€

# [ ๋ผ์šฐํŒ… ]

  • ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ
  • ์„œ๋น„์Šค ๋ฐ ํด๋ผ์ด์–ธํŠธ ๋ณ„ ์—”๋“œํฌ์ธํŠธ ์ œ๊ณต
  • ๋ฉ”์‹œ์ง€ ๋˜๋Š” ํ—ค๋”๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…

# [ ๊ณตํ†ต ๋กœ์ง ์ฒ˜๋ฆฌ ]

# [ Mediation(๋ฉ”๋””์—์ด์…˜) ]

๋ฉ”๋””์—์ด์…˜์ด๋ž€ '์ค‘์žฌ' ๋˜๋Š” '์กฐ์ •'์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ API ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์›ํ•˜๋Š” API ํ˜•ํƒœ์™€ ๋‹ค๋ฅผ๋•Œ API ๊ฒŒ์ดํŠธ์›จ์ด๊ฐ€ ์ด๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ด์•ผ๊ธฐํ•œ๋‹ค.

  • ๋ฉ”์‹œ์ง€ ํฌ๋งท ๋ณ€ํ™˜
  • ํ”„๋กœํ† ์ฝœ ๋ณ€ํ™˜
  • ๋ฉ”์‹œ์ง€ ํ˜ธ์ถœ ํŒจํ„ด ๋ณ€ํ™˜
  • Aggregation(์–ด๊ทธ๋ ˆ๊ฒŒ์ด์…˜) : API๋ฅผ ๋ฌถ์–ด์„œ ํ•˜๋‚˜์˜ API ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋ณด์ด๋Š” ๋™์ž‘

# [ ๋กœ๊น… ๋ฐ ๋ฏธํ„ฐ๋ง ]

  • API ํ˜ธ์ถœ ๋กœ๊น…
  • API Metering & Charing (๋ฏธํ„ฐ๋ง & ์ฐจ์ง•) : API ๋ฏธํ„ฐ๋ง๊ณผ ์ฐจ์ง•์€ ์œ ๋ฃŒ API ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ ๊ธฐ๋Šฅ์œผ๋กœ ์ธก์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ง€ํ‘œ๋“ค์„ ๊ธฐ๋กํ•˜๋Š” ์„œ๋น„์Šค

# [ QoS ์กฐ์ •(Quality of service) ]

Qos ์กฐ์ • ๊ธฐ๋Šฅ์ด๋ž€ API ์„œ๋น„์Šค๋ฅผ ํด๋ผ์ด์–ธํŠธ ๋Œ€์ƒ์— ๋”ฐ๋ผ์„œ ์„œ๋น„์Šค ๋ ˆ๋ฒจ์„ ์กฐ์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.
ํ˜ธ์ถœํšŸ์ˆ˜๋ฅผ ์ œํ•œ ํ•œ๋‹ค๊ฑฐ๋‚˜, ์ „์†ก ์šฉ๋Ÿ‰์ด๋‚˜, ๋„ค์ดํŠธ์›Œํฌ ๋Œ€์—ญํญ์„ ์œ ๋ฃŒ/๋ฌด๋ฃŒ ์‚ฌ์šฉ์ž์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ QoS ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ํ•œ๋‹ค.


# 0202 - jasypt

Jasypt is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.

๊ณต๊ฐœ๋œ ํ”„๋กœ์ ํŠธ์˜ private ์ •๋ณด์— ๋Œ€ํ•œ ๋ณด์•ˆ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๊ทธ ์ค‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ •๋ณด๋ฅผ ์•”ํ˜ธํ™” ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•œ๋‹ค.

[ ์‚ฌ์šฉ๋ฒ• ]

  • ์˜์กด์„ฑ ์ถ”๊ฐ€
dependencies {
	implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter'
}
1
2
3
  • Encrypt Key ์ƒ์„ฑ
    https://www.devglan.com/online-tools/jasypt-online-encryption-decryption
    jasypt ๊ด€๋ จ ์„ค์ • ์‹œ password๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค. ํ•ด๋‹น password๋ฅผ ์•”ํ˜ธํ™”ํ•˜๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ์‚ฌ์ดํŠธ์—์„œ ์•”ํ˜ธํ™”

  • Configuration ์ƒ์„ฑ

@Configuration
@EnableEncryptableProperties
public class JasyptConfig {
    @Bean(name = "encryptorBean")
    public StringEncryptor stringEncryptor(SimpleStringPBEConfig simpleStringPBEConfig) {
        PooledPBEStringEncryptor stringEncryptor = new PooledPBEStringEncryptor();
        stringEncryptor.setConfig(simpleStringPBEConfig);
        return stringEncryptor;
    }

    @Bean
    @ConfigurationProperties("config.encrypt")
    public SimpleStringPBEConfig simpleStringPBEConfig() {
        return new SimpleStringPBEConfig();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • properties ์„ค์ • ์ถ”๊ฐ€
jasypt:
  encryptor:
    bean: {๋นˆ์ด๋ฆ„}
config:
  encrypt:
    password: {์•”ํ˜ธํ™”๋œ ํŒจ์Šค์›Œ๋“œ}
    algorithm: PBEWithMD5AndDES
    provider-name: SunJCE
    pool-size: 1
    key-obtention-iterations: 1000
    string-output-type: base64
1
2
3
4
5
6
7
8
9
10
11
  • ์•”ํ˜ธํ™”
@SpringBootTest
class JasyptConfigTest {
    @Autowired
    @Qualifier("encryptorBean")
    private StringEncryptor stringEncryptor;

    @Test
    public void generatePassword() {
        String encrypt = stringEncryptor.encrypt("password");
        System.out.println(encrypt);
        String decrypt = stringEncryptor.decrypt(encrypt);
        System.out.println(decrypt);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • ์ ์šฉ ENC("์•”ํ˜ธํ™” password")ย ํ˜•์‹์œผ๋กœ ์•”ํ˜ธํ™”๋œ ๊ฐ’ ์ ์šฉ
spring:
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306
    username: dbuser
    password: ENC(WHXxOvGjJa7qXjALhA7ghdoYksJjabL/)
1
2
3
4
5
6

# 0205 - ThreadLocal

# [ Thread Local์ด๋ž€? ]

  • ์ผ์ข…์˜ ์“ฐ๋ ˆ๋“œ ์ง€์—ญ๋ณ€์ˆ˜ใ…ก ์˜ค์ง ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ์— ์˜ํ•ด ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋กœ์„œ, ๋‹ค๋ฅธ ๊ฐ๊ฐ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ThreadLocal์„ ํ˜ธ์ถœํ•ด๋„ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์„ ๋ฐ”๋ผ๋ณธ๋‹ค.
  • Thread์˜ ์ •๋ณด๋ฅผ Key๋กœ ํ•˜๋Š” Map ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ด๋‘๊ณ  ์‚ฌ์šฉํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ.
  • ThreadPool ์‚ฌ์šฉํ•˜์—ฌ Thread ์žฌํ™œ์šฉ ์‹œ ์ด์ „์— ์ €์žฅ๋œ ThreadLocal์„ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ ๋ชจ๋“  ThreadLocal ์‚ฌ์šฉ ํ›„ remove ํ•„์ˆ˜

# [ ํ™œ์šฉ ]

  • ์‚ฌ์šฉ์ž ์ธ์ฆ์ •๋ณด - Spring Sercurity์—์„œ ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด ์„ธ์…˜์„ ์‚ฌ์šฉํ•  ๋•Œ.
  • ํŠธ๋žœ์žญ์…˜ ์ปจํ…์ŠคํŠธ - ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ €๊ฐ€ ํŠธ๋žœ์žญ์…˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์ „ํŒŒํ•  ๋•Œ.
  • MDC(Mapped Diagnostic Context) - logback์—์„œ log์˜ ๋ฉ”ํƒ€์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ.

# [ ์‚ฌ์šฉ๋ฒ• ]

  • ๊ฐ์ฒด ์ƒ์„ฑ
ThreadLocal<String> threadLocalGeneric = new ThreadLocal<>();
1
  • ์ดˆ๊ธฐ๊ฐ’ ์„ค์ • ๋ฐฉ๋ฒ•
ThreadLocal<String> subThreadLocal = new ThreadLocal<String>() {
			@Override
			protected String initialValue() {
				return "Init Value";
			}
		};

1
2
3
4
5
6
7
  • ๊ฐ’ ์ €์žฅ
ThreadLocal<String> threadLocalGeneric = new ThreadLocal<>();
threadLocalGeneric.set("TEMP");
1
2
  • ๊ฐ’ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
ThreadLocal<String> threadLocalGeneric = new ThreadLocal<>();
String result = threadLocalGeneric.get();
1
2
  • ๊ฐ’ ์‚ญ์ œ
ThreadLocal<String> threadLocalGeneric = new ThreadLocal<>();
threadLocalGeneric.set("TEMP");
System.out.println(threadLocalGeneric.get());
// OUTPUT: TEMP

threadLocalGeneric.remove();
System.out.println(threadLocalGeneric.get());
// OUTPUT: null
1
2
3
4
5
6
7
8

# [ ์‚ฌ์šฉ ์˜ˆ์‹œ ]

  • Runnable ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„(MyRunnable) -> threadLocal์— ๋žœ๋ค ๊ฐ’ ์ €์žฅ
public static class MyRunnable implements Runnable {

	        private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();

	        @Override
	        public void run() {
	            threadLocal.set( (int) (Math.random() * 100D) );
	    
	            try {
	                Thread.sleep(50);
	            } catch (InterruptedException e) {
	            }
	    
	            System.out.println(threadLocal.get());
	        }
	    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • ํ•˜๋‚˜์˜ Runnable ๊ฐ์ฒด๋ฅผ 2๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ์— ๋‹ด๊ธฐ
MyRunnable runnable = new MyRunnable();
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
1
2
3
  • ๊ฐ ์“ฐ๋ ˆ๋“œ run ์‹œ ๋‘ ์“ฐ๋ ˆ๋“œ์— ๋‹ค๋ฅธ ๊ฐ’์ด ๋‹ด๊ธฐ๋Š”์ง€ ํ™•์ธ(์“ฐ๋ ˆ๋“œ ๋ณ„ ThreadLocal์— ๋žœ๋ค ๊ฐ’์ด ๋‹ด๊ธฐ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅด๋‹ค.)
System.out.print("thread1 get ๊ฒฐ๊ณผ :: ");
thread1.start();
// OUTPUT: thread1 get ๊ฒฐ๊ณผ :: 19

Thread.sleep(200);
System.out.print("thread2 get ๊ฒฐ๊ณผ :: ");
thread2.start();
// OUTPUT: thread2 get ๊ฒฐ๊ณผ :: 65

Thread.sleep(200);
1
2
3
4
5
6
7
8
9
10

# [ InheritableThreadLocal์ด๋ž€? ]

  • ๋ถ€๋ชจ ์“ฐ๋ ˆ๋“œ์—์„œ ์ƒ์„ฑ๋œ ThreadLocal์„ ์ž์‹ ์“ฐ๋ ˆ๋“œ์—์„œ๋„ ๋™์ผํ•œ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ThreadLocal Class.
ThreadLocal<String> threadLocal = new ThreadLocal<>();
InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

Thread thread1 = new Thread(() -> {
System.out.println("========== [" + Thread.currentThread().getName() + "] START ==========");
threadLocal.set("[" + Thread.currentThread().getName() + "] ThreadLocal Value");
inheritableThreadLocal.set("[" + Thread.currentThread().getName() + "] InheritableThreadLocal Value");

System.out.println("threadLocal get :: " + threadLocal.get());
System.out.println("inheritableThreadLocal get :: " + inheritableThreadLocal.get());

Thread childThread = new Thread( () -> {
System.out.println("========== [" + Thread.currentThread().getName() + " - ChildThread] START ==========");
System.out.println("threadLocal get :: " + threadLocal.get());
System.out.println("inheritableThreadLocal get :: " + inheritableThreadLocal.get());
});
childThread.start();
});

thread1.start();

Thread thread2 = new Thread(() -> {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("========== [" + Thread.currentThread().getName() + "] START ==========");
System.out.println("threadLocal get :: " + threadLocal.get());
System.out.println("inheritableThreadLocal get :: " + inheritableThreadLocal.get());
System.out.println("------------------------------------------------------------------------------");
});
thread2.start();

/* OUTPUT
 *
========== [Thread-2] START ==========
threadLocal get :: [Thread-2] ThreadLocal Value
inheritableThreadLocal get :: [Thread-2] InheritableThreadLocal Value
========== [Thread-4 - ChildThread] START ==========
threadLocal get :: null
inheritableThreadLocal get :: [Thread-2] InheritableThreadLocal Value
========== [Thread-3] START ==========
threadLocal get :: null
inheritableThreadLocal get :: null
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Last update: February 5, 2023 23:06
Contributors: jaesungahn91