๐ก ๊น์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ ๊ณ ๊ธํธ ๊ฐ์๋ฅผ ๋ฃ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
ํ๋ก์ ํฉํ ๋ฆฌ
๋์ ํ๋ก์๋ฅผ ์ฌ์ฉํ ๋ ๋ฌธ์ ์
- ์ธํฐํ์ด์ค๊ฐ ์๋ ๊ฒฝ์ฐ์๋ JDK ๋์ ํ๋ก์๋ฅผ ์ ์ฉํ๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ CGLIB๋ฅผ ์ ์ฉํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
- ๋ ๊ธฐ์ ์ ํจ๊ป ์ฌ์ฉํ ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ธฐ ์ํด JDK ๋์ ํ๋ก์๊ฐ ์ ๊ณตํ๋ InvocationHandler์ CGLIB๊ฐ ์ ๊ณตํ๋ MethodInterceptor๋ฅผ ๊ฐ๊ฐ ์ค๋ณต์ผ๋ก ๋ง๋ค์ด์ ๊ด๋ฆฌํด์ผ ํ ๊น?
- ํน์ ์กฐ๊ฑด์ ๋ง์ ๋ ํ๋ก์ ๋ก์ง์ ์ ์ฉํ๋ ๊ธฐ๋ฅ๋ ๊ณตํต์ผ๋ก ์ ๊ณต๋์์ผ๋ฉด?
Q: ์ธํฐํ์ด์ค๊ฐ ์๋ ๊ฒฝ์ฐ์๋ JDK ๋์ ํ๋ก์๋ฅผ ์ ์ฉํ๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ CGLIB๋ฅผ ์ ์ฉํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์คํ๋ง์ ์ ์ฌํ ๊ตฌ์ฒด์ ์ธ ๊ธฐ์ ๋ค์ด ์์ ๋, ๊ทธ๊ฒ๋ค์ ํตํฉํด์ ์ผ๊ด์ฑ ์๊ฒ ์ ๊ทผํ ์ ์๊ณ , ๋์ฑ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋ ์ถ์ํ๋ ๊ธฐ์ ์ ์ ๊ณตํ๋ค. ์คํ๋ง์ ๋์ ํ๋ก์๋ฅผ ํตํฉํด์ ํธ๋ฆฌํ๊ฒ ๋ง๋ค์ด์ฃผ๋ ํ๋ก์ ํฉํ ๋ฆฌ( ProxyFactory )๋ผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ด์ ์๋ ์ํฉ์ ๋ฐ๋ผ์ JDK ๋์ ํ๋ก์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ CGLIB๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค๋ฉด, ์ด์ ๋ ์ด ํ๋ก์ ํฉํ ๋ฆฌ ํ๋๋ก ํธ๋ฆฌํ๊ฒ ๋์ ํ๋ก์๋ฅผ ์์ฑํ ์ ์๋ค. ํ๋ก์ ํฉํ ๋ฆฌ๋ ์ธํฐํ์ด์ค๊ฐ ์์ผ๋ฉด JDK ๋์ ํ๋ก์๋ฅผ ์ฌ์ฉํ๊ณ , ๊ตฌ์ฒด ํด๋์ค๋ง ์๋ค๋ฉด CGLIB๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ์ค์ ์ ๋ณ๊ฒฝํ ์๋ ์๋ค.
Q: ๋ ๊ธฐ์ ์ ํจ๊ป ์ฌ์ฉํ ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ฉํ๊ธฐ ์ํด JDK ๋์ ํ๋ก์๊ฐ ์ ๊ณตํ๋ InvocationHandler์ CGLIB๊ฐ ์ ๊ณตํ๋ MethodInterceptor๋ฅผ ๊ฐ๊ฐ ์ค๋ณต์ผ๋ก ๋ฐ๋ก ๋ง๋ค์ด์ผ ํ ๊น?
์คํ๋ง์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ ์ฉํ ๋ Advice๋ผ๋ ์๋ก์ด ๊ฐ๋ ์ ๋์ ํ๋ค. ๊ฐ๋ฐ์๋ InvocationHandler ๋ MethodInterceptor๋ฅผ ์ ๊ฒฝ์ฐ์ง ์๊ณ , Advice๋ง ๋ง๋ค๋ฉด ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก InvocationHandler๋ MethodInterceptor๋ Advice๋ฅผ ํธ์ถํ๊ฒ ๋๋ค. ํ๋ก์ ํฉํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด Advice๋ฅผ ํธ์ถํ๋ ์ ์ฉ InvocationHandler, MethodInterceptor๋ฅผ ๋ด๋ถ์์ ์ฌ์ฉํ๋ค.
Q: ํน์ ์กฐ๊ฑด์ ๋ง์ ๋ ํ๋ก์ ๋ก์ง์ ์ ์ฉํ๋ ๊ธฐ๋ฅ๋ ๊ณตํต์ผ๋ก ์ ๊ณต๋์์ผ๋ฉด?
์์ ํน์ ๋ฉ์๋ ์ด๋ฆ์ ์กฐ๊ฑด์ ๋ง์ ๋๋ง ํ๋ก์ ๋ถ๊ฐ ๊ธฐ๋ฅ์ด ์ ์ฉ๋๋ ์ฝ๋๋ฅผ ์ง์ ๋ง๋ค์๋ค.
์คํ๋ง์ Pointcut์ด๋ผ๋ ๊ฐ๋ ์ ๋์ ํด์ ์ด ๋ฌธ์ ๋ฅผ ์ผ๊ด์ฑ ์๊ฒ ํด๊ฒฐํ๋ค.
์) save, delete ๋ถ๋ถ์๋ง ๋ก๊ทธ๋ฅผ ์ฐ๊ณ ๋๋จธ์ง ๊ธฐ๋ฅ์ ๋ก๊ทธ๋ฅผ ์ฐ๊ณ ์ถ์ง ์์ ๊ฒฝ์ฐ์ Pointcut ๊ฐ๋ ์ผ๋ก ํด๊ฒฐ
์ ๋ฆฌ
ํ๋ก์๋ฅผ ์์ฑํ๋๊ฑด ProxyFactory๋ฅผ ์ฌ์ฉํด์ ์์ฑํ๊ณ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง์ Advice์ ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
๋๋จธ์ง๋ ์คํ๋ง์ด ์์์ ๋ค ์ถ์ํํด์ ์ฒ๋ฆฌ๋ฅผ ํด์ค๋ค.
ํ๋ก์ ํฉํ ๋ฆฌ - ์ธํฐํ์ด์ค
Advice ๋ง๋ค๊ธฐ
Advice๋ ํ๋ก์์ ์ ์ฉํ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง์ด๋ค. ์ด๊ฒ์ JDK ๋์ ํ๋ก์๊ฐ ์ ๊ณตํ๋ InvocationHandler์ CGLIB๊ฐ ์ ๊ณตํ๋ MethodInterceptor์ ๊ฐ๋ ๊ณผ ์ ์ฌํ๋ค. ๋์ ๊ฐ๋ ์ ์ผ๋ก ์ถ์ํ ํ ๊ฒ์ด๋ค. ํ๋ก์ ํฉํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ๋์ ์ Advice๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
package org.aopalliance.intercept;
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
MethodInvocation invocation ๋ด๋ถ์๋ ๋ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ฐฉ๋ฒ, ํ์ฌ ํ๋ก์ ๊ฐ์ฒด ์ธ์คํด์ค, args, ๋ฉ์๋ ์ ๋ณด ๋ฑ์ด ํฌํจ๋์ด ์ ๋ค. ๊ธฐ์กด์ ํ๋ผ๋ฏธํฐ๋ก ์ ๊ณต๋๋ ๋ถ๋ถ๋ค์ด ์ด ์์ผ๋ก ๋ชจ๋ ๋ค์ด๊ฐ๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค. MethodInterceptor๋ Interceptor๋ฅผ ์์ํ๊ณ Interceptor๋ Advice ์ธํฐํ์ด์ค๋ฅผ ์์ํ๋ค.
TimeAdvice
@Slf4j
public class TimeAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info("TimeProxy ์คํ");
long startTime = System.currentTimeMillis();
Object result = invocation.proceed();
long endTime = System.currentTimeMillis();
long resultTime = endTime - startTime;
log.info("TimeProxy ์ข
๋ฃ resultTime={}", resultTime);
return result;
}
}
Object result = invocation.proceed()
invocation.proceed()๋ฅผ ํธ์ถํ๋ฉด ์ค์ ๊ธฐ๋ฅ์ ๋ด๊ณ ์๋ target ํด๋์ค๋ฅผ ํธ์ถํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋๋ค.
ProxyFactoryTest
@Slf4j
public class ProxyFactoryTest {
@Test
@DisplayName("์ธํฐํ์ด์ค๊ฐ ์์ผ๋ฉด JDK ๋์ ํ๋ก์ ์ฌ์ฉ")
void interfaceProxy() {
ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvice(new TimeAdvice());
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
proxy.save();
assertThat(AopUtils.isAopProxy(proxy)).isTrue();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).isTrue();
assertThat(AopUtils.isCglibProxy(proxy)).isFalse();
}
}
new ProxyFactory(target)
ํ๋ก์ ํฉํ ๋ฆฌ๋ฅผ ์์ฑํ ๋, ์์ฑ์์ ํ๋ก์์ ํธ์ถ ๋์์ ํจ๊ป ๋๊ฒจ์ค๋ค. ํ๋ก์ ํฉํ ๋ฆฌ๋ ์ด ์ธ์คํด์ค ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์๋ฅผ ๋ง๋ค์ด๋ธ๋ค. ๋ง์ฝ ์ด ์ธ์คํด์ค์ ์ธํฐํ์ด์ค๊ฐ ์๋ค๋ฉด JDK ๋์ ํ๋ก์๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๊ณ ์ธํฐํ์ด์ค๊ฐ ์๊ณ ๊ตฌ์ฒด ํด๋์ค๋ง ์๋ค๋ฉด CGLIB๋ฅผ ํตํด์ ๋์ ํ๋ก์๋ฅผ ์์ฑํ๋ค. ์ฌ๊ธฐ์๋ target์ด new ServiceImpl()์ ์ธ์คํด์ค์ด๊ธฐ ๋๋ฌธ์ ServiceInterface ์ธํฐํ์ด์ค๊ฐ ์๋ค. ๋ฐ๋ผ์ ์ด ์ธํฐํ์ด์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก JDK ๋์ ํ๋ก์๋ฅผ ์์ฑํ๋ค.
proxyFactory.addAdvice(new TimeAdvice())
ํ๋ก์ ํฉํ ๋ฆฌ๋ฅผ ํตํด์ ๋ง๋ ํ๋ก์๊ฐ ์ฌ์ฉํ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง์ ์ค์ ํ๋ค.
JDK ๋์ ํ๋ก์๊ฐ ์ ๊ณตํ๋ InvocationHandler์ CGLIB๊ฐ ์ ๊ณตํ๋ MethodInterceptor์ ๊ฐ๋ ๊ณผ ์ ์ฌํ๋ค.
์ด๋ ๊ฒ ํ๋ก์๊ฐ ์ ๊ณตํ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง์ ์ด๋๋ฐ์ด์ค( Advice )๋ผ ํ๋ค.
๋ฒ์ญํ๋ฉด ์กฐ์ธ์ ํด์ค๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
proxyFactory.getProxy()
ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋๋ค.
ํ๋ก์ ํฉํ ๋ฆฌ - ๊ตฌ์ฒด ํด๋์ค
์ด๋ฒ์๋ ๊ตฌ์ฒด ํด๋์ค๋ง ์๋ ConcreteService์ ํ๋ก์๋ฅผ ์ ์ฉํด๋ณด์.
ํ๋ก์ ํฉํ ๋ฆฌ๋ ์ธํฐํ์ด์ค ์์ด ๊ตฌ์ฒด ํด๋์ค๋ง ์์ผ๋ฉด CGLIB๋ฅผ ์ฌ์ฉํด์ ํ๋ก์๋ฅผ ์ ์ฉํ๋ค.
@Test
@DisplayName("๊ตฌ์ฒด ํด๋์ค๋ง ์์ผ๋ฉด CGLIB ์ฌ์ฉ")
void concreteProxy() {
ConcreteService target = new ConcreteService();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvice(new TimeAdvice());
ConcreteService proxy = (ConcreteService) proxyFactory.getProxy();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
proxy.call();
assertThat(AopUtils.isAopProxy(proxy)).isTrue();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse();
assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
}
proxyTargetClass ์ต์
@Test
@DisplayName("ProxyTargetClass ์ต์
์ ์ฌ์ฉํ๋ฉด ์ธํฐํ์ด์ค๊ฐ ์์ด๋ CGLIB๋ฅผ ์ฌ์ฉํ๊ณ , ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์ ์ฌ์ฉ")
void proxyTargetClass() {
ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.setProxyTargetClass(true);
proxyFactory.addAdvice(new TimeAdvice());
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
log.info("targetClass={}", target.getClass());
log.info("proxyClass={}", proxy.getClass());
proxy.save();
assertThat(AopUtils.isAopProxy(proxy)).isTrue();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).isFalse();
assertThat(AopUtils.isCglibProxy(proxy)).isTrue();
}
๋ง์ง๋ง์ผ๋ก ์ธํฐํ์ด์ค๊ฐ ์์ง๋ง, CGLIB๋ฅผ ์ฌ์ฉํด์ ์ธํฐํ์ด์ค๊ฐ ์๋ ํด๋์ค ๊ธฐ๋ฐ์ผ๋ก ๋์ ํ๋ก์๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์์๋ณด์. ํ๋ก์ ํฉํ ๋ฆฌ๋ proxyTargetClass๋ผ๋ ์ต์ ์ ์ ๊ณตํ๋๋ฐ, ์ด ์ต์ ์ true ๊ฐ์ ๋ฃ์ผ๋ฉด ์ธํฐํ์ด์ค๊ฐ ์์ด๋ ๊ฐ์ ๋ก CGLIB๋ฅผ ์ฌ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ธํฐํ์ด์ค๊ฐ ์๋ ํด๋์ค ๊ธฐ๋ฐ์ ํ๋ก์๋ฅผ ๋ง๋ค์ด์ค๋ค.
ํ๋ก์ ํฉํ ๋ฆฌ์ ๊ธฐ์ ์ ํ ๋ฐฉ๋ฒ
- ๋์์ ์ธํฐํ์ด์ค๊ฐ ์์ผ๋ฉด: JDK ๋์ ํ๋ก์, ์ธํฐํ์ด์ค ๊ธฐ๋ฐ ํ๋ก์
- ๋์์ ์ธํฐํ์ด์ค๊ฐ ์์ผ๋ฉด: CGLIB, ๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์
- proxyTargetClass=true: CGLIB, ๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์, ์ธํฐํ์ด์ค ์ฌ๋ถ์ ์๊ด์์
์ ๋ฆฌ
ํ๋ก์ ํฉํ ๋ฆฌ์ ์๋น์ค ์ถ์ํ ๋๋ถ์ ๊ตฌ์ฒด์ ์ธ CGLIB, JDK ๋์ ํ๋ก์ ๊ธฐ์ ์ ์์กดํ์ง ์๊ณ , ๋งค์ฐ ํธ๋ฆฌํ๊ฒ ๋์ ํ๋ก์๋ฅผ ์์ฑํ ์ ์๋ค. ํ๋ก์์ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง๋ ํน์ ๊ธฐ์ ์ ์ข ์์ ์ด์ง ์๊ฒ Advice ํ๋๋ก ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์์๋ค. ์ด๊ฒ์ ํ ๋ก์ ํฉํ ๋ฆฌ๊ฐ ๋ด๋ถ์์ JDK ๋์ ํ๋ก์์ธ ๊ฒฝ์ฐ InvocationHandler๊ฐ Advice๋ฅผ ํธ์ถํ๋๋ก ๊ฐ๋ฐํด๋๊ณ , CGLIB์ธ ๊ฒฝ์ฐ MethodInterceptor๊ฐ Advice๋ฅผ ํธ์ถํ๋๋ก ๊ธฐ๋ฅ์ ๊ฐ๋ฐํด๋์๊ธฐ ๋๋ฌธ์ด๋ค.
์ฐธ๊ณ
์คํ๋ง ๋ถํธ๋ AOP๋ฅผ ์ ์ฉํ ๋ ๊ธฐ๋ณธ์ ์ผ๋ก proxyTargetClass=true๋ก ์ค์ ํด์ ์ฌ์ฉํ๋ค.
๋ฐ๋ผ์ ์ธํฐํ์ด์ค๊ฐ ์์ด๋ ํญ์ CGLIB๋ฅผ ์ฌ์ฉํด์ ๊ตฌ์ฒด ํด๋์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํ๋ค.
'Spring > AOP' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
@Aspect AOP (0) | 2024.11.12 |
---|---|
๋น ํ์ฒ๋ฆฌ๊ธฐ (0) | 2024.11.12 |
ํฌ์ธํธ์ปท, ์ด๋๋ฐ์ด์ค, ์ด๋๋ฐ์ด์ (0) | 2024.11.11 |
CGLIB (0) | 2024.11.11 |
JDK ๋์ ํ๋ก์ (0) | 2024.11.11 |