CGLIB
๐ก ๊น์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ ๊ณ ๊ธํธ ๊ฐ์๋ฅผ ๋ฃ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
CGLIB
CGLIB: Code Generator Library
CGLIB๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํด์ ๋์ ์ผ๋ก ํด๋์ค๋ฅผ ์์ฑํ๋ ๊ธฐ์ ์ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
CGLIB๋ฅผ ์ฌ์ฉํ๋ฉด ์ธํฐํ์ด์ค๊ฐ ์์ด๋ ๊ตฌ์ฒด ํด๋์ค๋ง ๊ฐ์ง๊ณ ๋์ ํ๋ก์๋ฅผ ๋ง๋ค์ด๋ผ ์ ์๋ค.
CGLIB๋ ์๋๋ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ๋ฐ, ์คํ๋ง ํ๋ ์์ํฌ๊ฐ ์คํ๋ง ๋ด๋ถ ์์ค ์ฝ๋์ ํฌํจํ๋ค.
๋ฐ๋ผ์ ์คํ๋ง์ ์ฌ์ฉํ๋ค๋ฉด ๋ณ๋์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ง ์์๋ ์ฌ์ฉํ ์ ์๋ค.
์ฐธ๊ณ ๋ก ์ฐ๋ฆฌ๊ฐ CGLIB๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๋ค. ์ดํ์ ์ค๋ช ํ ์คํ๋ง์ ProxyFactory๋ผ๋ ๊ฒ์ด ์ด ๊ธฐ์ ์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๊ฒ ๋์์ฃผ๊ธฐ ๋๋ฌธ์, ๋๋ฌด ๊น์ด์๊ฒ ํ๊ธฐ ๋ณด๋ค๋ CGLIB๊ฐ ๋ฌด์์ธ์ง ๋๋ต ๊ฐ๋ ๋ง ์ก์ผ๋ฉด ๋๋ค. ์์ ์ฝ๋๋ก CGLIB๋ฅผ ๊ฐ๋จํ ์ดํดํด๋ณด์.
CGLIB ์ฝ๋
JDK ๋์ ํ๋ก์์์ ์คํ ๋ก์ง์ ์ํด InvocationHandler๋ฅผ ์ ๊ณตํ๋ฏ์ด, CGLIB๋ MethodInterceptor๋ฅผ ์ ๊ณตํ๋ค.
public interface MethodInterceptor extends Callback {
Object intercept(Object obj, Method method, Object[] args, MethodProxy
proxy) throws Throwable;
}
- obj : CGLIB๊ฐ ์ ์ฉ๋ ๊ฐ์ฒด
- method : ํธ์ถ๋ ๋ฉ์๋
- args : ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด์ ์ ๋ฌ๋ ์ธ์
- proxy : ๋ฉ์๋ ํธ์ถ์ ์ฌ์ฉ
TimeMethodInterceptor
@Slf4j
public class TimeMethodInterceptor implements MethodInterceptor {
private final Object target;
public TimeMethodInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
log.info("TimeProxy ์คํ");
long startTime = System.currentTimeMillis();
Object result = methodProxy.invoke(target, args);
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy ์ข
๋ฃ resultTime={}", resultTime);
return result;
}
}
- TimeMethodInterceptor๋ MethodInterceptor ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ CGLIB ํ๋ก์์ ์คํ ๋ก์ง์ ์ ์ํ๋ค.
- JDK ๋์ ํ๋ก์๋ฅผ ์ค๋ช ํ ๋ ์์ ์ ๊ฑฐ์ ๊ฐ์ ์ฝ๋์ด๋ค
- Object target: ํ๋ก์๊ฐ ํธ์ถํ ์ค์ ๋์
- proxy.invoke(target, args): ์ค์ ๋์์ ๋์ ์ผ๋ก ํธ์ถํ๋ค.
- ์ฐธ๊ณ ๋ก method๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง, CGLIB๋ ์ฑ๋ฅ์ MethodProxy proxy๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
์คํ ์์ ์ฝ๋
@Slf4j
public class CglibTest {
@Test
void cglib() {
ConcreteService target = new ConcreteService();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ConcreteService.class);
enhancer.setCallback(new TimeMethodInterceptor(target));
ConcreteService proxy = (ConcreteService)enhancer.create();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
proxy.call();
}
}
ConcreteService๋ ์ธํฐํ์ด์ค๊ฐ ์๋ ๊ตฌ์ฒด ํด๋์ค์ด๋ค. ์ฌ๊ธฐ์ CGLIB๋ฅผ ์ฌ์ฉํด์ ํ๋ก์๋ฅผ ์์ฑํด๋ณด์.
- Enhancer
- CGLIB๋ Enhancer๋ฅผ ์ฌ์ฉํด์ ํ๋ก์๋ฅผ ์์ฑํ๋ค.
- enhancer.setSuperclass(ConcreteService.class)
- CGLIB๋ ๊ตฌ์ฒด ํด๋์ค๋ฅผ ์์ ๋ฐ์์ ํ๋ก์๋ฅผ ์์ฑํ ์ ์๋ค.
- ์ด๋ค ๊ตฌ์ฒด ํด๋์ค๋ฅผ ์์ ๋ฐ์์ง ์ง์ ํ๋ค.
- enhancer.setCallback(new TimeMethodInterceptor(target))
- ํ๋ก์์ ์ ์ฉํ ์คํ ๋ก์ง์ ํ ๋นํ๋ค.
- enhancer.create()
- ํ๋ก์๋ฅผ ์์ฑํ๋ค.
- ์์ ์ค์ ํ enhancer.setSuperclass(ConcreteService.class)์์ ์ง์ ํ ํด๋์ค๋ฅผ ์์ ๋ฐ์์ ํ๋ก์๊ฐ ๋ง๋ค์ด์ง๋ค.
JDK ๋์ ํ๋ก์๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํ(implement)ํด์ ํ๋ก์๋ฅผ ๋ง๋ ๋ค.
CGLIB๋ ๊ตฌ์ฒด ํด๋์ค๋ฅผ ์์(extends) ํด์ ํ๋ก์๋ฅผ ๋ง๋ ๋ค.