Publish:

ํƒœ๊ทธ: , ,

์นดํ…Œ๊ณ ๋ฆฌ:

  • ํ”„๋ก์‹œ ํŒจํ„ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณธ๋‹ค.
  • java.lang.reflect.Proxy ๋ฅผ ์ด์šฉํ•ด ํ”„๋ก์‹œ ๊ฐ์ฒด(stub)๋ฅผ ์ž๋™ ์ƒ์„ฑํ•˜๋„๋ก ํ•ด๋ณด์ž.
  • ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ์˜์กด๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.

Reflection?

Java์˜ ๋ฆฌํ”Œ๋ ‰์…˜์€ ๋Ÿฐํƒ€์ž„ ์‹œ ํด๋ž˜์Šค์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(์˜ˆ: ํ•„๋“œ, ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž, ์ฃผ์„ ๋“ฑ)๋ฅผ ๊ฒ€์‚ฌํ•˜๊ฑฐ๋‚˜ ์ƒํ˜ธ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ์ปดํŒŒ์ผ ์‹œ ์ด๋ฆ„์„ ๋ชฐ๋ผ๋„ ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ ๋ฐ ํ•„๋“œ๋ฅผ ๋™์ ์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

Class

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋Ÿฐํƒ€์ž„ ์‹œ ํด๋ž˜์Šค๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

1
2
3
Class<?> clazz = MyClass.class; 
Class<?> clazz = obj.getClass(); 
Class<?> clazz = Class.forName("com.mysql.cj.jdbc.Driver"); 

Class ์ƒ์„ธ ์ •๋ณด ํ™•์ธ

1
2
3
4
5
6
7
8
9
10
11
12
13
Class<?> clazz = MyClass.class;

// ํด๋ž˜์Šค ์ด๋ฆ„ ํ™•์ธ
String className = clazz.getName();

// ์ ‘๊ทผ์ œํ•œ์ž ์ •๋ณด ํ™•์ธ
int modifiers = clazz.getModifiers();

// super class ์ •๋ณด ํ™•์ธ
Class<?> superClass = clazz.getSuperclass();

// ๊ตฌํ˜„๋œ ์ธํ„ฐํŽ˜์ด์Šค ์ •๋ณด ํ™•์ธ
Class<?>[] interfaces = clazz.getInterfaces();

ํ•„๋“œ ๋ฐ ๋ฉ”์†Œ๋“œ ์ •๋ณด ํ™•์ธ

1
2
3
4
5
// ๋ชจ๋“  ํ•„๋“œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
Field[] fields = clazz.getDeclaredFields();

// ๋ชจ๋“  ๋ฉ”์†Œ๋“œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
Method[] methods = clazz.getDeclaredMethods();

ํ•„๋“œ ์ˆ˜์ •

1
2
3
4
5
6
7
// private ํ•„๋“œ ์ ‘๊ทผ
Field privateField = clazz.getDeclaredField("fieldName");
privateField.setAccessible(true); // true ๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด private ํ•„๋“œ์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.
Object value = privateField.get(obj);

// private ํ•„๋“œ ์ˆ˜์ •
privateField.set(obj, newValue);

๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ

์•„๋ž˜์ฒ˜๋Ÿผ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ด์šฉํ•ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
// ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ๊ณผ ํ•จ๊ป˜ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
Method method = clazz.getDeclaredMethod("methodName", parameterTypes);
Object result = method.invoke(obj, arg1, arg2);

๋ฆฌํ”Œ๋ ‰์…˜์€ ์–ธ์ œ ์“ธ๊นŒ?

์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์ง๊ด€์ ์ด๊ณ  ์ดํ•ด๊ฐ€ ์‰ฌ์›Œ๋ณด์ด๋Š”๋ฐ ์™œ ๊ตณ์ด ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด์„œ ํ˜ธ์ถœํ•˜๋Š”๊ฑธ๊นŒ?

ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์ž…์žฅ๊ณผ ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์ž…์žฅ์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํƒ€์ž…์ด ์ •์ ์œผ๋กœ ๊ฒฐ์ •๋œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ๋ฒ”์šฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•˜๋Š” ์†Œ์Šค์ฝ”๋“œ์—์„œ๋Š” ์ œ์•ฝ ์‚ฌํ•ญ์ด ๋งŽ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฆฌํ”Œ๋ ‰์…˜์€ ๊ฐ์ฒด๋ฅผ ๋ฐ”์ดํŠธ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•˜๋Š” ์ง๋ ฌํ™” ๋ฐ ์—ญ์ง๋ ฌํ™” ํ”„๋กœ์„ธ์Šค์—์„œ ํด๋ž˜์Šค ๊ตฌ์กฐ๋ฅผ ๋™์ ์œผ๋กœ ๊ฒ€์‚ฌํ•˜๊ณ  ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. Gson ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—ญ์‹œ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ด์šฉํ•ด ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ์ถ”๋ก ํ•œ๋‹ค.

๋˜ํ•œ, ๊ณง ์•Œ์•„๋ณผ Proxy ๊ฐ์ฒด ์ƒ์„ฑ์—๋„ ๋ฆฌํ”Œ๋ ‰์…˜์ด ์‚ฌ์šฉ๋œ๋‹ค. ์Šคํ”„๋ง์—์„œ๋Š” ์ด๋ฅผ ๋” ๋ฐœ์ „์‹œ์ผœ AOP(Aspect-Oriented Programming) ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค. ์Šคํ”„๋ง์—์„œ ์ฃผ๋กœ ์“ฐ์ด๋Š” @Transactional ์–ด๋…ธํ…Œ์ด์…˜ ๋˜ํ•œ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ํŠธ๋žœ์žญ์…˜์„ ๊ด€๋ฆฌํ•œ๋‹ค.

gson ์€ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ด์šฉํ•ด ํƒ€์ž…์„ ์•Œ์•„๋‚ธ๋‹ค.

์ด์ „ ๊ธ€์—์„œ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ์„ธ์…˜์„ ํ™•์ธํ•˜๋Š” ๊ณผ์ • ๋˜ํ•œ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค. HandlerMethodArgumentResolver ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ด์šฉํ•ด ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ์‹œ ์ฃผ์˜ ์‚ฌํ•ญ

์˜ค๋ฒ„ํ—ค๋“œ

๋ฆฌํ”Œ๋ ‰์…˜์€ ๋Ÿฐํƒ€์ž„ ์‹œ ์œ ํ˜• ๊ฒ€์‚ฌ ๋ฐ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์„ ํฌํ•จํ•˜๋Š” ์ž‘์—…์ด๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์ธ ์ž‘์—…๋ณด๋‹ค ๋Š๋ฆฌ๋‹ค. ์‹œ๊ฐ„๊ณผ ๋ฉ”๋ชจ๋ฆฌ ์ธก๋ฉด์—์„œ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๋ณด์•ˆ๋ฌธ์ œ

๋ฆฌํ”Œ๋ ‰์…˜์€ ์ ‘๊ทผ์ œํ•œ์ž๋ฅผ ๋ชจ๋‘ ๋ฌด์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์•ˆ ์ทจ์•ฝ์„ฑ์ด ์žˆ๋‹ค.

์ฝ”๋“œ ๊ฐ€๋…์„ฑ

๋ฆฌํ”Œ๋ ‰์…˜์— ํฌ๊ฒŒ ์˜์กดํ•˜๋Š” ์ฝ”๋“œ๋Š” ๊ฐ€๋…์„ฑ์ด ๋‚ฎ๊ณ  ์œ ์ง€ ๊ด€๋ฆฌ๊ฐ€ ๋” ์–ด๋ ต๋‹ค. ํด๋ž˜์Šค์˜ ๋Œ€๋ถ€๋ถ„์ด ๋Ÿฐํƒ€์ž„ ์‹œ ๋™์ ์œผ๋กœ ๊ฒฐ์ •๋˜๋Š” ๊ฒฝ์šฐ ๊ฐœ๋ฐœ์ž๋Š” ํด๋ž˜์Šค์˜ ๊ตฌ์กฐ์™€ ๋™์ž‘์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค.

์ปดํŒŒ์ผ ์•ˆ์ •์„ฑ

๋ฆฌํ”Œ๋ ‰์…˜์€ ์ปดํŒŒ์ผ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž ์žฌ์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.

Proxy?

ํ”„๋ก์‹œ๋ž€ โ€˜๋Œ€๋ฆฌโ€™, โ€˜๋Œ€์‹ โ€™ ์ด๋ผ๋Š” ๋œป์„ ๊ฐ€์ง„๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ๋ถ„์‚ฐ ์ปดํ“จํŒ… ํ™˜๊ฒฝ์—์„œ ์›๊ฒฉ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœ์„ ๋Œ€์‹  ํ•ด์ฃผ๋Š” ๊ฐ์ฒด๋ผ๊ณ  ๋ณด๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

ํ”„๋ก์‹œ ํŒจํ„ด

์ž‘์€ ๊ทœ๋ชจ์˜ Stand-alone ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๊ตณ์ด ํ”„๋ก์‹œ๊ฐ€ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ์„œ๋น„์Šค์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๊ณ  ๋„๋ฉ”์ธ์ด ๋งŽ์•„์ง€๋ฉด์„œ ๋‹จ์ผ ์„œ๋ฒ„์—์„œ ๋ชจ๋“  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋ฒ„๊ฒ๊ณ , ๋™์‹œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ด์ง€๋Š” ์‹œ์ ์ด ๋˜๋ฉด ๊ฐ ๋„๋ฉ”์ธ์„ ๋ณ„๋„์˜ ์„œ๋ฒ„๋กœ ๋ถ„์‚ฐ์‹œ์ผœ์„œ ์šด์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ํšจ์œจ์ ์ผ ๊ฒƒ์ด๋‹ค.

์ด๋•Œ, ๋‹จ์ผ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋™์ž‘ํ•˜๋˜ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ์ž‘์—…์„ ํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ํ•จ์ˆ˜๊ฐ„ ์„œ๋กœ ์›๊ฒฉ ํ˜ธ์ถœ์„ ํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ์ด๋Ÿฐ ๋ถ„์‚ฐ ์ปดํ“จํŒ… ํ™˜๊ฒฝ์—์„œ ๊ธฐ์กด์˜ ๋ฐฉ์‹๊ณผ ๋™์ผํ•˜๊ฒŒ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ๋„ ์›๊ฒฉ ํ˜ธ์ถœ์˜ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ๋ ๊นŒ?

ํด๋ผ์ด์–ธํŠธ ์ชฝ์—์„œ๋Š” ํ”„๋ก์‹œ๋ฅผ ์ด์šฉํ•ด ํ˜ธ์ถœํ•˜๋Š”์ง€, ์•„๋‹Œ์ง€ ๊ด€์‹ฌ์ด ์—†๋‹ค. ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ๊ธฐ์กด ํ˜ธ์ถœ ๋ฐฉ์‹ ๊ทธ๋Œ€๋กœ ๋™์ž‘ํ•ด์•ผ ํ•œ๋‹ค. (Open-Closed Principle)

์ด์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์€ ๊พธ์ค€ํžˆ ์ง„ํ–‰๋˜์–ด ์™”๋‹ค. (RPC, RMI, CORBA) (์ตœ๊ทผ์—๋Š” stub ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” RESTful ๋ฐฉ์‹์œผ๋กœ ํ†ต์‹ ํ•œ๋‹ค.)

proxy pattern

stub

๋ถ„์‚ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์Šคํ…์€ ๊ทธ ์ž์ฒด๋กœ ์ œ ๊ธฐ๋Šฅ์€ ๋ฐœํœ˜ํ•˜์ง€ ๋ชปํ•˜์ง€๋งŒ ์›๋ž˜ ๊ฐ์ฒด๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ฐธ์กฐ ์—ญํ• ์„ ํ•˜๊ณ , ์› ๊ฐ์ฒด์˜ ๊ธฐ๋Šฅ์กฐ์ž‘์„ ์œ„์ž„๋ฐ›์€ proxy ์—ญํ• ์„ ํ•˜๋Š” ์ž‘์€ ๊ฐ์ฒด๋กœ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๊ธฐ์กด๊ณผ ๋™์ผํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์‹ค์ œ ํ”„๋ก์‹œ ๊ฐ์ฒด ๋‚ด๋ถ€์—์„œ ์›๊ฒฉ ํ˜ธ์ถœ์„ ํ•˜๊ณ  ์žˆ๋Š” ์…ˆ์ด๋‹ค.

์‹ค์ œ ๊ตฌํ˜„ ์‹œ stub ์— ๋Œ€์‘๋˜๋Š” ์›๊ฒฉ ๊ฐ์ฒด(server ์ชฝ์— ์กด์žฌ)์™€ ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด ๋™์ž‘ ๊ทœ์น™์„ ๋™์ผํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์— ๊ตฌํ˜„๋œ ๋™์ž‘ ๋ฐฉ์‹์€

  1. ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ์—ฐ๊ฒฐ์ด ์ˆ˜๋ฆฝ๋˜๋ฉด, proxy ๊ฐ์ฒด(stub)๋Š” ์›๊ฒฉ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์— ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์„ ๋งˆ์‚ด๋ง(Marshalling) ํ•˜์—ฌ ์›๊ฒฉ JVM ์œผ๋กœ ์ „์†กํ•œ ๋’ค ์‘๋‹ต ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. (ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋„๋ฉ”์ธ๋ช…, ํ˜ธ์ถœํ•  ํ•จ์ˆ˜๋ช…, ํ•จ์ˆ˜ ํ˜ธ์ถœ์— ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ)
  2. ์„œ๋ฒ„์˜ ์Šค์ผˆ๋ ˆํ†ค(skeleton) ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ๋งˆ์ƒฌ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์›๋ž˜๋Œ€๋กœ ์–ธ๋งˆ์‚ด๋Ÿ‰ ํ•œ๋‹ค.
  3. ์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‹ค์ œ ์›๊ฒฉ ๊ฐ์ฒด์—๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  4. ํ˜ธ์ถœ ํ›„ ๊ฒฐ๊ณผ ๊ฐ’์ด๋‚˜ ์˜ˆ์™ธ๋ฅผ ์Šค์ผˆ๋ ˆํ†ค์—๊ฒŒ ๋˜๋Œ๋ ค์ค€๋‹ค.
  5. ์Šค์ผˆ๋ ˆํ†ค์€ ๋‹ค์‹œ ๊ฒฐ๊ณผ๊ฐ’์ด๋‚˜ ์˜ˆ์™ธ๋ฅผ ๋งˆ์ƒฌ๋งํ•˜์—ฌ ํ˜ธ์ถœ์ž(stub)์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.

stub ์„ ํ†ตํ•ด ์›๊ฒฉ ๋ฉ”์†Œ๋“œ์— ์ ‘๊ทผํ•œ๋‹ค.

skeleton

์Šคํ…์€ ๊ฐ์ฒด ๊ทธ ์ž์ฒด์™€ ๋™์ผํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ง€๋งŒ, ์Šคํ…์˜ ๋ฉ”์†Œ๋“œ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ž์ฒด๋ฅผ ๋‹ด๊ณ ์žˆ์ง€๋Š” ์•Š์œผ๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์Šคํ…์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ˜ธ์ถœ๋œ ๋ฉ”์†Œ๋“œ ๋ช…๊ณผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋œ ๊ฐ’๋“ค์ด ์ŠคํŠธ๋ฆผ ํ˜•ํƒœ๋กœ ๋„คํŠธ์›Œํฌ๋ฅผ ํ†ตํ•ด ์Šค์ผˆ๋ ˆํ†ค์— ์ „๋‹ฌ๋œ๋‹ค. ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์„ ์Šค์ผˆ๋ ˆํ†ค์ด ๋ฐ›๊ฒŒ ๋˜๋ฉด ์Šค์ผˆ๋ ˆํ†ค์€ ์ŠคํŠธ๋ฆผ์„ ๋ถ„์„ํ•˜์—ฌ ์–ด๋–ค ๋ฉ”์†Œ๋“œ๊ฐ€ ์š”์ฒญ๋˜์—ˆ๋Š”์ง€๋ฅผ ํŒŒ์•…ํ•˜๊ณ , ์„œ๋ฒ„์— ์žˆ๋Š” ๊ฐ์ฒด์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋œ๋‹ค. ๋ฉ”์†Œ๋“œ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ’์€ ๋‹ค์‹œ ์Šค์ผˆ๋ ˆํ†ค์— ์˜ํ•ด ์Šคํ…์œผ๋กœ ์ „๋‹ฌ๋˜๋ฉฐ, ์Šคํ…์€ ๋งˆ์น˜ ํ•ด๋‹น ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋กœ์ปฌ ์ปดํ“จํ„ฐ์—์„œ ์ฒ˜๋ฆฌํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๊ฒฐ๊ณผ๊ฐ’์„ ์ „๋‹ฌํ•œ๋‹ค.

reflection ์œผ๋กœ proxy ๊ฐ์ฒด(stub) ์ž๋™ ์ƒ์„ฑํ•˜๊ธฐ

๊ธฐ์กด ์†Œ์Šค์—์„œ๋Š” stub ๊ฐ์ฒด๋ฅผ ๊ฐ๊ฐ์˜ ๋„๋ฉ”์ธ๋งˆ๋‹ค ๋งŒ๋“ค์—ˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค๋ณด๋‹ˆ ๊ตฌํ˜„์ฒด์˜ ๊ธฐ๋Šฅ๊ณผ ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ๋™์ผํ•œ ์ƒํƒœ์—์„œ ๋„๋ฉ”์ธ๋งŒ ๋ฐ”๋€ DaoImpl ํด๋ž˜์Šค๊ฐ€ ๊ณ„์† ์ƒ๊ฒจ๋‚ฌ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ตฌํ˜„์ฒด๋“ค์„ ClientApp์—์„œ ์ปดํŒŒ์ผ ์‹œ์ ์— ์ฃผ์ž…ํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค.

๋„๋ฉ”์ธ์ด ์ƒˆ๋กœ ์ƒ๊ธฐ๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๋„ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์•ผํ–ˆ๋‹ค.

๊ฐ ๋„๋ฉ”์ธ ๋ ˆํผ๋Ÿฐ์Šค ํƒ€์ž…์— ๋งž๋Š” dao ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์ฃผ์ž…ํ•ด์ค˜์•ผ ํ–ˆ๋‹ค.

newProxyInstance

1
2
// java.lang.reflect.Proxy.class
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

java.lang.reflect.Proxy ํด๋ž˜์Šค์—๋Š” newProxyInstance ๋ผ๋Š” ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ค€ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋™์  ํ”„๋ก์‹œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•ด ์ค€๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ:

  • loader: ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ํด๋ž˜์Šค ๋กœ๋”. ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋™์ ์œผ๋กœ ๋กœ๋“œํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•œ๋‹ค.
  • interfaces: ์ž๋™ ์ƒ์„ฑํ•  ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ชฉ๋ก. ๋ฐฐ์—ด ํƒ€์ž…์ด๋‹ค.
  • h (InvocationHandler): InvocationHandler ๊ตฌํ˜„์ฒด๋ฅผ ๋„ฃ์–ด์ค€๋‹ค. ํ”„๋ก์‹œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ „๋‹ฌ๋ฐ›์€ Handler ๊ฐ์ฒด๊ฐ€ CRUD ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค.

stub (client proxy Dao)

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
48
public class DaoProxyGenerator {

  private String host;
  private int port;
  private Gson gson;

  public DaoProxyGenerator(String host, int port) {
    this.host = host;
    this.port = port;
    gson = new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
  }

  public <T> T create(Class<T> clazz, String dataName) {
    return (T) Proxy.newProxyInstance(DaoProxyGenerator.class.getClassLoader(),
      new Class<?>[] {clazz}, (proxy, method, args) -> {
        // ์„œ๋ฒ„์— ์š”์ฒญํ•  ๋•Œ๋งˆ๋‹ค ์—ฐ๊ฒฐํ•œ๋‹ค.
        try (Socket socket = new Socket(host, port);
          DataInputStream in = new DataInputStream(socket.getInputStream());
          DataOutputStream out = new DataOutputStream(socket.getOutputStream())) {
          out.writeUTF(dataName);
          out.writeUTF(method.getName());
          if (args == null) {
            out.writeUTF("");
          } else {
            out.writeUTF(gson.toJson(args[0]));
          }

          String code = in.readUTF();
          String entity = in.readUTF();

          if (!code.equals("200")) {
            throw new Exception(entity);
          }

          Type returnType = method.getGenericReturnType();

          if (returnType == void.class) {
            return null;
          } else {
            return gson.fromJson(entity, returnType);
          }
        } catch (Exception e) {
          e.printStackTrace();
          throw new DaoException(e);
        }
      });
  }
}

๊ธฐ์กด์— ์ข…์†์„ฑ์„ ์ฃผ์ž…ํ•˜๋Š” ๊ณผ์ •๊ณผ ๋‹ค๋ฅธ์ ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

DaoProxyGenerator ๋ผ๋Š” ํด๋ž˜์Šค์˜ ์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์—์„œ ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•ด ์ค€๋‹ค. ์ด๋Ÿฐ ๋ฐฉ์‹์„ ์ทจํ•จ์œผ๋กœ์จ ์ข€ ๋” ๋‚ฎ์€ ๊ฒฐํ•ฉ๋„๋ฅผ ๊ฐ–๊ฒŒ ๋˜์—ˆ๊ณ , dao ๊ฐ์ฒด ์ƒ์„ฑ ๋กœ์ง์„ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ๋ชจ๋‘ ์บก์Šํ™” ํ•จ์œผ๋กœ์จ ๋†’์€ ์‘์ง‘๋„๋ฅผ ๊ฐ–๊ฒŒ ๋˜์—ˆ๋‹ค. (low coupling, high cohesion)

๋งŒ์•ฝ ์ƒํ˜ธ์ž‘์šฉ(์ƒ์†, ํฌํ•จ, ๊ตฌํ˜„ ๋“ฑ)ํ•˜๋Š” ๊ฐ์ฒด๋“ค์ด ๋งŽ์•„์ง€๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ทธ ๋ชจ๋“  ๊ด€๊ณ„๋ฅผ ์ผ์ผ์ด ๊ธฐ์–ตํ•˜๊ณ  ์ฃผ์ž…ํ•ด ์ค€๋‹ค๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅ์— ๊ฐ€๊น๋‹ค.

์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์ด๋Ÿฌํ•œ ๊ณ ๋ฏผ์„ ๋ฆฌํ”Œ๋ ‰์…˜๊ณผ ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐํ•œ๋‹ค. ์Šคํ”„๋ง์—์„œ DI(Dependency Injection)๋Š” ์Šคํ”„๋ง IoC ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ด๋ฃจ์–ด์ง€๋Š”๋ฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ์™ธ๋ถ€ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฃผ์ž…๋œ๋‹ค. ๋ณต์žกํ•œ ์˜์กด ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ์Šคํ”„๋ง์—๊ฒŒ ์œ„์ž„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

ํ”„๋ก์‹œ๋Š” AOP(Aspect-Oriented Programming) ๋ฐ ๋Ÿฐํƒ€์ž„ ์‹œ ๋™์ ์œผ๋กœ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ ค๋Š” ๊ธฐํƒ€ ๋‹ค์–‘ํ•œ ๊ฒฝ์šฐ์™€ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์œ ์šฉํ•˜๋‹ค.

skeleton (ServerApp)

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
// ServerApp.class
public class ServerApp {
    ...
  
  // skeleton method
  void processRequest(DataInputStream in, DataOutputStream out) throws IOException {
    System.out.println("[ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ]");
    String dataName = in.readUTF();
    String command = in.readUTF();
    String value = in.readUTF();

    try {
      Object dao = daoMap.get(dataName);
      if (dao == null) {
        throw new RequestException("์š”์ฒญ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!");
      }
      System.out.printf("๋ฐ์ดํ„ฐ: %s\n", dataName);

      Method commandHandler = findMethod(dao.getClass(), command);
      System.out.printf("๋ฉ”์„œ๋“œ: %s\n", commandHandler.getName());

      Object[] args = getArguments(commandHandler, value);

      // ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
      Object returnValue = commandHandler.invoke(dao, args);

      out.writeUTF("200");
      out.writeUTF(gson.toJson(returnValue));
      System.out.println("ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‘๋‹ต ์™„๋ฃŒ!");

    } catch (RequestException e) {
      out.writeUTF("400");
      out.writeUTF(gson.toJson(e.getMessage()));

    } catch (Exception e) {
      out.writeUTF("500");
      out.writeUTF(gson.toJson(e.getMessage()));
    }
  }
}

skeleton(ServerApp) ์€ Dao ๊ตฌํ˜„์ฒด๋“ค์„ ๋ฏธ๋ฆฌ Map ์— ๋‹ด์•„๋’€๋‹ค๊ฐ€ stub ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ๋งˆ์ƒฌ๋ง ๋ฐ์ดํ„ฐ๊ฐ€ ์ „๋‹ฌ๋˜๋ฉด ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•ด ํ˜ธ์ถœํ•ด์•ผ ๋  Dao ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐพ์•„์„œ ํ˜ธ์ถœํ•œ๋‹ค.

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

app-api

1
2
3
4
5
6
7
8
9
10
11
12
app-api
โ””โ”€โ”€ src
    โ””โ”€โ”€ main
        โ”œโ”€โ”€ java
        โ”‚ย ย  โ””โ”€โ”€ bitcamp
        โ”‚ย ย      โ””โ”€โ”€ myapp
        โ”‚ย ย          โ””โ”€โ”€ dao
        โ”‚ย ย              โ””โ”€โ”€ DaoProxyGenerator.java
        โ””โ”€โ”€ resources
โ””โ”€โ”€ build.gradle

8 directories, 2 files

app-common

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
app-common
โ””โ”€โ”€ src
    โ””โ”€โ”€ main
        โ”œโ”€โ”€ java
        โ”‚ย ย  โ””โ”€โ”€ bitcamp
        โ”‚ย ย      โ””โ”€โ”€ myapp
        โ”‚ย ย          โ”œโ”€โ”€ dao
        โ”‚ย ย          โ”‚ย ย  โ”œโ”€โ”€ AssignmentDao.java
        โ”‚ย ย          โ”‚ย ย  โ”œโ”€โ”€ BoardDao.java
        โ”‚ย ย          โ”‚ย ย  โ”œโ”€โ”€ DaoException.java
        โ”‚ย ย          โ”‚ย ย  โ””โ”€โ”€ MemberDao.java
        โ”‚ย ย          โ””โ”€โ”€ vo
        โ”‚ย ย              โ”œโ”€โ”€ Assignment.java
        โ”‚ย ย              โ”œโ”€โ”€ Board.java
        โ”‚ย ย              โ””โ”€โ”€ Member.java
        โ””โ”€โ”€ resources
โ””โ”€โ”€ build.gradle

9 directories, 8 files

app-server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
app-server
โ””โ”€โ”€ src
    โ””โ”€โ”€ main
        โ”œโ”€โ”€ java
        โ”‚ย ย  โ””โ”€โ”€ bitcamp
        โ”‚ย ย      โ”œโ”€โ”€ RequestException.java
        โ”‚ย ย      โ””โ”€โ”€ myapp
        โ”‚ย ย          โ”œโ”€โ”€ ServerApp.java
        โ”‚ย ย          โ””โ”€โ”€ dao
        โ”‚ย ย              โ””โ”€โ”€ json
        โ”‚ย ย                  โ”œโ”€โ”€ AbstractDao.java
        โ”‚ย ย                  โ”œโ”€โ”€ AssignmentDaoImpl.java
        โ”‚ย ย                  โ”œโ”€โ”€ BoardDaoImpl.java
        โ”‚ย ย                  โ””โ”€โ”€ MemberDaoImpl.java
        โ””โ”€โ”€ resources
โ”œโ”€โ”€ assignment.json
โ”œโ”€โ”€ board.json
โ”œโ”€โ”€ build.gradle
โ”œโ”€โ”€ greeting.json
โ””โ”€โ”€ member.json

9 directories, 11 files

app-client

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
app-client
โ””โ”€โ”€ src
    โ””โ”€โ”€ main
        โ”œโ”€โ”€ java
        โ”‚ย ย  โ””โ”€โ”€ bitcamp
        โ”‚ย ย      โ”œโ”€โ”€ menu
        โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ AbstractMenu.java
        โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ AbstractMenuHandler.java
        โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ Menu.java
        โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ MenuGroup.java
        โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ MenuHandler.java
        โ”‚ย ย      โ”‚ย ย  โ””โ”€โ”€ MenuItem.java
        โ”‚ย ย      โ”œโ”€โ”€ myapp
        โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ ClientApp.java
        โ”‚ย ย      โ”‚ย ย  โ””โ”€โ”€ handler
        โ”‚ย ย      โ”‚ย ย      โ”œโ”€โ”€ HelpHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”œโ”€โ”€ assignment
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ AssignmentAddHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ AssignmentDeleteHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ AssignmentListHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ AssignmentModifyHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ””โ”€โ”€ AssignmentViewHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”œโ”€โ”€ board
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ BoardAddHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ BoardDeleteHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ BoardListHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ”œโ”€โ”€ BoardModifyHandler.java
        โ”‚ย ย      โ”‚ย ย      โ”‚ย ย  โ””โ”€โ”€ BoardViewHandler.java
        โ”‚ย ย      โ”‚ย ย      โ””โ”€โ”€ member
        โ”‚ย ย      โ”‚ย ย          โ”œโ”€โ”€ MemberAddHandler.java
        โ”‚ย ย      โ”‚ย ย          โ”œโ”€โ”€ MemberDeleteHandler.java
        โ”‚ย ย      โ”‚ย ย          โ”œโ”€โ”€ MemberListHandler.java
        โ”‚ย ย      โ”‚ย ย          โ”œโ”€โ”€ MemberModifyHandler.java
        โ”‚ย ย      โ”‚ย ย          โ””โ”€โ”€ MemberViewHandler.java
        โ”‚ย ย      โ””โ”€โ”€ util
        โ”‚ย ย          โ”œโ”€โ”€ AnsiEscape.java
        โ”‚ย ย          โ””โ”€โ”€ Prompt.java
        โ””โ”€โ”€ resources
โ””โ”€โ”€ build.gradle

13 directories, 26 files

์ข€ ๋” ์ฐพ์•„๋ณผ ๋‚ด์šฉ

์Šคํ”„๋ง์—์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

  • JDK Dynamic Proxy
  • CGLib

reference

๋ฐฉ๋ฌธํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋Œ“๊ธ€,์ง€์ ,ํ”ผ๋“œ๋ฐฑ ์–ธ์ œ๋‚˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜Š

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ