Spring Core Advanced
์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ณ ๊ธํธ ๊ฐ์๋ฅผ ์์ฝํ ๋ด์ฉ์ ๋๋ค.
โญ๏ธ ThreadLocal
๋์์ฑ ๋ฌธ์
๋ค์์ ์ฐ๋ ๋๊ฐ ๋์์ ๊ฐ์ ์ธ์คํด์ค ํ๋ ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด์ ๋ฐ์ํ๋ ๋ฌธ์
์คํ๋ง ๋น์ฒ๋ผ ์ฑ๊ธํค ๊ฐ์ฒด์ ํ๋๋ฅผ ๋ณ๊ฒฝํ๋ฉฐ ์ฌ์ฉํ ๋ ์ฃผ์
ThreadLocal
ํน์ ์ค๋ ๋๋ง ์ ๊ทผํ ์ ์๋ ํน๋ณํ ์ ์ฅ์
๊ฐ ์ค๋ ๋๋ง๋ค ๋ณ๋์ ๋ด๋ถ ์ ์ฅ์ ์ ๊ณต
ํน์ ์ค๋ ๋ ๋ก์ปฌ์ ๋ชจ๋ ์ฌ์ฉ๋ฉด
ThreadLocal.remove()ํธ์ถ๋ก ์ ์ฅ๋ ๊ฐ์ ๋ฐ๋์ ์ ๊ฑฐ์ค๋ ๋ ํ์ ์ฌ์ฉํ ๊ฒฝ์ฐ(ex. WAS) ์ค๋ ๋ ๋ก์ปฌ ๊ฐ์ ์ ๊ฑฐํ์ง ์์ผ๋ฉด, ์ฌ์ฉ์B๊ฐ ์ฌ์ฉ์A ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ฒ ๋๋ ๋ฌธ์ ๋ฐ์
์ค๋ ๋๋ ์ค๋ ๋ ํ์ ํตํด ์ฌ์ฌ์ฉ๋์ง ๋๋ฌธ์ ์ค๋ ๋ ๋ก์ปฌ์์ ์ ๊ฑฐ๋์ง ์๊ณ ๋จ์์๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ์กฐํํ ์ ์๊ฒ ๋๋ค.
Template Method Pattern
๋คํ์ฑ(์์๊ณผ ์ค๋ฒ๋ผ์ด๋ฉ)์ ํ์ฉํด์ ๋ณํ๋ ๋ถ๋ถ(ํต์ฌ ๊ธฐ๋ฅ)๊ณผ ๋ณํ์ง ์๋ ๋ถ๋ถ(๋ก๊ทธ ์ถ์ ๊ธฐ, ํธ๋์ญ์
..)์ ๋ถ๋ฆฌํ๋ ๋์์ธ ํจํด
๊ตฌ์กฐ

์ธ์คํด์ค ํธ์ถ ๊ณผ์

๋ถ๋ชจ ํด๋์ค์ ํ ํ๋ฆฟ(๋ณํ์ง ์๋ ๋ถ๋ถ)์ ์ ์ํ๊ณ , ์ผ๋ถ ๋ณ๊ฒฝ๋๋ ๋ก์ง์ ์์ ํด๋์ค์ ์ ์
์์ ํด๋์ค๊ฐ ์ ์ฒด ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ํน์ ๋ถ๋ถ๋ง ์ฌ์ ์
๊ฒฐ๊ตญ ์์๊ณผ ์ค๋ฒ๋ผ์ด๋ฉ์ ํตํ ๋คํ์ฑ์ผ๋ก ๋ฌธ์ ํด๊ฒฐ
ํด๋์ค๋ ๋จ ํ ๊ฐ์ ์ฑ ์์ ๊ฐ์ ธ์ผ ํ๋ค๋
๋จ์ผ ์ฑ ์ ์์น(Single Responsibility Principle)์ ์ ์งํค๋ ํจํด๋จ, ์์์์ ์ค๋ ๋จ์ ๋ค์ด ์กด์ฌ
๊ฐํ ์์กด์ฑ์ผ๋ก ๋ถ๋ชจ ํด๋์ค์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์๋๋ผ๋ ๋ถ๋ชจ ํด๋์ค๋ฅผ ์์์ผ ํ๊ณ
๋ถ๋ชจ ํด๋์ค๋ฅผ ์์ ํ๋ฉด ์์ ํด๋์ค์ ์ํฅ์ ์ค ์ ์์
์์ ๊ตฌ์กฐ๋ก ์ธํด ์์ฑ๋๋ ํด๋์ค๋ ์ต๋ช ๋ด๋ถ ํด๋์ค์ ๋ณต์ก์ฑ
์ต๋ช ๋ด๋ถ ํด๋์ค
์ง์ ์ด๋ฆ์ด ์๊ณ ํด๋์ค ๋ด๋ถ์ ์ ์ธ๋๋ ํด๋์ค
๊ฐ์ฒด ์ธ์คํด์ค ์์ฑ๊ณผ ๋์์ ์์ฑํ ํด๋์ค๋ฅผ ์์ ๋ฐ์ ์์ ํด๋์ค ์ ์
AbstractTemplate template1 = new AbstractTemplate() {
@Override
protected void call() {
log.info("๋น์ฆ๋์ค ๋ก์ง1 ์คํ");
}
};
log.info("ํด๋์ค ์ด๋ฆ1={}", template1.getClass()); // class hello...TemplateMethodTest$1
template1.execute();Template Example
public abstract class AbstractTemplate<T> {
private final LogTrace trace;
public AbstractTemplate(LogTrace trace) {
this.trace = trace;
}
public T execute(String message) {
TraceStatus status = null;
try {
status = trace.begin(message);
//๋ก์ง ํธ์ถ
T result = call();
trace.end(status);
return result;
} catch (Exception e) {
trace.exception(status, e);
throw e;
}
}
protected abstract T call();
}Strategy Pattern
Template Method Pattern ์ ์์์ผ๋ก ์ธํ ๋จ์ ์ ์์์ผ๋ก ํด๊ฒฐํ ๋์์ธ ํจํด
๊ตฌ์กฐ

์ ๋ต ํจํด ์คํ ๊ณผ์

๋ณํ์ง ์๋ ๋ถ๋ถ์ Context(๋ณํ์ง ์๋ ํ ํ๋ฆฟ)์, ๋ณํ๋ ๋ถ๋ถ์ Strategy(๋ณํ๋ ์๊ณ ๋ฆฌ์ฆ) ์ธํฐํ์ด์ค์ ๋๊ณ , ํด๋น ๊ตฌํ์ฒด๋ฅผ ํตํด ๋ฌธ์ ๋ฅผ ํด๊ฒฐ
Context์ ์ํ๋ Strategy ๊ตฌํ์ฒด ์ฃผ์
ํด๋ผ์ด์ธํธ๋ Context ์คํ
Context๋ Context ๋ก์ง ์์
Context ๋ก์ง ์ค๊ฐ์ strategy.call() ํธ์ถ๋ก ์ฃผ์ ๋ฐ์ Strategy ๋ก์ง ์คํ
Context๋ ๋๋จธ์ง ๋ก์ง ์คํ
์ต๋ช ํด๋์ค ์ฌ์ฉ
Context/Strategy ์ ์กฐ๋ฆฝ, ํ ์คํ ๋ฐฉ์์ ์ ํฉ
ํ๋์ Strategy ์ ์ฅ ๋ฐฉ์์ ์ ๋ต ํจํด
ํ ๋ฒ ์กฐ๋ฆฝ ์ดํ Context ์คํ๋ง ํ๋ฉด ๋
์คํ๋ง ๋ก๋ฉ ์์ ์ ์์กด๊ด๊ณ ์ฃผ์ ์ ํตํด ์กฐ๋ฆฝ ํ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๊ฒ๊ณผ ์ ์ฌ
๋จ์ ์, ์กฐ๋ฆฝ ์ดํ์ ์ ๋ต ๋ณ๊ฒฝ์ด ๋ฒ๊ฑฐ๋ก์ (์ฑ๊ธํค ์ฌ์ฉ ์ ๋์์ฑ ์ด์ ๋ฑ ๊ณ ๋ ค ์ฌํญ์ด ์กด์ฌ)
Template Callback Pattern
์ ๋ต์ ํ๋๋ก ๊ฐ์ง์ง ์๊ณ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ
์ ๋ต ํจํด์์ ํ ํ๋ฆฟ๊ณผ ์ฝ๋ฐฑ ๋ถ๋ถ์ด ๊ฐ์กฐ๋ ํจํด(GOF ํจํด์ ์๋๊ณ ์คํ๋ง ๋ด๋ถ์์ ๋ถ๋ฆฌ์)
์ฝ๋๊ฐ Call ์ดํ ์ฝ๋๋ฅผ ๋๊ฒจ์ค ๊ณณ์ Back ์์ ์คํ(CallBack..)
์คํ๋ง์์ XxxTemplate(JdbcTemplate, RestTemplate, TransactionTemplate, RedisTemplate) ํํ๋ ํ ํ๋ฆฟ ์ฝ๋ฐฑ ํจํด์ด ์ฌ์ฉ๋์ด ๋ง๋ค์ด์ง ํด๋์ค

ํ๋ผ๋ฏธํฐ์ Strategy ์ ๋ฌ ๋ฐฉ์์ ์ ๋ต ํจํด
์คํํ ๋๋ง๋ค ์ ๋ต์ ์ ์ฐํ๊ฒ ๋ณ๊ฒฝ
๋จ์ ์, ์คํํ ๋๋ง๋ค ์ ๋ต์ ๊ณ์ ์ง์ ํด ์ฃผ์ด์ผ ํ๋ ๋ฒ๊ฑฐ๋ก์
์ฝ๋ฐฑ์ ์ฌ์ฉํ ๊ฒฝ์ฐ ์ต๋ช ๋ด๋ถ ํด๋์ค๋ ๋๋ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ํธ๋ฆฌ
๋จ, ์ฌ๋ฌ ๊ณณ์์ ํจ๊ป ์ฌ์ฉ๋ ๊ฒฝ์ฐ ์ฌ์ฌ์ฉ์ ์ํด ์ฝ๋ฐฑ์ ๋ณ๋์ ํด๋์ค๋ก ๋ง๋๋๊ฒ ์ข์
Context -> Template
Strategy -> Callback
Example
์ ์ฉ
Proxy
ํ๋ก์์ ์ฃผ์ ๊ธฐ๋ฅ
์ ๊ทผ ์ ์ด๊ถํ์ ๋ฐ๋ฅธ ์ ๊ทผ ์ฐจ๋จ
์บ์ฑ
์ง์ฐ ๋ก๋ฉ
๋ถ๊ฐ ๊ธฐ๋ฅ ์ถ๊ฐ๊ธฐ์กด ์ ๊ณต ๊ธฐ๋ฅ์ ๋ถ๊ฐ ๊ธฐ๋ฅ ์ํ
ex. ์์ฒญ/์๋ต ๊ฐ ๋ณํ, ์ถ๊ฐ ๋ก๊ทธ
๋จ์
๋์ ํด๋์ค๋ง ๋ค๋ฅผ ๋ฟ ๋ก์ง์ ์ ์ฌํ๊ณ , ๋์ ํด๋์ค ๊ฐ์๋งํผ ํ๋ก์ ํด๋์ค ์์ฑ ํ์
๋์ ํ๋ก์ ๊ธฐ์์ ํตํด ํ๋ก์ ํด๋์ค๋ฅผ ํ๋๋ง ๋ง๋ค์ด์ ๋ชจ๋ ๊ณณ์ ์ ์ฉ ๊ฐ๋ฅ
Proxy Pattern
ํ๋ก์๋ฅผ ์ ์ฉํ์ฌ ์ ๊ทผ์ ์ ์ดํ๋ ํจํด
์๋(intent) : ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ํ ์ ๊ทผ์ ์ ์ดํ๊ธฐ ์ํด ๋๋ฆฌ์ ์ ๊ณต

์ค์ ๊ฐ์ฒด์ ํด๋ผ์ด์ธํธ์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ํ๋ก์ ๋์ ์ผ๋ก ์ ๊ทผ์ ์ ์ด
์ค์ ํด๋ผ์ด์ธํธ ์ ์ฅ์์ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ฃผ์ ๋์๋์ง, ์ค์ ๊ฐ์ฒด๊ฐ ์ฃผ์ ๋์๋์ง ์ ์ ์์
ํ๋ก์ ๊ฐ์ฒด
@Slf4j
public class CacheProxy implements Subject {
private Subject target; // ํ๋ก์๊ฐ ํธ์ถํ๋ ๋์
private String cacheValue;
public CacheProxy(Subject target) {
this.target = target;
}
/**
* ํ๋ก์๋ ์ค์ ๊ฐ์ฒด์ ๋ชจ์์ด ๊ฐ์์ผ ํ๋ฏ๋ก ์ธํฐํ์ด์ค ๊ตฌํ
*/
@Override
public String operation() {
log.info("ํ๋ก์ ํธ์ถ");
if (cacheValue == null) {
// ํด๋ผ์ด์ธํธ๊ฐ ํ๋ก์๋ฅผ ํธ์ถํ๋ฉด ํ๋ก์๊ฐ ์ต์ข
์ ์ผ๋ก ์ค์ ๊ฐ์ฒด ํธ์ถ
cacheValue = target.operation();
}
return cacheValue;
}
}ํ๋ก์ ๊ฐ์ฒด ์ ์ฉ
Subject realSubject = new RealSubject(); // ์ค์ ๊ฐ์ฒด
Subject cacheProxy = new CacheProxy(realSubject); // ์ค์ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์ ๋ฌ
ProxyPatternClient client = new ProxyPatternClient(cacheProxy); // ํ๋ก์ ๊ฐ์ฒด ์ฃผ์
client.execute(); // ์ดํ์๋ ์บ์ ๋ฐ์ดํฐ ๋ฐํ
client.execute();
client.execute();Decorator Pattern
ํ๋ก์๋ฅผ ์ ์ฉํ์ฌ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ํจํด
์๋(intent) : ๊ฐ์ฒด์ ์ถ๊ฐ ์ฑ ์(๊ธฐ๋ฅ)์ ๋์ ์ผ๋ก ์ถ๊ฐํ๊ณ , ๊ธฐ๋ฅ ํ์ฅ์ ์ํ ์ ์ฐํ ๋์ ์ ๊ณต

client -> messageDecorator(proxy) -> realComponent ๊ฐ์ฒด ์์กด
client -> timeDecorator(proxy) -> messageDecorator(proxy) -> realComponent ๊ฐ์ฒด ์์กด
์ ์ฉ
ํ๋ก์๋ฅผ ์ฌ์ฉํด ๊ธฐ์กด ์ฝ๋๋ฅผ ์์ ํ์ง ์๊ณ ์๋ก์ด ๊ธฐ๋ฅ์ ๋์
์ค์ ๊ฐ์ฒด ๋์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก(ํ๋ก์ ๋ด๋ถ์์ ์ค์ ๊ฐ์ฒด ์ฐธ์กฐ)
ํ๋ก์ ๊ฐ์ฒด๋ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์คํ๋ง ๋น์ผ๋ก ๊ด๋ฆฌํ๊ณ ์๋ฐ ํ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ๋ ๋ฐ๋ฉด์ค์ ๊ฐ์ฒด๋ ์๋ฐ ํ ๋ฉ๋ชจ๋ฆฌ์๋ ์ฌ๋ผ๊ฐ์ง๋ง ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํ์ง ์์ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํตํด์ ์ฐธ์กฐ๋๋ ์กด์ฌ
์ธํฐํ์ด์ค์ ๊ตฌํ ํด๋์ค(์คํ๋ง ๋น ์๋ ๋ฑ๋ก)
์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ก์ ๋์
ํ๋ก์ ํด๋์ค๋ฅผ ๋ค์ ์์ฑํด์ผ ํ๋ ๋จ์ ์กด์ฌ
์ธํฐํ์ด์ค ์๋ ๊ตฌ์ฒด ํด๋์ค(์คํ๋ง ๋น ์๋ ๋ฑ๋ก)
ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์ ๋์
์ธํฐํ์ด์ค๊ฐ ์๋๋ผ๋ ๋คํ์ฑ์ผ๋ก ํด๋์ค๋ฅผ ์์๋ฐ์์ ํ๋ก์๋ฅผ ์ ์ฉ
์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ก์์ ๋นํด ์ฌ๋ฌ ๋จ์ ์ด ์กด์ฌ
๋ถ๋ชจ ํด๋์ค์ ์์ฑ์ ํธ์ถ ํ์
final ํด๋์ค ์์ ๋ถ๊ฐ
final ๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋ฉ ๋ถ๊ฐ
์ปดํฌ๋ํธ ์ค์บ ์คํ๋ง ๋น ์๋ ๋ฑ๋ก
๋์ ํ๋ก์
๋ฆฌํ๋ ์
ํด๋์ค/๋ฉ์๋
๋ฉํ์ ๋ณด๋ฅผ๋์ ์ผ๋ก ํ๋ํ๊ณ , ์ฝ๋๋ฅผ๋์ ์ผ๋ก ํธ์ถ๋ฐํ์์ ๋์ํ๋ฏ๋ก ์ปดํ์ผ ์์ ์ ์ค๋ฅ๋ฅผ ์ก์ ์ ์๋ ๋จ์
์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข๊ณ , ํ๋ ์์ํฌ ๊ฐ๋ฐ์ด๋ ์ผ๋ฐ์ ์ธ ๊ณตํต ์ฒ๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ ๋ถ๋ถ์ ์ผ๋ก ์ฃผ์ํด์ ์ฌ์ฉ
@Test
void reflectionTest() throws Exception {
Class classHello = Class.forName("hello.proxy.jdkdynamic.ReflectionTest$Hello"); // ํด๋์ค ๋ฉํ ์ ๋ณด ํ๋
Hello target = new Hello();
Method methodCallA = classHello.getMethod("callMethodA"); // ๋ฉ์๋ ๋ฉํ ์ ๋ณด ํ๋
dynamicCall(methodCallA, target);
Method methodCallB = classHello.getMethod("callMethodB");
dynamicCall(methodCallB, target);
}
private void dynamicCall(Method method, Object target) throws Exception {
Object result = method.invoke(target); // ํ๋ํ ๋ฉ์๋ ๋ฉํ ์ ๋ณด๋ก ์ค์ ์ธ์คํด์ค์ ๋ฉ์๋ ํธ์ถ
}JDK ๋์ ํ๋ก์
๋์ ํด๋์ค์ ์ธํฐํ์ด์ค๊ฐ ์์ ๊ฒฝ์ฐ(์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ก์)
์ธํฐํ์ด์ค ๊ธฐ๋ฐ๋์ ํ๋ก์ ์์ฑ(๋ฐํ์)๊ฐ๊ฐ์ ๋์ ๊ฐ์ฒด ํ๋ก์๋ฅผ ์ง์ ๋ง๋ค์ง ์๊ณ , ํ๋ก์ ๋์ ์์ฑ(JDK ๋์ ํ๋ก์) ํ
InvocationHandler์ธํฐํ์ด์ค ๊ตฌํ์ฒด(ํ๋ก์ ๋ก์ง ์ ์) ํ๋๋ฅผ ๊ณตํต ์ฌ์ฉ๋์ ํ๋ก์๋ ํธ๋ค๋ฌ ๋ก์ง๋ง ํธ์ถํ๊ณ ๋ฉ์๋์ ์ธ์๋ฅผ ๊ฐ์ง๊ณ ์คํ
๊ฐ์ฒด์ ์ธํฐํ์ด์ค๊ฐ ๋ฐ๋์ ํ์ํด์, ํด๋์ค๋ง ์๋ ๊ฒฝ์ฐ์๋ ์ ์ฉํ ์ ์๋ ํ๊ณ
InvocationHandler.java
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}TimeInvocationHandler.java (InvocationHandler ์ธํฐํ์ด์ค ๊ตฌํ์ฒด)
Object proxy : ํ๋ก์ ์์
Method method : ํธ์ถํ ๋ฉ์๋
Object[] args : ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ์ ๋ฌํ ์ธ์
@Slf4j
public class TimeInvocationHandler implements InvocationHandler {
private final Object target;
public TimeInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("TimeProxy ์คํ");
long startTime = System.currentTimeMillis();
Object result = method.invoke(target, args);
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy ์ข
๋ฃ resultTime={}", resultTime);
return result;
}
}์ ์ฉ ์์
@Test
void dynamic() {
AInterface target = new AImpl();
TimeInvocationHandler handler = new TimeInvocationHandler(target);
/**
* Proxy.newProxyInstance (๋์ ํ๋ก์ ์์ฑ)
*
* ClassLoader loader, Class<?>[] interfaces, InvocationHandler h
* ํด๋์ค ๋ก๋ ์ ๋ณด, ์ธํฐํ์ด์ค, ํธ๋ค๋ฌ ๋ก์ง
*
* ํด๋น ์ธํฐํ์ด์ค ๊ธฐ๋ฐ์ผ๋ก ๋์ ํ๋ก์ ์์ฑ ๋ฐ ํธ๋ค๋ฌ ๋ก์ง์ ๊ฒฐ๊ณผ ๋ฐํ
*/
AInterface proxy = (AInterface) Proxy.newProxyInstance(AInterface.class.getClassLoader(), new Class[]{AInterface.class}, handler);
proxy.call();
log.info("targetClass={}", target.getClass()); // targetClass=class hello.proxy.jdkdynamic.code.AImpl
log.info("proxyClass={}", proxy.getClass()); // proxyClass=class com.sun.proxy.$Proxy12
}์คํ ์์
JDK ๋์ ํ๋ก์์ call() ์คํ
proxy.call();JDK ๋์ ํ๋ก์๋
InvocationHandler.invoke()ํธ์ถTimeInvocationHandler ๋ด๋ถ ๋ก์ง ์ํ ๋ฐ
method.invoke(target, args)ํธ์ถ.target์ ์ค์ ๊ฐ์ฒด AImpl ์ธ์คํด์ค์
call()์คํAImpl ์ธ์คํด์ค์ call() ์คํ์ด ๋๋๋ฉด TimeInvocationHandler ์๋ต
์ ์ฉ

CGLIB
๋์ ํด๋์ค์ ์ธํฐํ์ด์ค๊ฐ ์์ ๊ฒฝ์ฐ(๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์)
์ธํฐํ์ด์ค ์์ด
๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ(์์) ๋์ ํ๋ก์ ์์ฑ์์ ์ฌ์ฉ์ผ๋ก ์ธํ ์ ์ฝ
๋ถ๋ชจ ํด๋์ค์ ๊ธฐ๋ณธ ์์ฑ์ ํ์
final ํด๋์ค๋ ์์ ๋ถ๊ฐ
final ๋ฉ์๋๋ ์ค๋ฒ๋ผ์ด๋ฉ ๋ถ๊ฐ
JDK ๋์ ํ๋ก์ ์คํ ๋ก์ง์ InvocationHandler๋ฅผ ์ ๊ณตํ๋ฏ,
MethodInterceptor์ ๊ณต
MethodInterceptor.java
package org.springframework.cglib.proxy;
/**
* obj : CGLIB ์ ์ฉ ๊ฐ์ฒด
* method : ํธ์ถ๋ ๋ฉ์๋
* args : ๋ฉ์๋ ํธ์ถ์ ์ ๋ฌ๋ ์ธ์
* proxy : ๋ฉ์๋ ํธ์ถ์ ์ฌ์ฉ
*/
public interface MethodInterceptor extends Callback {
Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = proxy.invoke(target, args); // ์ค์ ๋์ ๋์ ํธ์ถ(CGLIB๋ ์ฑ๋ฅ์ Method ๋์ MethodProxy ์ฌ์ฉ)
return result;
}Spring Proxy Factory
ํ๋ก์ ์์ฑ์ ProxyFactory ๋ก์ง์ Advice
๋จ์ ๋ฌธ์ ์ .. -> ๋น ํ์ฒ๋ฆฌ๊ธฐ๋ก ์ฒ๋ฆฌ ๊ฐ๋ฅ
๋๋ฌด ๋ง์ ์ค์ ์ด ํ์
์คํ๋ง ๋น์ด 100๊ฐ ์๋ค๋ฉด, ํ๋ก์ ๋ถ๊ฐ ๊ธฐ๋ฅ ์ ์ฉ์ ์ํด 100๊ฐ์ ๋์ ํ๋ก์ ์์ฑ ํ์
์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ Proxy Factory ์ ์ฉ ๋ถ๊ฐ๋ฅ
์ค์ ๊ฐ์ฒด๊ฐ ์คํ๋ง ์ปจํ ์ด๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋ ์ํ์ด๋ฏ๋ก
ใ ์ธํฐํ์ด์ค๊ฐ ์๋ ๊ฒฝ์ฐ JDK ๋์ ํ๋ก์, ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ CGLIB ์ ์ฉ
๋์ ํ๋ก์๋ฅผ ํตํฉํด์ ๋ง๋ค์ด์ฃผ๋
ProxyFactory์ ๊ณต์ธํฐํ์ด์ค๊ฐ ์์ผ๋ฉด JDK ๋์ ํ๋ก์ ์ฌ์ฉ, ๊ตฌ์ฒด ํด๋์ค๋ง ์๋ค๋ฉด CGLIB ์ฌ์ฉ(default)

ใ JDK ๋์ ํ๋ก์, CGLIB ๋ฅผ ํจ๊ป ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ถ๊ฐ ๊ธฐ๋ฅ ์ ์ฉ
InvocationHandler,MethodInterceptor ๋ฅผ ์ ๊ฒฝ์ฐ์ง ์๊ณ ,
Advice๋ง ์์ฑorg.aopalliance.intercept.
MethodInterceptor๊ตฌํ์ผ๋ก Advice ์์ฑ

ใ ํน์ ์กฐ๊ฑด์ ํ๋ก์ ๋ก์ง์ ์ ์ฉํ๋ ๊ณตํต ๊ธฐ๋ฅ
Pointcut๊ฐ๋ ๋์ ์ผ๋ก ์ผ๊ด์ฑ์๊ฒ ํด๊ฒฐ
/** new ProxyFactory(target)
* ํ๋ก์ ํธ์ถ ๋์์ ํจ๊ป ์ ๋ฌ
* target ์ธ์คํด์ค์ ์ธํฐํ์ด์ค๊ฐ ์๋ค๋ฉด, JDK ๋์ ํ๋ก์๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉ
* ์ธํฐํ์ด์ค๊ฐ ์๊ณ ๊ตฌ์ฒด ํด๋์ค๋ง ์๋ค๋ฉด, CGLIB๋ฅผ ํตํด์ ๋์ ํ๋ก์๋ฅผ ์์ฑ
*/
ProxyFactory proxyFactory = new ProxyFactory(target);
/** setProxyTargetClass(true)
* ์ธํฐํ์ด์ค๊ฐ ์์ด๋ CGLIB ์ฌ์ฉ ๋ฐ ํ๊ฒ ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์(CGLIB) ์ฌ์ฉ
*/
proxyFactory.setProxyTargetClass(true);
/** .addAdvice(new TimeAdvice())
* ํ๋ก์ ํฉํ ๋ฆฌ๋ฅผ ํตํด์ ๋ง๋ ํ๋ก์๊ฐ ์ฌ์ฉํ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง์ ์ค์
* JDK ๋์ ํ๋ก์๊ฐ ์ ๊ณตํ๋ InvocationHandler ์ CGLIB๊ฐ ์ ๊ณตํ๋ MethodInterceptor ์ ๊ฐ๋
๊ณผ ์ ์ฌ
*/
proxyFactory.addAdvice(new TimeAdvice());
/** proxyFactory.getProxy()
* ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ทธ ๊ฒฐ๊ณผ ๋ฐํ
*/
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();MethodInterceptor ๊ตฌํ์ผ๋ก Advice ์์ฑ ์์
Spring Proxy Factory ์ฌ์ฉ ์์
Pointcut, Advice, Advisor
ํต์ฌ. ํ๋์ Target ์ ์ฌ๋ฌ AOP๊ฐ ๋์์ ์ ์ฉ๋์ด๋, ์คํ๋ง์ AOP๋ Target ๋ง๋ค ํ๋์ ํ๋ก์๋ง ์์ฑ

Pointcut : ๋์ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ํํฐ ์ญํ
๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ด๋ ๊ณณ์ ์ ์ฉ/๋ฏธ์ ์ฉํ ์ง ํ๋จํ๋ ํํฐ๋ง ๋ก์ง
์ฃผ๋ก ํด๋์ค์ ๋ฉ์๋ ์ด๋ฆ์ผ๋ก ํํฐ๋ง
์คํ๋ง์ด ์ ๊ณตํ๋ ๋ํ์ ์ธ Pointcut
AspectJExpressionPointcut: aspectJ ํํ์ ๋งค์นญ (์ค๋ฌด์์ ์ฃผ๋ก ๋ง์ด ์ฌ์ฉ)NameMatchMethodPointcut: ๋ฉ์๋ ์ด๋ฆ ๊ธฐ๋ฐ ๋งค์นญํ๋คJdkRegexpMethodPointcut: JDK ์ ๊ท ํํ์ ๊ธฐ๋ฐ ๋งค์นญTruePointcut: ํญ์ ์ฐธ ๋ฐํAnnotationMatchingPointcut: ์ ๋ ธํ ์ด์ ๋งค์นญ
Pointcut ์ ๋ ๊ฐ์ง ์ญํ โผ๏ธ
์์ฑ ๋จ๊ณ-> ํ๋ก์ ์ ์ฉ ์ฌ๋ถ ํ๋จ (ํด๋์ค, ๋ฉ์๋ ์กฐ๊ฑด ๋ชจ๋ ๋น๊ต)์ฌ์ฉ ๋จ๊ณ-> advice(๋ถ๊ฐ ๊ธฐ๋ฅ) ์ ์ฉ ์ฌ๋ถ ํ๋จ
Advice : ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง ๋ด๋น
ํ๋ก์๊ฐ ํธ์ถํ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ(=ํ๋ก์ ๋ก์ง)
Advisor : ํ๋์ Pointcut, ํ๋์ Advice๋ฅผ ๊ฐ๋ ๊ฒ
์กฐ์ธ(
Advice)์ ์ด๋(Pointcut)์ ํ ๊ฒ์ธ๊ฐ?์กฐ์ธ์(
Advisor)๋ ์ด๋(Pointcut)์ ์กฐ์ธ(Advice)์ ํด์ผํ ์ง ์๊ณ ์๋ค.
ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(Pointcut.TRUE, new TimeAdvice()); // Advisor ์ธํฐํ์ด์ค์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ๊ตฌํ์ฒด
proxyFactory.addAdvisor(advisor);
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();โญ๏ธ BeanPostProcessor
๋น ์ ์ฅ์์ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ๊ธฐ ์ง์ ์กฐ์์ ํ๊ณ ์ถ์ ๊ฒฝ์ฐ ๋น ํ์ฒ๋ฆฌ๊ธฐ(BeanPostProcessor)๋ฅผ ์ฌ์ฉ(๋น ์์ฑ ํ ์ฒ๋ฆฌ ์ฉ๋)
Spring Proxy Factory ์ ๋จ์ (๋ง์ ์ค์ , ์ปดํฌ๋ํธ ์ค์บ ๋์ ๊ฐ์ฒด ์ ์ฉ์ ์ด๋ ค์)์ ํด๊ฒฐ

์์ฑ: ์คํ๋ง ๋น ๋์ ๊ฐ์ฒด ์์ฑ(@Bean, @ComponentScan..)์ ๋ฌ: ์์ฑ๋ ๊ฐ์ฒด๋ฅผ ๋น ์ ์ฅ์์ ๋ฑ๋กํ๊ธฐ ์ง์ ์ ๋น ํ์ฒ๋ฆฌ๊ธฐ์ ์ ๋ฌํ ์ฒ๋ฆฌ ์์: ๋น ํ์ฒ๋ฆฌ๊ธฐ๋ ์ ๋ฌ๋ ์คํ๋ง ๋น ๊ฐ์ฒด๋ฅผ ์กฐ์ํ๊ฑฐ๋ ๋ค๋ฅธ ๊ฐ์ฒด๋ก ๋ฐ๋์น๊ธฐ ๊ฐ๋ฅ๋ฑ๋ก: ๋น ํ์ฒ๋ฆฌ๊ธฐ๋ ๋น ๋ฐํ. ์ ๋ฌ ๋ ๋น์ ๊ทธ๋๋ก ๋ฐํํ๋ฉด ํด๋น ๋น์ด ๋ฑ๋ก๋๊ณ , ๋ฐ๊ฟ์น๊ธฐ ํ๋ฉด ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ๋น ์ ์ฅ์์ ๋ฑ๋ก
BeanPostProcessor interface
๋น ํ์ฒ๋ฆฌ๊ธฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด
BeanPostProcessor์ธํฐํ์ด์ค ๊ตฌํ ํ ์คํ๋ง ๋น ๋ฑ๋กpostProcessBeforeInitialization: ๊ฐ์ฒด ์์ฑ ์ดํ @PostConstruct ๊ฐ์ ์ด๊ธฐํ ๋ฐ์ ์ ํธ์ถ๋๋ ํฌ์คํธ ํ๋ก์ธ์postProcessAfterInitialization: ๊ฐ์ฒด ์์ฑ ์ดํ @PostConstruct ๊ฐ์ ์ด๊ธฐํ ๋ฐ์ ํ ํธ์ถ๋๋ ํฌ์คํธ ํ๋ก์ธ์
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws
BeansException
Object postProcessAfterInitialization(Object bean, String beanName) throws
BeansException
}์ ์ฉ
BeanPostProcessor ๋ฅผ ์ฌ์ฉํด์ ์ค์ ๊ฐ์ฒด ๋์ ํ๋ก์๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก ๊ฐ๋ฅ
์๋ ๋ฑ๋ก ๋น์ ํฌํจํ์ฌ ์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉํ๋ ๋น๊น์ง ๋ชจ๋ ํ๋ก์ ์ ์ฉ์ด ๊ฐ๋ฅ
์ค์ ํ์ผ์์ ํ๋ก์๋ฅผ ์์ฑํ๋ ์ฝ๋๊ฐ ๋ถํ์

์คํ๋ง ์ ๊ณต ๋น ํ์ฒ๋ฆฌ๊ธฐ
์คํ๋ง AOP ๋ Pointcut ์ ์ฌ์ฉํด์ ํ๋ก์ ์ ์ฉ ๋์ ์ฌ๋ถ ์ฒดํฌ
ํ๋ก์๊ฐ ํ์ํ ๊ณณ์๋ง ํ๋ก์ ์ ์ฉ
ํ๋ก์ ๋ด๋ถ ํน์ ๋ฉ์๋๊ฐ ํธ์ถ ๋์์ ๋ ์ด๋๋ฐ์ด์ค ์ ์ฉ
์์กด์ฑ ์ถ๊ฐ๋ก
implementation 'org.springframework.boot:spring-boot-starter-aop'aspectjweaver: aspectJ ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ๋ก ๋ฐ ์คํ๋ง ๋ถํธ๊ฐ AOP ๊ด๋ จ ํด๋์ค๋ฅผ ์๋์ผ๋ก ์คํ๋ง ๋น์ ๋ฑ๋กAnnotationAwareAspectJAutoProxyCreator๋น ํ์ฒ๋ฆฌ๊ธฐ๊ฐ ์คํ๋ง ๋น์ ์๋์ผ๋ก ๋ฑ๋ก
AutoProxyCreator

์๋์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํด์ฃผ๋ ๋น ํ์ฒ๋ฆฌ๊ธฐ
์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋ Advisor ๋ค์ ์๋์ผ๋ก ์ฐพ์์ ํ๋ก์๊ฐ ํ์ํ ๊ณณ์ ์๋์ผ๋ก ํ๋ก์ ์ ์ฉ
ํ๋ก์๋ฅผ ๋ชจ๋ ๊ณณ์ ์์ฑํ๋ ๊ฒ์ ๋น์ฉ ๋ญ๋น์ด๋ฏ๋ก ํฌ์ธํธ์ปท์ผ๋ก ํํฐ๋ง ํ ํ์ํ ๊ณณ์ ์ต์ํ์ ํ๋ก์ ์ ์ฉ
Advisor1, Advisor2, 3, 4.. ๊ฐ ์ ๊ณตํ๋ ํฌ์ธํธ์ปท์ ์กฐ๊ฑด์ ๋ชจ๋ ๋ง์กฑํ๋๋ผ๋ ํ๋ก์๋ฅผ ํ ๊ฐ๋ง ์์ฑํ๊ณ ํ๋ก์๋ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์ฌ๋ฌ Advisor๋ฅผ ์์
์คํ๋ง์ด ์ ๊ณตํ๋ ๋น ํ์ฒ๋ฆฌ๊ธฐ ์ ์ฉ
AspectJExpressionPointcut
AOP์ ํนํ๋ ์ ๋ฐํ ํฌ์ธํธ์ปท ํํ์(AspectJ) ์ ์ฉ
/** package ๊ธฐ์ค ํฌ์ธํธ์ปท ์ ์ฉ
* AspectJExpressionPointcut : AspectJ ํฌ์ธํธ์ปท ํํ์ ์ ์ฉ
* execution(* hello.proxy.app..*(..)) : AspectJ๊ฐ ์ ๊ณตํ๋ ํฌ์ธํธ์ปท ํํ์
* * : ๋ชจ๋ ๋ฐํ ํ์
* hello.proxy.app.. : ํด๋น ํจํค์ง์ ๊ทธ ํ์ ํจํค์ง
* *(..) : * ๋ชจ๋ ๋ฉ์๋ ์ด๋ฆ, (..) ํ๋ผ๋ฏธํฐ๋ ์๊ด ์์
* -> hello.proxy.app ํจํค์ง์ ๊ทธ ํ์ ํจํค์ง์ ๋ชจ๋ ๋ฉ์๋๋ ํฌ์ธํธ์ปท์ ๋งค์นญ ๋์
*/
@Bean
public Advisor advisor2(LogTrace logTrace) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* hello.proxy.app..*(..))");
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
//advisor = pointcut + advice
return new DefaultPointcutAdvisor(pointcut, advice);
}
/** method ๊ธฐ์ค ํฌ์ธํธ์ปท ์ ์ฉ
* hello.proxy.app ํจํค์ง์ ํ์ ํจํค์ง์ ๋ชจ๋ ๋ฉ์๋๋ ํฌ์ธํธ์ปท์ ๋งค์นญํ๋,
* noLog() ๋ฉ์๋๋ ์ ์ธ
*/
@Bean
public Advisor advisor3(LogTrace logTrace) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))");
LogTraceAdvice advice = new LogTraceAdvice(logTrace);
//advisor = pointcut + advice
return new DefaultPointcutAdvisor(pointcut, advice);
}์คํ๋ง์ ํ๋ก์๋ฅผ ์ ์ฉํ๋ ค๋ฉด Advisor(pointcut, advice ๋ก ๊ตฌ์ฑ)๋ฅผ ๋ง๋ค์ด์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ฉด ์๋ ํ๋ก์ ์์ฑ๊ธฐ๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ
์๋ ํ๋ก์ ์์ฑ๊ธฐ๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋ Advisor ๋ค์ ์ฐพ๊ณ , ์คํ๋ง ๋น๋ค์ ์๋์ผ๋ก ํฌ์ธํธ์ปท์ด ๋งค์นญ๋๋ ๊ฒฝ์ฐ ํ๋ก์๋ฅผ ์ ์ฉ
@Aspect ์ ๋
ธํ
์ด์
์ ์ฌ์ฉํด์ ๋ ํธ๋ฆฌํ๊ฒ pointcut ๊ณผ advice ๋ฅผ ๋ง๋ค๊ณ ํ๋ก์์ ์ ์ฉํ ์ ์๋ค.
โญ๏ธ @Aspect Proxy
@Aspect์ ๋ ธํ ์ด์ ์ผ๋ก pointcut ๊ณผ advice ๋ก ๊ตฌ์ฑ๋์ด ์๋ Advisor ์ ํธ๋ฆฌํ ์์ฑ ์ง์์๋ ํ๋ก์ ์์ฑ๊ธฐ(AnnotationAwareAspectJAutoProxyCreator)๋ฅผ ํตํด @Aspect ๋ฅผ ์ฐพ์์ Advisor ๋ก ๋ณํ/์ ์ฅ, Advisor ๊ธฐ๋ฐ์ผ๋ก ํ์ํ ๊ณณ์ ํ๋ก์๋ฅผ ์์ฑ

@Aspect -> Advisor ๋ณํ ๊ณผ์
์คํ: ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ๋ก๋ฉ ์์ ์ ์๋ ํ๋ก์ ์์ฑ๊ธฐ ํธ์ถ
๋ชจ๋ @Aspect ๋น ์กฐํ: ์๋ ํ๋ก์ ์์ฑ๊ธฐ๋ ์คํ๋ง ์ปจํ ์ด๋์์ @Aspect ์ด ๋ถ์ ์คํ๋ง ๋น์ ๋ชจ๋ ์กฐํ
์ด๋๋ฐ์ด์ ์์ฑ: @Aspect ์ด๋๋ฐ์ด์ ๋น๋(BeanFactoryAspectJAdvisorsBuilder)๋ฅผ ํตํด @Aspect ์ ๋ ธํ ์ด์ ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ด๋๋ฐ์ด์ ์์ฑ
@Aspect ๊ธฐ๋ฐ ์ด๋๋ฐ์ด์ ์ ์ฅ: ์์ฑํ ์ด๋๋ฐ์ด์ ๋ฅผ @Aspect ์ด๋๋ฐ์ด์ ๋น๋ ๋ด๋ถ์ ์ ์ฅ
@Aspect ์ด๋๋ฐ์ด์ ๋น๋(BeanFactoryAspectJAdvisorsBuilder)
@Aspect ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฌ์ธํธ์ปท, ์ด๋๋ฐ์ด์ค, ์ด๋๋ฐ์ด์ ์์ฑ ๋ฐ ๋ณด๊ด(์บ์ฑ)

์๋ ํ๋ก์๋ฅผ ์์ฑ๊ธฐ์ ๋์๊ณผ ๋์ผํ๋ฐ, @Aspect Advisor ์กฐํ ๋ถ๋ถ์ด ์ถ๊ฐ
Aspect ์ ์ฉ ํด๋์ค
@Slf4j
@Aspect // ์ ๋
ธํ
์ด์
๊ธฐ๋ฐ ํ๋ก์ ์ ์ฉ ์ ํ์
public class LogTraceAspect {
private final LogTrace logTrace;
public LogTraceAspect(LogTrace logTrace) {
this.logTrace = logTrace;
}
/**
* Pointcut + Advice = Advisor
*
* Pointcut : @Around ๊ฐ์ ํฌ์ธํธ์ปท ํํ์ ์ฝ์
(ํํ์์ AspectJ ํํ์ ์ฌ์ฉ)
* Advice : @Around ๋ฉ์๋ = Advice
* ProceedingJoinPoint : ์ค์ ํธ์ถ ๋์, ์ ๋ฌ ์ธ์, ์ด๋ค ๊ฐ์ฒด์ ๋ฉ์๋๊ฐ ํธ์ถ๋์๋์ง ์ ๋ณด ํฌํจ(MethodInvocation invocation ๊ณผ ์ ์ฌ)
*/
@Around("execution(* hello.proxy.app..*(..))") //=> Pointcut path
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { //=> Advice Logic
TraceStatus status = null;
// log.info("target={}", joinPoint.getTarget()); //์ค์ ํธ์ถ ๋์
// log.info("getArgs={}", joinPoint.getArgs()); //์ ๋ฌ์ธ์
// log.info("getSignature={}", joinPoint.getSignature()); //join point์๊ทธ๋์ฒ
try {
String message = joinPoint.getSignature().toShortString();
status = logTrace.begin(message);
// ์ค์ ํธ์ถ ๋์(target) ํธ์ถ
Object result = joinPoint.proceed();
logTrace.end(status);
return result;
} catch (Exception e) {
logTrace.exception(status, e);
throw e;
}
}
}โญ๏ธ Spring AOP
์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ํฌ๊ฒ ํต์ฌ ๊ธฐ๋ฅ๊ณผ ๋ถ๊ฐ ๊ธฐ๋ฅ์ผ๋ก ๋๋ ์ ์์
์ฌ๊ธฐ์, ๋ถ๊ฐ ๊ธฐ๋ฅ ์ ์ฉ์ ๋ฌธ์
์ ์ฉ ์ ๋ง์ ๋ฐ๋ณต ํ์
์ฌ๋ฌ ๊ณณ์ ์ค๋ณต ์ฝ๋ ๋ฐ์
๋ณ๊ฒฝ ์ ์ค๋ณต์ผ๋ก ๋ง์ ์์ ํ์
์ ์ฉ ๋์ ๋ณ๊ฒฝ ์ ๋ง์ ์์ ํ์
Aspect
๋ถ๊ฐ ๊ธฐ๋ฅ๊ณผ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ด๋์ ์ ์ฉํ ์ง ์ ํํ๋ ๊ธฐ๋ฅ์ ํ๋๋ก ํฉํ์ฌ ๋ง๋ค์ด์ง ๋ชจ๋
Advisor(Pointcut + Advice) ๋ ๊ฐ๋ ์ ํ๋์ Aspect
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ๋ผ๋ณด๋ ๊ด์ ์ ํ๋์ ๊ธฐ๋ฅ์์ ํก๋จ ๊ด์ฌ์ฌ(cross-cutting concerns) ๊ด์ ์ผ๋ก ๋ณด๋ ๊ฒ
Aspect ๋ฅผ ์ฌ์ฉํ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ AOP(Aspect-Oriented Programming)
OOP ๋ฅผ ๋์ฒดํ๊ธฐ ์ํ ๊ฒ์ด ์๋ ํก๋จ ๊ด์ฌ์ฌ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ด๋ ค์ด OOP์ ๋ถ์กฑํ ๋ถ๋ถ ๋ณด์กฐ ๋ชฉ์ ์ผ๋ก ๊ฐ๋ฐ
AspectJ Framework
์คํ๋ง AOP๋ ๋๋ถ๋ถ AspectJ ๋ฌธ๋ฒ์ ์ฐจ์ฉํ๊ณ , ํ๋ก์ ๋ฐฉ์์ AOP ์ ์ฉ(AspectJ ์ ๊ณต ๊ธฐ๋ฅ ์ผ๋ถ๋ง ์ ๊ณต)
AspectJ Framework๋ ํก๋จ ๊ด์ฌ์ฌ์ ๊น๋ํ ๋ชจ๋ํ
์๋ฐ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ํ ์๋ฒฝํ ๊ด์ ์งํฅ ํ์ฅ
ํก๋จ ๊ด์ฌ์ฌ์ ๊น๋ํ ๋ชจ๋ํ
์ค๋ฅ ๊ฒ์ฌ ๋ฐ ์ฒ๋ฆฌ
๋๊ธฐํ
์ฑ๋ฅ ์ต์ ํ(์บ์ฑ)
๋ชจ๋ํฐ๋ง ๋ฐ ๋ก๊น
AOP ์ ์ฉ ๋ฐฉ์
์ปดํ์ผ ์์

.java ์์ค ์ฝ๋๋ฅผ ์ปดํ์ผ๋ฌ(AspectJ๊ฐ ์ ๊ณตํ๋ ํน๋ณํ ์ปดํ์ผ๋ฌ)๋ฅผ ์ฌ์ฉํด์ .class ๋ฅผ ๋ง๋๋ ์์ ์ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง ์ถ๊ฐ (=Weaving / aspect ์ ์ค์ ์ฝ๋๋ฅผ ์ฐ๊ฒฐ)
๋จ์ , ์ปดํ์ผ ์์ ์ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ฉํ๋ ค๋ฉด ํน๋ณํ ์ปดํ์ผ๋ฌ๊ฐ ํ์ํ๊ณ ๋ณต์ก
ํด๋์ค ๋ก๋ฉ ์์

์๋ฐ๋ฅผ ์คํํ๋ฉด ์๋ฐ๋ .class ํ์ผ์ JVM ๋ด๋ถ์ ํด๋์ค ๋ก๋์ ๋ณด๊ด. ์ด๋ ์ค๊ฐ์์ .class ํ์ผ์ ์กฐ์ํ ๋ค์ JVM์ ๋ก๋
๋๋ถ๋ถ ๋ชจ๋ํฐ๋ง ํด๋ค์ด java Instrumentation ๋ฐฉ์ ์ฌ์ฉ
๋จ์ , ๋ก๋ ํ์ ์๋น์ ์๋ฐ๋ฅผ ์คํํ ๋ ํน๋ณํ ์ต์ (java -javaagent)์ ํตํด ํด๋์ค ๋ก๋ ์กฐ์๊ธฐ๋ฅผ ์ง์ ํด์ผ ํ๋๋ฐ, ์ด ๋ถ๋ถ์ด ๋ฒ๊ฑฐ๋กญ๊ณ ์ด์์ด ์ด๋ ค์
๋ฐํ์ ์์ (ํ๋ก์)

๋ฐํ์ ์์ (์ปดํ์ผ์ด ๋๋๊ณ , ํด๋์ค ๋ก๋์ ํด๋์ค๋ ๋ค ์ฌ๋ผ๊ฐ๊ณ , ์ด๋ฏธ ์๋ฐ๊ฐ ์คํ๋๊ณ ๋ ๋ค์ ์ํ, ์๋ฐ์ main ๋ฉ์๋ ์คํ ์ดํ) ํ๋ก์๋ฅผ ํตํด ์คํ๋ง ๋น์ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ฉ(AOP)
๋จ์ , ํ๋ก์ ์ฌ์ฉ์ผ๋ก AOP ๊ธฐ๋ฅ์ ์ผ๋ถ ์ ์ฝ(final, ์์, ์์ฑ์, ..)์ด ์์ง๋ง, ๋ค๋ฅธ ๋ฐฉ๋ฒ์์ ๋ณต์กํ ์ค์ ๋จ๊ณ๊ฐ ๋ถํ์
๋ถ๊ฐ ๊ธฐ๋ฅ์ด ์ ์ฉ๋๋ ์ฐจ์ด
์ปดํ์ผ ์์ : ์ค์ ๋์ ์ฝ๋์ ์ ์คํฉํธ๋ฅผ ํตํ ๋ถ๊ฐ ๊ธฐ๋ฅ ํธ์ถ ์ฝ๋๊ฐ ํฌํจ (AspectJ ์ง์ ์ฌ์ฉ ํ์)ํด๋์ค ๋ก๋ฉ ์์ : ์ค์ ๋์ ์ฝ๋์ ์ ์คํฉํธ๋ฅผ ํตํ ๋ถ๊ฐ ๊ธฐ๋ฅ ํธ์ถ ์ฝ๋๊ฐ ํฌํจ (AspectJ ์ง์ ์ฌ์ฉ ํ์)๋ฐํ์ ์์ : ์ค์ ๋์ ์ฝ๋๋ ๊ทธ๋๋ก ์ ์งํ๋ ๋์ ํ๋ก์๋ฅผ ํตํด ๋ถ๊ฐ ๊ธฐ๋ฅ์ด ์ ์ฉ (ํญ์ ํ๋ก์๋ฅผ ํตํด ๋ถ๊ฐ ๊ธฐ๋ฅ ์ฌ์ฉ -> ์คํ๋ง AOP ์ฌ์ฉ ๋ฐฉ์)
Join Point(AOP๋ฅผ ์ ์ฉํ ์ ์๋ ์ง์ )
AOP๋ ๋ฉ์๋ ์คํ ์์น ๋ฟ๋ง ์๋๋ผ, ๋ค์ํ ์์น์ ์ ์ฉ ๊ฐ๋ฅ
์ ์ฉ ๊ฐ๋ฅ ์ง์ : ์์ฑ์, ํ๋ ๊ฐ ์ ๊ทผ, static ๋ฉ์๋ ์ ๊ทผ, ๋ฉ์๋ ์คํ
์ปดํ์ผ ์์ / ํด๋์ค ๋ก๋ฉ ์์
๋ฐ์ดํธ ์ฝ๋๋ฅผ ์ค์ ์กฐ์ํ๊ธฐ ๋๋ฌธ์ ํด๋น ๊ธฐ๋ฅ์ ๋ชจ๋ ์ง์ ์ ๋ค ์ ์ฉ ๊ฐ๋ฅ
์คํ๋ง AOP
ํ๋ก์ ๋ฐฉ์์ ์ฌ์ฉ(์ค๋ฒ๋ผ์ด๋ฉ ๊ฐ๋ ์ผ๋ก ๋์)ํ๋ฏ๋ก
๋ฉ์๋ ์คํ ์ง์ ์๋ง AOP ์ ์ฉ๊ฐ๋ฅ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํ ์ ์๋
์คํ๋ง ๋น์๋ง AOP ์ ์ฉ๊ฐ๋ฅ
AspectJ๋ ๋ ์ฌ์ธํ๊ณ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง๋ง, ์์์ผ ํ ๋ด์ฉ์ด ๋ง๊ณ , ์๋ฐ ๊ด๋ จ ๋ณต์กํ ์ค์ ์ด ๋ง์ผ๋ฏ๋ก, ์ค๋ฌด์์๋ ๋ณ๋ ์ค์ ์์ด ์ฌ์ฉํ ์ ์๋ ์คํ๋ง ์ ๊ณต AOP ๊ธฐ๋ฅ๋ง ์ฌ์ฉํด๋ ๋๋ถ๋ถ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐ ๊ฐ๋ฅ
AOP ์ฉ์ด
Join point
AOP๋ฅผ ์ ์ฉํ ์ ์๋ ๋ชจ๋ ์ง์ (์์น, ๋ฉ์๋ ์คํ, ์์ฑ์ ํธ์ถ, ํ๋ ๊ฐ ์ ๊ทผ, static ๋ฉ์๋ ์ ๊ทผ)
ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ ์คํ๋ง AOP๋ ํญ์ ๋ฉ์๋ ์คํ ์ง์ ์ผ๋ก ์ ํ
Pointcut
Pointcut ์ค์์ Advice๊ฐ ์ ์ฉ๋ ์์น ์ ๋ณ(์ฃผ๋ก AspectJ ํํ์์ ์ฌ์ฉํด์ ์ง์ )
ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ ์คํ๋ง AOP๋ ๋ฉ์๋ ์คํ ์ง์ ๋ง Pointcut์ผ๋ก ์ ๋ณ ๊ฐ๋ฅ
Target
Advice(๋ถ๊ฐ ๊ธฐ๋ฅ)๋ฅผ ๋ฐ๋ ๊ฐ์ฒด, Pointcut์ผ๋ก ๊ฒฐ์
Advice
๋ถ๊ฐ ๊ธฐ๋ฅ
Around, Before, After ๊ฐ์ ๋ค์ํ ์ข ๋ฅ์ Advic ์กด์ฌ
Aspect
Advice + Pointcut์ ๋ชจ๋ํ ํ ๊ฒ(@Aspect)
์ฌ๋ฌ Advice์ Pointcut ํจ๊ป ์กด์ฌ ๊ฐ๋ฅ
Advisor
ํ๋์ Advice์ ํ๋์ Pointcut์ผ๋ก ๊ตฌ์ฑ
์คํ๋ง AOP์์๋ง ์ฌ์ฉ๋๋ ํน๋ณํ ์ฉ์ด
Weaving
Pointcut์ผ๋ก ๊ฒฐ์ ํ ํ์ผ์ Join point์ Advice๋ฅผ ์ ์ฉํ๋ ๊ฒ
ํต์ฌ ๊ธฐ๋ฅ ์ฝ๋์ ์ํฅ์ ์ฃผ์ง ์๊ณ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ถ๊ฐ ๊ฐ๋ฅ
AOP ์ ์ฉ์ ์ํด ์ ์คํํธ๋ฅผ ๊ฐ์ฒด์ ์ฐ๊ฒฐํ ์ํ
์ปดํ์ผ ํ์(AspectJ compiler)
๋ก๋ ํ์
๋ฐํ์, ์คํ๋ง AOP๋ ๋ฐํ์, ํ๋ก์ ๋ฐฉ์
AOP Proxy
AOP ๊ธฐ๋ฅ์ ๊ตฌํํ๊ธฐ ์ํด ๋ง๋ ํ๋ก์ ๊ฐ์ฒด
์คํ๋ง์์ AOP ํ๋ก์๋ JDK ๋์ ํ๋ก์ ๋๋ CGLIB ํ๋ก์
โญ๏ธ AOP ๊ตฌํ
implementation 'org.springframework.boot:spring-boot-starter-aop'AOP ๊ธฐ๋ฅ ์ฌ์ฉ์ ์ํด spring-boot-starter-aop dependency ์ถ๊ฐ
@Aspect ์ฌ์ฉ์ ์ํด @EnableAspectJAutoProxy ์ค์ ์ด ํ์ํ์ง๋ง, ์คํ๋ง ๋ถํธ๊ฐ ์๋์ผ๋ก ์ถ๊ฐ
@Aspect ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ
@Bean ์ ์ฌ์ฉํด์ ์ง์ ๋ฑ๋ก
@Component ์ปดํฌ๋ํธ ์ค์บ์ ์ฌ์ฉํด์ ์๋ ๋ฑ๋ก
@Import ์ฃผ๋ก ์ค์ ํ์ผ์ ์ถ๊ฐํ ๋ ์ฌ์ฉ(@Configuration)
@Pointcut
ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ: ๋ฉ์๋ ์ด๋ฆ + ํ๋ผ๋ฏธํฐ
๋ฉ์๋์ ๋ฐํ ํ์ ์ void
@Aspect
@Component
public class Aspect {
/**
* @Around ์ ๋
ธํ
์ด์
์ ๊ฐ์ Pointcut
* @Around ์ ๋
ธํ
์ด์
์ ๋ฉ์๋๋ Advice
* execution(* hello.aop.order..*(..)) -> hello.aop.order ํจํค์ง์ ๊ทธ ํ์ ํจํค์ง( .. )๋ฅผ ์ง์ ํ๋ AspectJ ํฌ์ธํธ์ปท ํํ์
*/
@Around("execution(* hello.aop.order..*(..))")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); // join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
//------------------------------------------------------
/** pointcut signature
* pointcut expression : hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
*/
@Pointcut("execution(* hello.aop.order..*(..))")
private void allOrder() {
}
@Around("allOrder()")
public Object doLog2(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
//------------------------------------------------------
// ํด๋์ค ์ด๋ฆ ํจํด์ด *Service
@Pointcut("execution(* *..*Service.*(..))")
private void allService() {
}
/**
* hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง ์ด๋ฉด์,
* ํด๋์ค ์ด๋ฆ ํจํด์ด *Service
*/
@Around("allOrder() && allService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
try {
log.info("[ํธ๋์ญ์
์์] {}", joinPoint.getSignature());
Object result = joinPoint.proceed();
log.info("[ํธ๋์ญ์
์ปค๋ฐ] {}", joinPoint.getSignature());
return result;
} catch (Exception e) {
log.info("[ํธ๋์ญ์
๋กค๋ฐฑ] {}", joinPoint.getSignature());
throw e;
} finally {
log.info("[๋ฆฌ์์ค ๋ฆด๋ฆฌ์ฆ] {}", joinPoint.getSignature());
}
}
}Advice ์์
์ด๋๋ฐ์ด์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์๋ฅผ ๋ณด์ฅํ์ง ์์
@Order ๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง, ์ด๋๋ฐ์ด์ค ๋จ์๊ฐ ์๋๋ผ ํด๋์ค ๋จ์๋ก ์ ์ฉ ํ์
Advice ์ข
๋ฅ
์ฐธ๊ณ .
JoinPoint Interface ์ฃผ์ ๊ธฐ๋ฅ
getArgs() : ๋ฉ์๋ ์ธ์ ๋ฐํ
getThis() : ํ๋ก์ ๊ฐ์ฒด ๋ฐํ
getTarget() : ๋์ ๊ฐ์ฒด ๋ฐํ
getSignature() : ์กฐ์ธ๋๋ ๋ฉ์๋์ ๋ํ ์ค๋ช ๋ฐํ
toString() : ์กฐ์ธ๋๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์ฉํ ์ค๋ช ๋ฐํ
ProceedingJoinPoint Interface ์ฃผ์ ๊ธฐ๋ฅ
proceed() : ๋ค์ ์ด๋๋ฐ์ด์ค๋ ํ์ผ ํธ์ถ

@Around: ๋ฉ์๋ ํธ์ถ ์ /ํ์ ์ํ๋ค๋ฅธ ์ด๋๋ฐ์ด์ค ๊ธฐ๋ฅ ๋ชจ๋ ์ฒ๋ฆฌ(์กฐ์ธ ํฌ์ธํธ ์คํ ์ฌ๋ถ ์ ํ, ๋ฐํ ๊ฐ ๋ณํ, ์์ธ ๋ณํ ๋ฑ)
๋ค์ ์ด๋๋ฐ์ด์ค๋ ํ์ผ ํธ์ถ์ ์ํด ProceedingJoinPoint ์ฌ์ฉํ๊ณ , ๋๋จธ์ง ์ด๋๋ฐ์ด์ค๋ JoinPoint ์ฌ์ฉ
ํญ์ joinPoint.proceed() ํธ์ถ ํด์ผ ํ๋ ๋ถ๋ถ์ ์ฃผ์
@Before: ์กฐ์ธ ํฌ์ธํธ ์คํ ์ ์ ์คํ์์ ํ๋ฆ ๋ณ๊ฒฝ ๋ถ๊ฐ
๋ฉ์๋ ์ข ๋ฃ ์ ๋ค์ ํ์ผ(proceed()) ์๋ ํธ์ถ
@After: ์กฐ์ธ ํฌ์ธํธ๊ฐ ์ ์ ๋๋ ์์ธ์ ๊ด๊ณ์์ด ์คํ๋ฉ์๋ ์คํ์ด ์ข ๋ฃ๋๋ฉด ์คํ(=finally)
์ ์ ๋ฐ ์์ธ ๋ฐํ ์กฐ๊ฑด์ ๋ชจ๋ ์ฒ๋ฆฌ
์ผ๋ฐ์ ์ผ๋ก ๋ฆฌ์์ค ํด์ ์ ์ฌ์ฉ
@AfterReturning: ์กฐ์ธ ํฌ์ธํธ ์ ์ ์๋ฃ ํ ์คํreturning ์์ฑ ์ด๋ฆ์ ์ด๋๋ฐ์ด์ค ๋ฉ์๋ ๋งค๊ฐ๋ณ์ ์ด๋ฆ ์ผ์น
returning ์ ์ ์ง์ ๋ ํ์ ์ ๊ฐ(Obejct)์ ๋ฐํํ๋ ๋ฉ์๋๋ง ๋์
๋ฐํ๋๋ ๊ฐ์ฒด ๋ณ๊ฒฝ ๋ถ๊ฐ
@AfterThrowing: ๋ฉ์๋๊ฐ ์์ธ๋ฅผ ๋์ง๋ ๊ฒฝ์ฐ ์คํ@AfterReturning ํน์ง๊ณผ ๋์ผ
@Before("hello.aop.order.aop.Pointcuts.orderAndService()")
public void doBefore(JoinPoint joinPoint) {
log.info("[before] {}", joinPoint.getSignature());
}
@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn(JoinPoint joinPoint, Object result) {
log.info("[return] {} return={}", joinPoint.getSignature(), result);
}
@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Exception ex) {
log.info("[ex] {} message={}", joinPoint.getSignature(), ex.getMessage());
}
@After(value = "hello.aop.order.aop.Pointcuts.orderAndService()")
public void doAfter(JoinPoint joinPoint) {
log.info("[after] {}", joinPoint.getSignature());
}@Around ๊ฐ ๊ฐ์ฅ ๋์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง๋ง, @Before, @After ์ ๊ฐ์ด ์ ์ฝ์ด ์๋ ์ด๋๋ฐ์ด์ค๋ฅผ ์ฌ์ฉํด์ ๋ช ํํ๊ฒ ์ค๊ณ๋ฅผ ํด๋ณด์.
ํฌ์ธํธ์ปท
Pointcut ์ง์์
ํฌ์ธํธ์ปท ํํ์(AspectJ pointcut expression)์ execution ๊ฐ์ ํฌ์ธํธ์ปท ์ง์์(PCD, Pointcut Designator)๋ก ์์
ํฌ์ธํธ์ปท ์ง์์ ์ข ๋ฅ
execution : ๋ฉ์๋ ์คํ ์กฐ์ธ ํฌ์ธํธ ๋งค์นญ(๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๊ณ , ๊ธฐ๋ฅ๋ ๋ณต์ก)
within : ํน์ ํ์ ๋ด์ ์กฐ์ธ ํฌ์ธํธ ๋งค์นญ
args : ์ธ์๊ฐ ์ฃผ์ด์ง ํ์ ์ ์ธ์คํด์ค์ธ ์กฐ์ธ ํฌ์ธํธ
this : ์คํ๋ง ๋น ๊ฐ์ฒด(์คํ๋ง AOP ํ๋ก์)๋ฅผ ๋์์ผ๋ก ํ๋ ์กฐ์ธ ํฌ์ธํธ
target : Target ๊ฐ์ฒด(์คํ๋ง AOP ํ๋ก์๊ฐ ๊ฐ๋ฅดํค๋ ์ค์ ๋์)๋ฅผ ๋์์ผ๋ก ํ๋ ์กฐ์ธ ํฌ์ธํธ
@target : ์คํ ๊ฐ์ฒด์ ํด๋์ค์ ์ฃผ์ด์ง ํ์ ์ ์ ๋ ธํ ์ด์ ์ด ์๋ ์กฐ์ธ ํฌ์ธํธ
@within : ์ฃผ์ด์ง ์ ๋ ธํ ์ด์ ์ด ์๋ ํ์ ๋ด ์กฐ์ธ ํฌ์ธํธ
@annotation : ๋ฉ์๋๊ฐ ์ฃผ์ด์ง ์ ๋ ธํ ์ด์ ์ ๊ฐ์ง๊ณ ์๋ ์กฐ์ธ ํฌ์ธํธ๋ฅผ ๋งค์นญ
@args : ์ ๋ฌ๋ ์ค์ ์ธ์์ ๋ฐํ์ ํ์ ์ด ์ฃผ์ด์ง ํ์ ์ ์ ๋ ธํ ์ด์ ์ ๊ฐ๋ ์กฐ์ธ ํฌ์ธํธ
bean : ์คํ๋ง ์ ์ฉ ํฌ์ธํธ์ปท ์ง์์, ๋น ์ด๋ฆ์ผ๋ก ํฌ์ธํธ์ปท ์ง์
execution ๋ฌธ๋ฒ
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern namepattern(param-pattern) throws-pattern?)
execution(์ ๊ทผ์ ์ด์ํจํด? ๋ฐํํ์ ํจํด ์ ์ธํ์ ํจํด? ๋ฉ์๋์ด๋ฆํจํด(ํ๋ผ๋ฏธํฐ) ์์ธํจํด?)
๋ฉ์๋ ์คํ ์กฐ์ธ ํฌ์ธํธ ๋งค์นญ
?๋ ์๋ต ๊ฐ๋ฅํ ํจํด*ํจํด ์ง์ ๊ฐ๋ฅ
ํจํค์ง ํจ์นญ ๊ท์น
hello.aop.member.(1).(2)
(1): ํ์
(2): ๋ฉ์๋ ์ด๋ฆ
. : ์ ํํ๊ฒ ํด๋น ์์น์ ํจํค์ง
.. : ํด๋น ์์น์ ํจํค์ง์ ๊ทธ ํ์ ํจํค์ง๋ ํฌํจ
๋ฉ์๋/ํจํค์ง ์ด๋ฆ ๋งค์นญ
ํ๋ผ๋ฏธํฐ ๋งค์นญ ๊ท์น
(String) : ์ ํํ๊ฒ String ํ์ ํ๋ผ๋ฏธํฐ
() : ํ๋ผ๋ฏธํฐ ์์
(*) : ์ ํํ ํ๋์ ํ๋ผ๋ฏธํฐ, ๋จ ๋ชจ๋ ํ์ ํ์ฉ
(*, *) : ์ ํํ ๋ ๊ฐ์ ํ๋ผ๋ฏธํฐ, ๋จ ๋ชจ๋ ํ์ ํ์ฉ
(..) : ์ซ์์ ๋ฌด๊ดํ๊ฒ ๋ชจ๋ ํ๋ผ๋ฏธํฐ, ๋ชจ๋ ํ์ ํ์ฉ. ํ๋ผ๋ฏธํฐ๊ฐ ์์ด๋ ํ์ฉ (= 0..*)
(String, ..) : String ํ์ ์ผ๋ก ์์. ์ซ์์ ๋ฌด๊ดํ๊ฒ ๋ชจ๋ ํ๋ผ๋ฏธํฐ, ๋ชจ๋ ํ์ ํ์ฉ
ex. (String) , (String, Xxx) , (String, Xxx, Xxx) ํ์ฉ
within ์ง์์
ํน์ ํ์ ๋ด ์กฐ์ธ ํฌ์ธํธ์ ๋ํ ๋งค์นญ ์ ํ
ํด๋น ํ์ ์ด ๋งค์นญ๋๋ฉด ๊ทธ ์์ ๋ฉ์๋(์กฐ์ธ ํฌ์ธํธ)๋ค์ด ์๋์ผ๋ก ๋งค์นญ
execution ํ์ ๋ถ๋ถ๋ง ์ฌ์ฉ
๋ถ๋ชจ ํ์ ์ง์ ๋ถ๊ฐ
๊ฑฐ์ ์ฌ์ฉํ์ง ์๊ณ , ๋ณดํต execution ์ฌ์ฉ
args ์ง์์
์ธ์๊ฐ ์ฃผ์ด์ง ํ์ ์ ์ธ์คํด์ค์ธ ์กฐ์ธ ํฌ์ธํธ๋ก ๋งค์นญ
executionr vs args
executionr
ํ๋ผ๋ฏธํฐ ํ์ ์ ์ ํํ ๋งค์นญ
ํด๋์ค์ ์ ์ธ๋ ์ ๋ณด(๋ฉ์๋ ์๊ทธ๋์ฒ) ๊ธฐ๋ฐ ํ๋จ / ์ ์
args
๋ถ๋ชจ ํ์ ํ์ฉ
์ค์ ๋์ด์จ ํ๋ผ๋ฏธํฐ ๊ฐ์ฒด ์ธ์คํด์ค(๋ฐํ์์ ์ ๋ฌ๋ ์ธ์) ๊ธฐ๋ฐ ํ๋จ / ๋์
๋จ๋ ์ผ๋ก ์ฌ์ฉ๋๊ธฐ ๋ณด๋ค ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ ์ฃผ๋ก ์ฌ์ฉ
@target, @within ์ง์์
ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ ํจ๊ป ์ฌ์ฉ
@target : ์ธ์คํด์ค ๊ธฐ์ค์ผ๋ก ๋ชจ๋ ๋ฉ์๋์ ์กฐ์ธ ํฌ์ธํธ๋ฅผ ์ ์
๋ถ๋ชจ ํ์ ์ ๋ฉ์๋๋ ์ ์ฉ
@within : ์ ํ๋ ํด๋์ค ๋ด๋ถ์ ์๋ ๋ฉ์๋๋ง ์กฐ์ธ ํฌ์ธํธ๋ก ์ ์
๋ถ๋ชจ ํ์ ์ ๋ฉ์๋๋ ์ ์ฉ๋์ง ์์
์ฐธ๊ณ . args, @args, @target ์ง์์๋ ๋จ๋ ์ผ๋ก ์ฌ์ฉํ์ง ์๊ธฐ !!!
์ค์ ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ์์ฑ, ์คํ๋ ๋ ์ด๋๋ฐ์ด์ค ์ ์ฉ ์ฌ๋ถ๋ฅผ ํ์ธ ๊ฐ๋ฅํ๋ฏ๋ก ํ๋ก์๊ฐ ์์ด์ผ๋ง(์คํ ์์ ) ํ๋จ ๊ฐ๋ฅ
๋จ, ํ๋ก์๋ฅผ ์์ฑํ๋ ์์ ์ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๋ง๋ค์ด์ง๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ก๋ฉ ์์ ์ด๋ฏ๋ก args, @args, @target ์ง์์๋ ์คํ๋ง์ ๋ชจ๋ ๋น์ AOP๋ฅผ ์ ์ฉํ๋ ค๊ณ ์๋ -> ์คํ๋ง ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋น ์ค์๋ final ์ง์ ๋น๋ค๋ ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ ๋ฐ์
์ต๋ํ ํ๋ก์ ์ ์ฉ ๋์์ ์ถ์ํ๋ ํํ์(execution)๊ณผ ํจ๊ป ์ฌ์ฉํ๊ธฐ
@annotation, @args ์ง์์
@annotation : ์ฃผ์ด์ง ์ ๋ ธํ ์ด์ (@MethodAop)์ ๊ฐ์ง๊ณ ์๋ ๋ฉ์๋๋ฅผ ์กฐ์ธ ํฌ์ธํธ ๋งค์นญ
@args : ๋ฐํ์ ํ์ ์ ์ ๋ฌ๋ ์ธ์๊ฐ ์ฃผ์ด์ง ํ์ ์(@Check) ์ ๋ ธํ ์ด์ ์ด ์๋ ๊ฒฝ์ฐ์ ๋งค์นญ
bean ์ง์์
๋น ์ด๋ฆ์ผ๋ก AOP ์ ์ฉ ์ฌ๋ถ ์ง์ (์คํ๋ง ์ ์ฉ ํฌ์ธํธ์ปท ์ง์์)
this, target ์ง์์
this : ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋์ด ์๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋์์ผ๋ก ํฌ์ธํธ์ปท ๋งค์นญ
target : ์คํ๋ง AOP ํ๋ก์ ๊ฐ์ฒด๊ฐ ๊ฐ๋ฅดํค๋ ์ค์ target ๊ฐ์ฒด๋ฅผ ๋์์ผ๋ก ํฌ์ธํธ์ปท ๋งค์นญ
ํ๋ก์ ๋์์ธ this ๋ ๊ตฌ์ฒด ํด๋์ค ์ง์ ์ ํ๋ก์ ์์ฑ ์ ๋ต์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ์ ์์
์ ๊ฐ์ ํจํด ์ฌ์ฉ ๋ถ๊ฐ
๋ถ๋ชจ ํ์ ํ์ฉ
๋จ๋ ์ผ๋ก ์ฌ์ฉ๋๊ธฐ ๋ณด๋ค๋ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ ์ฃผ๋ก ์ฌ์ฉ
๋งค๊ฐ๋ณ์ ์ ๋ฌ
ํฌ์ธํธ์ปท ํํ์์ ์ฌ์ฉํด์ ์ด๋๋ฐ์ด์ค์ ๋งค๊ฐ๋ณ์ ์ ๋ฌ ๊ฐ๋ฅ
this, target, args,@target, @within, @annotation, @args
๋ฉ์๋์ ์ง์ ํ ํ์ ์ผ๋ก ์ ํ
โญ๏ธ AOP ์ค์ ์์
์ฐธ๊ณ . ์คํ๋ง์ ๊ฐ์ฅ ๋ํ์ ์ธ AOP๋ @Transactional
โญ๏ธ ์ฃผ์์ฌํญ
ํ๋ก์ ๋ฐฉ์์ AOP ํ๊ณ - ๋์ ๊ฐ์ฒด๋ฅผ ์ง์ ํธ์ถ
์์กด๊ด๊ณ ์ฃผ์ ์ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ฃผ์ ๋๋ฏ๋ก ๋์ ๊ฐ์ฒด๋ฅผ ์ง์ ํธ์ถํ๋ ๋ฌธ์ ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ์ํ์ง ์์ง๋ง, ๋์ ๊ฐ์ฒด์ ๋ด๋ถ์์ ๋ฉ์๋ ํธ์ถ(์์ ์ ์ธ์คํด์ค ๋ด๋ถ ๋ฉ์๋ ํธ์ถ)์ด ๋ฐ์ํ๋ฉด ํ๋ก์๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋์ ๊ฐ์ฒด๋ฅผ ์ง์ ํธ์ถํ๋ ๋ฌธ์ ๋ฐ์
์คํ๋ง์ ํ๋ก์ ๋ฐฉ์์ AOP๋ฅผ ์ฌ์ฉํ๋๋ฐ, ๋ฉ์๋ ๋ด๋ถ ํธ์ถ์ ํ๋ก์๋ฅผ ์ ์ฉํ ์ ์์


ํ๋ก์ ๋ฐฉ์์ AOP ํ๊ณ - ํ๋ก์ ๋ฐฉ์์ AOP์ ๋ด๋ถ ํธ์ถ ๋ฌธ์
ํ๋ก์ ๋ฐฉ์์ AOP ํ๊ณ. ๋์ I. ์๊ธฐ ์์ ์ฃผ์
์์ ์ ์ธ์คํด์ค ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ฒ์ด ์๋๋ผ, ํ๋ก์ ์ธ์คํด์ค๋ฅผ ํตํด์ ํธ์ถ
ํ๋ก์ ๋ฐฉ์์ AOP ํ๊ณ. ๋์ II. ์ง์ฐ ์กฐํ
ObjectProvider(Provider), ApplicationContext ์ฌ์ฉ
ObjectProvider : ๊ฐ์ฒด ์กฐํ๋ฅผ ์คํ๋ง ์ปจํ ์ด๋ ์คํ๋ง ๋น ์์ฑ ์์ ์์ ์ค์ ๊ฐ์ฒด ์ฌ์ฉ ์์ (.getObject())์ผ๋ก ์ง์ฐ
ํ๋ก์ ๋ฐฉ์์ AOP ํ๊ณ. ๋์ III. ๊ตฌ์กฐ ๋ณ๊ฒฝ
๋ด๋ถ ํธ์ถ์ ๋ณ๋ ํด๋์ค๋ก ๋ถ๋ฆฌ

ํ๋ก์ ๊ธฐ์ ์ ํ๊ณ
ํ์ ์บ์คํ
ํ๋ก์ ์บ์คํ ๋ฌธ์ ๋ ์์กด๊ด๊ณ ์ฃผ์ ์ ๋ฐ์
JDK ๋์ ํ๋ก์ : ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ก์ ์์ฑ
ํ๋ก์๋ฅผ ์ธํฐํ์ด์ค๋ก ์บ์คํ ๊ฐ๋ฅํ์ง๋ง, ๊ตฌ์ฒด ํด๋์ค๋ก ํ์ ์บ์คํ ์ด ๋ถ๊ฐ๋ฅ(์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํ๋ก์์ด๋ฏ๋ก..)
CGLIB : ๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์ ์์ฑ
๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์๊ฐ ์์ฑ๋๋ฏ๋ก, ๊ตฌ์ฒด ํด๋์ค๋ก ํ์ ์บ์คํ ๊ฐ๋ฅ
ํ๋ก์ ๊ธฐ์ ์ ํ๊ณ - ํ์ ์บ์คํ
์์กด๊ด๊ณ ์ฃผ์
JDK ๋์ ํ๋ก์
์ธํฐํ์ด์ค ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํด์ ๋์ ๊ฐ์ฒด Impl ํ์ ์ ์์กด๊ด๊ณ ์ฃผ์ ๋ถ๊ฐ

CGLIB
๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํด์ ๋์ ๊ฐ์ฒด Impl ํ์ ์ ์์กด๊ด๊ณ ์ฃผ์ ๊ฐ๋ฅ

@Autowired MemberService memberService; // ์์กด๊ด๊ณ ์ฃผ์
: JDK ๋์ ํ๋ก์ O, CGLIB O
@Autowire MemberServiceImpl memberServiceImpl; // ์์กด๊ด๊ณ ์ฃผ์
: JDK ๋์ ํ๋ก์ X, CGLIB Oํ๋ก์ ๊ธฐ์ ๊ณผ ํ๊ณ - ์์กด๊ด๊ณ ์ฃผ์
CGLIB ํ๋ก์ ๋ฌธ์ ์
๋์ ํด๋์ค์ ๊ธฐ๋ณธ ์์ฑ์ ํ์
์์ฑ์๋ฅผ 2๋ฒ ํธ์ถ
์ค์ target ๊ฐ์ฒด ์์ฑ
ํ๋ก์ ๊ฐ์ฒด ์์ฑ ์ ๋ถ๋ชจ ํด๋์ค ์์ฑ์ ํธ์ถ
final ํค์๋ ํด๋์ค, ๋ฉ์๋ ์ฌ์ฉ ๋ถ๊ฐ
์คํ๋ง์ ํ๋ก์ ๊ธฐ์ ์ ํ๊ณ ํด๊ฒฐ์ฑ
์คํ๋ง 3.2 : CGLIB๋ฅผ ์คํ๋ง ๋ด๋ถ์ ํจ๊ป ํจํค์ง
์คํ๋ง 4.0 : objenesis ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ๊ธฐ๋ณธ ์์ฑ์ ํ์ ๋ฌธ์ , ์์ฑ์ 2๋ฒ ํธ์ถ ๋ฌธ์ ํด๊ฒฐ
์คํ๋ง ๋ถํธ 2.0 : CGLIB ๊ธฐ๋ณธ ์ฌ์ฉ
Last updated