์๋ฐ AOP์ ๋ชจ๋ ๊ฒ(Spring AOP & AspectJ)
by JiwonDev์ด ๊ธ์ ์ฌ์ ์ง์์ด ์๋ค๋ฉด ์ฝ๊ธฐ ์ด๋ ค์ธ ์ ์๋ค. ๋ฐ์ดํธ์ฝ๋์ ๋ฆฌํ๋ ์ ์ ๋ชจ๋ฅธ๋ค๋ฉด ์๋์ ๊ธ์ ๊ผญ ์ฝ์ด๋ณด๋๋กํ์.
์คํ๋ง์ ๋น ํฌ์คํธ ํ๋ก์ธ์
๐Spring boot ๊ฐ stereotype annotation ์ ๋ถ์ธ ํด๋์ค๋ค์ ์ด๋ป๊ฒ ์ฐพ๊ณ bean ์ผ๋ก ๋ฑ๋กํ๋์ง ๊ทธ ๊ณผ์ ์ ์ต๋ํ ์์ธํ๊ฒ ์ค๋ช ํด์ฃผ์ธ์.
stereotype ์ด๋
ธํ
์ด์
์ ๋๋ฌ๋ณด๋ฉด, ์์ @Componet๊ฐ ๋ถ์ด์์ต๋๋ค. ์ฆ ์ปดํฌ๋ํธ ์ค์บ์ ๋์์ด ๋ฉ๋๋ค.
๐@Configuration ์์๋ @ComponentScan์ด ๋ถ์ด์์ต๋๋ค.
๊ธฐ๋ณธ ๊ฐ์ ํด๋์ค์ ํจํค์ง๋ฅผ ๊ธฐ์ ์ผ๋ก, ํ์ ํจํค์ง์ ์๋ ๋ชจ๋ @Component๋ค์ ์ค์บํฉ๋๋ค.
โก ๋ฌผ๋ก @ComponentScan ์ต์
์ผ๋ก basePackages ๋ณ๊ฒฝํ๊ฑฐ๋, includeFilters, excludeFilters๋ก ํํฐ๋ง ๋ณ๊ฒฝ ๊ฐ๋ฅ.
โก ์ฐธ๊ณ ๋ก ์ต๊ฐํ๊ฑฐ ๋ค ์ง์ํฉ๋๋ค. ์ ๊ทํํ์ , ํน์ ์ด๋
ธํ
์ด์
, ํน์ ํด๋์คํ์
.. ๋ค ํํฐ๋ง ๊ฐ๋ฅํฉ๋๋ค.
โก ๋น ์ด๋ฆ์ ํด๋์ค์ด๋ฆ ๊ทธ๋๋ก ์ฌ์ฉํ๋, ์ฒซ๊ธ์๋ฅผ ์๋ฌธ์๋ก ๋ฐ๊ฟ๋๋ค. (๋ฌผ๋ก @Componet(..name..) ์ผ๋ก ๋ณ๊ฒฝ๊ฐ๋ฅ)
๐๋ฆฌํ๋์
์ ์ฌ์ฉํ๊ณ ์ ํด๋, ํด๋น ๋น์ ์ ์ฒด ํด๋์ค ๊ฒฝ๋ก๊ฐ ํ์ํฉ๋๋ค. ์ด๋ ๋ฐํ์์๋ ์ ์ ์์ต๋๋ค.
โก @ComponentScan์ ์์น๋ฅผ ๊ธฐ์ ์ผ๋ก ๋ชจ๋ ํ์ ํจํค์ง๋ฅผ ํ์ํ์ฌ @Component๋ฅผ ์ฐพ์ต๋๋ค.
โก ๋ฌผ๋ก ๋ฌด์ง์ฑ์ผ๋ก ํ๋ก์ ํธ ์ ์ฒด ํจํค์ง๋ฅผ ์ค์บํ ์ ์์ผ๋, ์ด๋ ๋น๋ ํ์์ด ๋งค์ฐ ๋๋ ค์ง๋๋ค.
๐ ์ฌ๋ฐ๋ ์ ์, ์คํ๋ง์ ์ด๋
ธํ
์ด์
์ด ์๋๋ผ XML์ด๋ ์ปค์คํ
ํ ๋ฐฉ๋ฒ์ผ๋ก๋ ๋น ๋ฑ๋ก์ด ๊ฐ๋ฅํฉ๋๋ค.
์คํ๋ง ์ปจํ
์ด๋๋ BeanDefinition ์ด๋ผ๋ ๊ฐ์ฒด๋ง ์ฌ์ฉํฉ๋๋ค. Reader๋ ์ถ์ํ๋์ด์์ผ๋ฉฐ ๊ฐ์๋ผ์ธ ์ ์์ต๋๋ค.
์ค์ ๋ก ์คํ๋ง ์ปจํ
์ด๋(ApplicationContext)๋ ๊ตฌํ์ฒด์ ๋ฐ๋ผ ๋ค๋ฅธ BeanDefinitionReader๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์ฐธ๊ณ ๋ก Bean์ ๊ด๋ฆฌํ๊ณ ์กฐํํ๋๊ฑด BeanFactory ์ธํฐํ์ด์ค๊ฐ ๋ด๋นํฉ๋๋ค.
// ์๋ตํ๊ฒ ์๋๋ผ, ์ ์ฒด ์ฝ๋์
๋๋ค. ์์ธ๋ก ์ฌํํฉ๋๋ค.
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
HierarchicalBeanFactory, MessageSource,
ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
๐ ์คํ๋ง์์ ์ค์ ๋น ๋์ , ํ๋ก์๊ฐ ์ปจํ
์ด๋์ ์ฝ์
๋๊ธฐ๋ ํฉ๋๋ค.
ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ฉด ๋น ํ์ฒ๋ฆฌ๊ธฐ (BeanPostProcessor)์์ ๋น์ ๋ฐํ์์ ๋ฐ๊ฟ์น๊ธฐํ ํ ์ปจํ
์ด๋์ ๋ฑ๋กํฉ๋๋ค.
์ด ๋ ์ค์ ์ ๋ช ๊ฐ๋ฅผ ์ถ๊ฐํ๋ ๋จ 1๊ฐ์ ํ๋ก์๋ง ์์ฑ๋ฉ๋๋ค. CGLIB๋ฅผ ์ฌ์ฉํ๋ ๋ค์ด๋๋ฏน ํ๋ก์์ ์ฅ์ !
๐ ์, ๋ฌผ๋ก ํ๋กํ ํ์
๋น์ ์ปจํ
์ด๋์ ์๋ต๋๋ค. ์ด๋ ๋นํ์ฒ๋ฆฌ๊ธฐ ์ดํ ์์กด์ฑ ์ฃผ์
์ด ๋๋๋ฉด ๋ฒ๋ฆฌ๋๊ฑฐ์์
(ํด๋์ค๋ ๊ฐ์ง๊ณ ์์. ์ธ์คํด์ค๋ฅผ ์ปจํ
์ด๋์ ๊ด๋ฆฌํ์ง์์์, ๋ค์ ์์ฒญํ๋ฉด ์๋ก ๋ง๋ค์ด์ค)
๐ ๋จ, ๋น์์ ์์ฑ์ ์ฃผ์
์ ์ฌ์ฉ์ํ๋ฉด ๊ฐ์ฒด๊ฐ ๋จผ์ ์์ฑ๋ ํ, ๋์ค์ ์์กด์ฑ์ด ์ฃผ์
๋ฉ๋๋ค.
๊ทธ๋์ ์ด๊ธฐํ์ฉ / ์ข
๋ฃ์ฉ ์ฝ๋ฐฑ ๋ฉ์๋๋ฅผ ์์ฑํด๋จ๋ค๊ฐ, ํด๋น ์์ ์ ์คํํ๋๋ก ๋ง๋ค ์ ์์ต๋๋ค.
@Configuration
static class LifeCycleConfig {
// ํด๋น ๊ฐ์ฒด์ ๋ฉ์๋ ์ด๋ฆ์ ๋๊ธฐ๋ฉด ๋ฉ๋๋ค. ๋ฌผ๋ก ์์ผ๋ฉด ์คํ๋ง์๋ฌ.
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://hello-spring.dev");
return networkClient;
}
}
์ด๊ฒ ๋ฒ๊ฑฐ๋กญ๋ค๋ฉด, ์๋์ ๊ฐ์ด ํด๋์ค์ ์ง์ @PostConstruct, @PreDestory ๋ฅผ ๋ถ์ฌ๋ ๋๊ฐ์ด ๋์ํฉ๋๋ค.
public class NetworkClient {
private String url;
public NetworkClient() {
System.out.println("์์ฑ์ ํธ์ถ, url = " + url);
}
... ์๋ต ...
@PostConstruct
public void init() {
System.out.println("NetworkClient.init");
connect();
call("์ด๊ธฐํ ์ฐ๊ฒฐ ๋ฉ์์ง");
}
@PreDestroy
public void close() {
System.out.println("NetworkClient.close");
disConnect();
}
}
์ด ์ด๋
ธํ
์ด์
์ด ์์ ๋์๋ ์ธํฐํ์ด์ค(InitalizingBean, DispoableBean)์ ๊ตฌํํ๊ฑฐ๋ xml๋ก ์ ์๋๋ฐ,
ํด๋น ์ด๋
ธํ
์ด์
์ด ์๊ธฐ๊ณ ๋์๋ ๊ฑฐ์ ์์ฐ๋ ๊ธฐ๋ฅ์ด์์. ์ฐธ๊ณ ๋ก ์ฒ๋ฆฌ๋๋ ์์๋ ์๋์ ๊ฐ์ต๋๋ค.
# ์คํ๋ง์ Proxy
์คํ๋งAOP๋ ํ๋ก์ ํจํด์ ๊ธฐ๋ฐ์ผ๋ก ์ค๊ณ๋์๋ค. ํ์ง๋ง ์ค์ ๋ก๋ ๋์์ธํจํด์์ ๋งํ๋ Proxyํจํด๊ณผ๋ ์กฐ๊ธ ๋ค๋ฅธ๋ฐ, ๋์์ธํจํด์์ Proxyํจํด์ ํ๊ฒ์ ๋ํ ๊ธฐ๋ฅ์ ํ์ฅํ์ง๋ ์๊ณ , Client๊ฐ Target์ ์ ๊ทผํ๋ ๋ฐฉ์์ ๋ณ๊ฒฝํ๋ ์ฝ๋ ํจํด์ ์๋ฏธํ๊ธฐ ๋๋ฌธ์ด๋ค.
์คํ๋ง์์ ๋งํ๋ ํ๋ก์๋ ๋ฆฌํ๋ ์ ๊ณผ ๋ฐ์ดํธ์ฝ๋ ์กฐ์์ ์ด์ฉํด ์ค์ ํ๊ฒ์ ๊ธฐ๋ฅ์ ๋์ ์ํํ๋ฉด์, ๊ธฐ๋ฅ์ ํ์ฅํ๊ฑฐ๋ ์ถ๊ฐํ ์๋ ์๋(OCP์์น) ๋ค์ด๋๋ฏน ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
์ข ๋ ์ฝ๊ฒ๋งํ์๋ฉด, ์คํ๋ง AOP๋ [๋ฐํ์์ ํ๋ก์ ์ธ์คํด์ค๊ฐ ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋๋] ๋ค์ด๋๋ฏน ํ๋ก์ ๊ธฐ๋ฒ์ผ๋ก ๊ตฌํ๋์ด์ ธ์๋ค.
# JDK Dynamic Proxy
์๋ฐ์์ ์ ๊ณตํ๋ API (java.lang.reflect.Proxy)๋ฅผ ์ฌ์ฉํ๋ฉฐ ์ธํฐํ์ด์ค ๊ธฐ๋ฐ์ผ๋ก Proxy๋ฅผ ์์ฑํ๋ค. ์ฌ์ฉ๋ฐฉ๋ฒ์๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ง๋ง ๊ฐ๋ฐ์๋ InvocationHandler ๊ฐ์ฒด์ invoke()๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ ์ค์ ๊ฐ์ฒด์ ์ ๋ณด๋ฅผ ๋ฐ์์ค๊ณ ์กฐ์ํ๋ฉด ๋๋ค.
์ด๋ ๊ฒ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ํ๋ํ๋ ์ง์ ๋ง๋๋๊ฒ ์๋๋ผ, ๋ฐํ์ ์์ ์ [ํด๋์ค ์ ๋ณด Object.class]๋ฅผ ์ด์ฉํ์ฌ ์ด๋ ธํ ์ด์ , ๋ฉ์๋์ ๋ฐ๋ผ ๋์ ์ผ๋ก ๋ค๋ฅธ ๋ฉ์๋ ๋์์ ์คํํ๋๋ก ํ๋ก์๋ฅผ ๋ง๋ค ์ ์๋ค.
// BookService ์ธํฐํ์ด์ค์ ํ๋ก์ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๋ฐํ์์ ๋์ ์ผ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ.
BookService bookService = (BookService) Proxy.newProxyInstance(
BookService.class.getClassLoader() // ํ๋ก์๋ฅผ ๋ง๋ค ClassLoader
,new Class[]{BookService.class} // ํ๋ก์๋ฅผ ๋ง๋ค ์ธํฐํ์ด์ค
,new InvocationHandler() { //invoke handler, ํ๋ก์์ ๋ด์ฉ. ์ง์ ์์ฑํ ๊ตฌํ์ฒด
BookService bookService = new DefaultBookService();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ์๋ฌด๋ฐ ๋์๋ ํ์ง์๊ณ , ๋จ์ํ ์ค์ ๊ฐ์ฒด์๊ฒ ์์ํ๋ ํ๋ก์ ์ฝ๋.
// Object invoke = method.invoke(...)๋ฑ์ผ๋ก ๋ฆฌํ๋ ์
์กฐ์๊ฐ๋ฅ.
// method.invoke(๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด , ๋ฉ์๋์ ์ ๋ฌํ ํ๋ผ๋ฉํ)
// ์ฌ๊ธฐ์ ์ฝ๋๋ฅผ ์์ฑํ๋ฉด ๊ฐ์ฒด์ ๋ชจ๋ ๋ฉ์๋๊ฐ ๋์ผํ ์ํฅ์ ๋ฐ๋๋ค.
return method.invoke(bookService, args);
}
});
์๋ฅผ ๋ค์ด BookService ์ธํฐํ์ด์ค์ ํน์ ๋ฉ์๋( ex rent() )์ ์ถ๊ฐ์ ์ธ ๋์์ ํ๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด, ์๋์ ๊ฐ์ด ์์ฑํ๋ฉด ๋๋ค. ํ์ํ๋ค๋ฉด ๋ค๋ฅธ ๊ฐ์ฒด์์ ๋ฉ์๋๋ฅผ ์คํํ๋๋ก ๋ฐ๊ฟ์ ์๋ค. (invoke์ ์ฒซ๋ฒ์งธ ์ธ์)
if (method.getName().equals("rent")) {
System.out.println("aaaa ์คํ ์ ์ถ๊ฐ ๋์");
// method.invoke(๋ฉ์๋๋ฅผ ํธ์ถํ ๊ฐ์ฒด , ๋ฉ์๋์ ์ ๋ฌํ ํ๋ผ๋ฉํ)
Object invoke = method.invoke(bookService, args);// ๋ฉ์๋๋ฅผ ์คํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ๋๋ค.
System.out.println("bbbb ์คํ ํ ์ถ๊ฐ ๋์");
return invoke; // ์ด์ ์ด ๋ฉ์๋๋ ์ฌ๊ธฐ์ returnํ ๋ฐํ๊ฐ์ ๊ฐ์ง๊ฒ ๋๋ค.
}
๋ค๋ง ์ฌ์ฉํด๋ณด๋ฉด ์๊ฒ ์ง๋ง, ํน์ ๋ฉ์๋๋ง ์ฌ์ฉํ๊ณ ์ถ๋๋ผ๋ [ํด๋น ๊ฐ์ฒด ์ ๋ณด]๋ฅผ ๋ฆฌํ๋ ์ (object.class)์ ํตํด ํต์งธ๋ก ๊ฐ์ ธ์์ ์์ ์์ ์ฒ๋ผ ์กฐ๊ฑด๋ฌธ์ ์ด์ฉํด ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. ์ฝ๋๊ฐ ์๋นํ ๋ณต์กํด์ง๋ค.
# CGlib proxy
CGlib๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ฃผ๋ ์ฝ๋ ์์ฑ(Code gen)๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
- JDK ํ๋ก์๋ ์ธํฐํ์ด์ค์ ์ ํ์๋ ๋ชจ๋ ๋ฉ์๋์ ํ๋ก์๋ฅผ ์ ์ฉ์ํจ๋ค. ๊ทธ๋ฆฌ๊ณ Class<T>์ ๋ณด๋ก ์กฐ๊ฑด๋ฌธ์ ๋ง๋ค์ด ํน์ ๋ฉ์๋๋ง ์ถ๊ฐ๋์์ ํ๋๋ก ๋ง๋ค ์ ์๋ค.
- CGlib๋ MethodMatcher ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ๋ฉ์๋๋ง ํ๋ก์ํ ํ๊ณ , ๋๋จธ์ง๋ ํ๋ก์๋ฅผ ๊ฑฐ์น์ง ์๊ณ ์ค์ ๊ฐ์ฒด ๋ฉ์๋๋ฅผ ํธ์ถํ๋๋ก ๋ง๋ค ์ ์๋ค.
- ์ด๊ฒ ๊ฐ๋ฅํ ์ด์ ๋ CGlib๋ ์ธํฐํ์ด์ค๊ฐ ์๋ ํ๊ฒ ๊ฐ์ฒด๋ฅผ ์ง์ ์์๋ฐ์ ๋ง๋ค๊ธฐ ๋๋ฌธ์ด๋ค.
MethodInterceptor handler = new MethodInterceptor() {
private final MethodMatcher methodMatcher; // ํน์ ๋ฉ์๋๋ฅผ ์ฐพ๋ ๊ฐ์ฒด
BookService bookService = new BookService();
public MethodInterceptor(MemthodMatch m){
this.methodMatcher = m;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy
methodProxy) throws Throwable {
if (methodMatcher.matches(method)) {
// CGlib๋ ์์๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ์ ํน์ ๋ฉ์๋๋ง ํ๋ก์๋ก ๋ฐ๊ฟ ์ ์์
// JDK ๋ค์ด๋๋ฏน ํ๋ก์์ ๋ค๋ฅด๊ฒ ํ์์๋ ๋ฉ์๋๋ ํ๋ก์๋ฅผ ์๊ฑฐ์น๊ฒ ํ ์์์.
return methodName.toUpperCase();
}
return method.invoke(bookService, objects);
}
};
// CGlib๋ก ์กฐ์ํ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฝ์
BookService bookService = (BookService) Enhancer.create(BookService.class, handler);
# ๊ทธ๋์ ์ด๊ฑธ ์คํ๋ง AOP์ ์ด๋ป๊ฒ ์ ์ฉํ๋๋ฐ์?
- [JDK ํ๋ก์์ InvocationHandler], [CGlib์ MethodInterceptor]๋ ์คํ๋ง AOP์์ JoinPoint ๊ฐ๋ ์ด๋ค.
- [JDK ํ๋ก์์ ์กฐ๊ฑด๋ฌธ], [CGlib์ MethodMatcher]๋ ์คํ๋ง AOP์ PointCut ๊ฐ๋ ์ด๋ค.
- [JDK invoke ๋ฉ์๋ ๋ด์ฉ], [CGlib ์ Intercept ๋ฉ์๋ ๋ด์ฉ]์ ์คํ๋ง AOP์ Advice ๊ฐ๋ ์ด๋ค.
๋ค๋ง ์คํ๋ง AOP๋ฅผ ํ์ฉํ๋ค๊ณ ํด์ ํ๋ก์๋ฅผ ์ฒ์๋ถํฐ ๊ตฌํํ์ง๋ ์๋๋ค. @AspectJ๊ณผ ์ด๋ป๊ฒ Advice๋ฅผ ์ง์ ํ ๊ฑด์ง์ ๋ํ ์ค์ (@Before, @Around, @AfterThrowing...) ๊ทธ๋ฆฌ๊ณ ํน์ ์กฐ๊ฑด์ ํํฐ๋งํ Expression์ ๊ธฐ๋ฐ์ผ๋ก PointCut ์์ค์ ํ๋ค.
# ์คํ๋ง AOP์ ๋ํด ๊ฐ์ ์ก์๋ณด์
@ AOP ๋?
๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ(Aspect Oriented Progamming) ๊ธฐ๋ฒ์ ๊ฐ์ฒด์งํฅ์ ๋ณด์ํ๋ ์๋จ์ผ๋ก, ํฉ์ด์ง ๊ด์ (Aspect)๋ฅผ ๋ชจ๋ํ ํ์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ํค์น์ง ์๊ณ ์ฌ์ฌ์ฉํ๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ด๋ค.
์คํ๋ง์์๋ ์ด๋ ธํ ์ด์ ์ ํตํด AOP๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋๋ก ๋ง๋ค์ด์ค๋ค.
@Component
@Aspect // ๋ชจ๋ ๋ฉ์๋์ ์ฑ๋ฅ์ ์๊ฐ์ผ๋ก ์ธก์ ํ๋ Cross-cutting corncern ๊ฐ์ฒด
public class TimeTraceAop {
@Around("execution(* hello.hellospring..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START: " + joinPoint.toString());
try {
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END: " + joinPoint.toString() + timeMs + "ms");
}
}
}
@ AOP์์ ์ฌ์ฉํ๋ ์ฉ์ด
Aspect : ๊ณตํต ๊ด์ฌ์ฌ(Cross-cutting corncern)์ ๋ชจ๋ํ ํ ๊ฒ
Target : Aspect(๊ณตํต๊ด์ฌ์ฌ)๋ฅผ ์ ์ฉํ ํต์ฌ๋ก์ง์ ๊ฐ์ง ๊ฐ์ฒด
Weaving - Aspect ๋ฅผ ๋์ ๊ฐ์ฒด(Target)์ ์ฐ๊ฒฐ์์ผ AOP ๊ฐ์ฒด๋ก ๋ง๋๋ ๋ฐ์ดํธ ์ฝ๋ ๋ฐ ๊ฐ์ฒด ์กฐ์๊ณผ์
Advice : Aspect(๊ณตํต๊ด์ฌ์ฌ)์ ๋์์ ์ ์ ๊ฒ. Aspect์ ๊ตฌํ์ฒด (๊ฐ์ฒด์ ๋ฉ์๋์กฐ์)
- Join Point : Advice๊ฐ ์ ์ฉ๋๋ ์์ . (๋ฉ์๋ ์คํ, ์์ฑ์ ํธ์ถ, ํ๋ ๊ฐ ๋ณ๊ฒฝ๊ฐ์ ํน์ํ ์คํ ์์ )
return joinPoint.proceed(); - Pointcut : [Join Point]์ ์ ๊ท์ => ์คํ ์คํ, Pointcut์ด ์ผ์นํ๋ ๊ฐ์ฒด๋ค์๊ฒ Aspect ์ ์ฉ(์กฐ๊ฑด๋ฌธ)
@Pointcut("execution(* hello(..))")
@ AOP๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ(AspectJ ์ ์คํ๋งAOP)
AOP๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๊ณ , ๊ทธ๋งํผ ๋ค์ํ AOP ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๊ตฌ๋ค์ด ์กด์ฌํ๋ค. ๋๋ถ๋ถ ๋ฐ์ดํธ์ฝ๋ Weaving์ ์ฌ์ฉํ์ฌ ๊ตฌํํ๋ฉฐ ๋๋ถ๋ถ AspectJ์ Spring AOP ์ด 2๊ฐ์ง ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ AOP๋ฅผ ๊ตฌํํ๋ค.
- Spring AOP ๋ ์คํ๋ง์์ ์ฌ์ฉํ ์ ์๋ ๊ฐ๋จํ AOP ๊ธฐ๋ฅ๋ง์ ์ ๊ณตํ๋ค.
- CGlib๋ฑ์ ๋ฐ์ดํธ์ฝ๋ ์กฐ์์ ์ด์ฉํ ๋ค์ด๋๋ฏน ํ๋ก์๋ฅผ ์ฌ์ฉํด์ AOP ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
- ๋ฐํ์ ์์ ์ ๋์ ์ผ๋ก ๋ณํ ์ ์๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ด์ฉํ๊ธฐ์ ์ฑ ์ฑ๋ฅ์ ์ํฅ์ ๋ผ์น ์ ์๋ค.
- AspectJ ๋ ์๋ฐ์์ ์๋ฒฝํ AOP ์๋ฃจ์
์ ๊ณต์ ๋ชฉํ๋กํ๋ ๊ธฐ์ ์ด๋ค.
- [ .aj ํ์ผ]์ ์ด์ฉํ assertj ์ปดํ์ผ๋ฌ๋ฅผ ์ถ๊ฐ๋ก ์ฌ์ฉํ์ฌ ์ปดํ์ผ ์์ ์ด๋ JVM ํด๋์ค ๋ก๋์์ ์ ์กฐ์ํ๋ค.
- ๋ฐํ์ ์์ ์๋ ์ํฅ๋ผ์น์ง ์๋๋ค. ์ฆ ์ปดํ์ผ์ด ์๋ฃ๋ ์ดํ์๋ ์ฑ ์ฑ๋ฅ์ ์ํฅ์ด ์๋ค.
- ๋ฐ์์ ๋ชธ์ผ๋ก ๋๋ผ๊ฒ ์ง๋ง, Spring AOP์ ๋นํด ์ฌ์ฉ๋ฐฉ๋ฒ์ด ๋ค์ํ๊ณ ๋ด๋ถ ๊ตฌ์กฐ๊ฐ ๊ต์ฅํ ๋ณต์กํ๋ค.
์ฐธ๊ณ ๋ก spring aop๋ฅผ ๊ฐ๋ฐํ ๋, AspectJ์ ๊ฐ๋ฐ์๊ฐ CTO๋ก ์ฐธ์ฌํ๋ค๊ณ ํ๋ค.
# AspectJ ์ SpringAOP ๋น๊ตํ๊ธฐ
@1. ๊ธฐ๋ฅ๊ณผ ๋ชฉํ๊ฐ ๋ค๋ฅด๋ค.
- Spring AOP๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ์ง๋ฉดํ๋ ์ผ๋ฐ์ ์ธ ๋ฌธ์ ํด๊ฒฐ์ ์ํด Spring IoC์์ ์ ๊ณตํ๋ ๊ฐํธํ AOP ๊ธฐ๋ฅ์ด๋ค. ์ด๋์๋ ์ธ ์ ์๋ ์๋ฒฝํ AOP ์๋ฃจ์
์ด ์๋๋ผ, [Spring ์ปจํ
์ด๋๊ฐ ๊ด๋ฆฌํ๋ Bean]์๋ง ์ฌ์ฉํ๋ ค๊ณ ๋ง๋ค์๊ณ , ์ค์ ๋ก ์ฌ๊ธฐ์๋ง AOP๋ฅผ ์ ์ฉ ํ ์ ์๋ค.
- AspectJ๋ [์๋ฐ์ฝ๋์์ ๋์ํ๋ ๋ชจ๋ ๊ฐ์ฒด]์ ๋ํด ์๋ฒฝํ AOP ์๋ฃจ์ ์ ๊ณต์ ๋ชฉํ๋ก ํ๋ ๊ธฐ์ ์ด๋ค. ์ฑ๋ฅ์ด ๋ฐ์ด๋๊ณ ๊ธฐ๋ฅ์ด ๋งค์ฐ ๊ฐ๋ ฅํ์ง๋ง ๊ทธ๋งํผ Spring AOP์ ๋นํด ์ฌ์ฉ๋ฐฉ๋ฒ์ด๋ ๋ด๋ถ ๊ตฌ์กฐ๊ฐ ํจ์ฌ ๋ ๋ณต์กํ๋ค.
@2. Weaving ๋ฐฉ๋ฒ์ด ๋ค๋ฅด๋ค.
Weaving์ ๊ณตํต๊ด์ฌ์ฌํญ(Aspect)์ ๋์์ฝ๋(Advice)๋ฅผ ๋์ ๊ฐ์ฒด(Target)์ ์ฐ๊ฒฐ์์ผ ๊ด์ ์งํฅ์ ๊ตฌํํ ๊ฐ์ฒด๋ก ๋ง๋๋ ๊ณผ์ ์ด๋ค. ์ข ๋ ์ฝ๊ฒ๋งํ๋ฉด AOP๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ๋ฐ์ดํธ์ฝ๋ ์กฐ์ ๋ฐฉ๋ฒ์ ์๋ฏธํ๋ค๊ณ ์๊ฐํ๋ฉด ๋๋ค.
* ์์ค์ฝ๋๋ก ์๋น์ ๊ตฌํ(Source-code Weaving)ํ๋๊ฒ ๊ฐ์ฅ ์ข๊ธด ํ๊ฒ ์ง๋ง, ํ์ฌ๊น์ง ์๋ฐ์ธ์ด๊ฐ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ผ๋ก๋ ์๋ฒฝํ AOP๋ฅผ ๊ตฌํํ๊ธฐ ์ด๋ ต๋ค. ์ต์ง๋ก ๋น์ทํ๊ฒ ๋ง๋ค์ด๋ด์ผ ์ฝ๋๊ฐ ๋ณต์กํด์ ธ ์ ์ง๋ณด์๊ฐ ์ด๋ ต๊ณ ์ค๋ฒํค๋๊ฐ ์ฌํด์ง๊ธฐ์ ์์ง๊น์ง๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ์ฌ ์ ๊ณตํ๋ AOP ๋๊ตฌ๋ง ์กด์ฌํ๋ค.
* ์ฐธ๊ณ ๋ก ๊ฐ ์๋น ๋ฐฉ๋ฒ์ ์๊ธ์๋ฅผ ๋ฐ์ RTW CTW, BW(๋๋ PCW), LTW ๋ผ๊ณ ์ค์ฌ์ ๋ง์ด ์ฌ์ฉํ๋ค. ์ ๊ธฐ ํ๋๋๊น.
Spring AOP๋ ์์์ ์ค๋ช ํ ๋ฐํ์ ์๋น(๋ค์ด๋๋ฏน ํ๋ก์)๋ฅผ ์ฌ์ฉํ๋ค.
- ์๋ฐ์ ๋ฆฌํ๋ ์ API์ CGlib๋ฑ์ ๋๊ตฌ๋ก ๋ฐํ์์ ๋์ ์ธ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค.
- ๋์ ์ธ ํ๋ก์ ๊ฐ์ฒด๋, ํด๋์ค์ ์ ๋ณด์ ๋ฐ๋ผ ๋ฐํ์์์ ๋ค๋ฅด๊ฒ ๊ตฌํ๋๋๋ก ๋ง๋๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํ๋ค.
- ๋ณต์กํ ์ค์ ์์ด Spring ๋น ๋ฑ๋ก์ ํ๊ฒ๋๋ฉด ์๋์ผ๋ก ๋ฑ๋ก๋์ด ์ฌ์ฉํ๊ธฐ ๋งค์ฐ ํธํ๋ค.
- ๊ทผ๋ฐ ๋ฐํ์์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ ๋งํผ, ์ค๋ฒํค๋๊ฐ ์ฌํ๊ณ ์ฑ๋ฅ์ ์ํฅ์ ํฌ๊ฒ ๋ฏธ์น ์ ์๋ค.
๋ฒค์น๋งํน์ AspectJ๊ฐ Spring AOP๋ณด๋ค ์ต์ 8๋ฐฐ, ์ต๋ 35๋ฐฐ์ ๋ ๋น ๋ฅด๋ค.
AspectJ๋ 3๊ฐ์ง ์ ํ์ Weaving์ ์ ๊ณตํ๋ค.
- 1. Compile-Time ์๋น : AspectJ ์ ์ฉ ์ปดํ์ผ๋ฌ๋ฅผ ์ด์ฉํ์ฌ Aspect ๋ถ๋ถ๊ณผ Target ์ฝ๋ ๋ถ๋ถ์ ์
๋ ฅ์ผ๋ก ๋ฐ๊ณ ํ๋๋ก ์ฎ์ธ ๋ฐ์ดํธ์ฝ๋(.class)๋ฅผ ์์ฑํ๋ค. ์ปดํ์ผ์ด ์๋ฃ๋ ์ดํ์๋ ์ฑ์ ์ฑ๋ฅ์ ์ ํ ์ํฅ์ ๋ผ์น์ง ์๋๋ค.
- 2. Post-Complie ์๋น : ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ Weaving ํ ๋ ์ฌ์ฉํ๋ค. [Compile-Time ์๋น]๊ณผ ๊ฑฐ์ ๋์ผํ ๋์์ ํ๋ค. ๋ณดํต ํด๋์คํ์ผ์ JAR์ ์ฎ๊ธฐ ์ํด์ ์ฌ์ฉํด์ [Binary ์๋น]์ด๋ผ๊ณ ๋ถ๋ฅด๋๊ฒ ์ผ๋ฐ์ ์ด๋ค.
- 3. Load-time ์๋น : ์ ์ฉ ์ปดํ์ผ๋ฌ๋ฅผ ์ฌ์ฉํ์ง์๊ณ , ์กฐ์๋์ง ์์ ๋ฐ์ดํธ์ฝ๋(.class)๋ฅผ ๊ฐ JVM์ ๋ก๋ ๋ ๋ ClassLoader๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ ์๋น ๋ฐฉ์์ด๋ค. ๊ฐ์ฒด๋ฅผ ๋ก๋ํ ๋ ์๋น์ด ์ผ์ด๋๋ ๊ฑฐ๋ผ ์ฑ ์ฑ๋ฅ์ ํ๋ฝ์ ๋ฐ์์ํฌ ์ ์๋ค.
์ฐธ๊ณ ๋ก CTW, LTW๋ ๋์์ ๊ฐ์ ์ธํฐํ์ด์ค์์ ์ค์ ๊ฐ์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์๋ค.
// ๊ธฐ๋ณธ๊ฐ, ์ปดํ์ผ ํ์ ์๋น
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ, order = 0)
// ๋ก๋ ํ์ ์๋น
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ, order = 0)
@EnableLoadTimeWeaving
CTW(Complie-Time Weaving) vs LTW(Load-time Weaving)
* LTW (Load-Time Weaving)
- JVM์ด ๋ฐ์ดํธ์ฝ๋(.class) ๋ก๋ํ ๋ AspectJ์ด ๊ฐ๋ก์ฑ์ ์๋น๋ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ ๋ฐฉ์.
- CTW์ ๋ค๋ฅด๊ฒ ์คํ๋๊ธฐ ์ ๊น์ง๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ธฐ๋๋ฌธ์ ์ปดํ์ผ ์๊ฐ์ด ์งง์์ง๋ค๋ ์ฅ์ ์ด ์์ง๋ง ํด๋์ค๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ผ๊ฐ๋ ๊ณผ์ ์์ ์๋น์ด ์ผ์ด๋๊ธฐ ๋๋ฌธ์ [Complie-Time ์๋น]๊ณผ ๋ค๋ฅด๊ฒ ๋ฐํ์ ์ฑ๋ฅ์ ์ํฅ์ ๋ผ์น ์ ์๋ค.
- ๋ํ ์คํ๋ง์์ ์ฌ์ฉํ ์ App..Context์ ๊ฐ์ฒด๊ฐ ๋ก๋๋ ๋, [aspectj ์๋น]์์ ๋ฟ๋ง ์๋๋ผ [Spring-instrument]๋ ๊ฐ๊ฐ ๊ฐ์ฒด์ ๋ํ ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ๋ฅผ ํด์ค์ผํ๋ค. Spring-instrument๋ aspectj์ class loader๋ฅผ ์์ํ๋ ์ญํ ์ ๋งก๋๋ค. => ์ฑ๋ฅ ํ๋ฝ, ๋ฌผ๋ก LTW ์ค์ ์ ํตํด ์ฑ๋ฅ ํ๋ฝ์ ๋ง์ ์ ์๋ค.
- ์ด๋ ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด์๋ JVM argument์ ๋ค์๊ณผ ๊ฐ์ ์ต์
์ ์ถ๊ฐํด์ผํ๋ค.
-javaagent:/fullpath/aspectjweaver-1.8.1.jar -javaagent:/fullpath/spring-instrument-4.0.6.RELEASE.jarโ
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ LTW๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ [๋ฐํ์ ์๋น]์ฒ๋ผ ๋์ ์ธ ์๋น์ ๊ตฌํํ ์ ์๊ธฐ ๋๋ฌธ.
* CTW (Compile-Time Weaving)
- ์์ ์ปดํ์ผํ๋ ์์ ์ AspectJ ์ปดํ์ผ๋ฌ๋ฅผ ์ด์ฉํ์ฌ ํ๋์ ๋ฐ์ดํธ์ฝ๋(.class)๋ก ๋ง๋ค์ด๋ฒ๋ฆฌ๋ ๋ฐฉ์.
- ์ปดํ์ผ์ด ์๋ฃ๋ ๋ฐ์ดํธ์ฝ๋๋ ์ด๋ ํ ์๋น๋ ์ผ์ด๋์ง ์๊ธฐ์ ์ฑ ์ฑ๋ฅ์ ์ ํ ์ํฅ์ด ์๋ค.
- ๋ค๋ง lombok๊ณผ ๊ฐ์ด ์ปดํ์ผ ๊ณผ์ ์์ ์กฐ์์ ํ๋ ํ๋ฌ๊ทธ์ธ๊ณผ ์ถฉ๋ํ์ฌ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ด ๋งค์ฐ ๋๋ค. (์ฌ์ค์ ๊ฐ์ด ์ฌ์ฉํ์ง ๋ชปํ๋ค.)
@3. ๊ฒฐ๋ก
Spring AOP๊ฐ ์ฑ๋ฅ๊ณผ ๊ธฐ๋ฅ์ ๋งค์ฐ ๋ถ์กฑํ์ง๋ง, Spring Bean์ ์๋์ผ๋ก ์ ์ฉ๋๊ณ ์ค์ ํ๊ธฐ ๋งค์ฐ ํธ๋ฆฌํ๋ค. ๋ํ AspectJ์ ๋ค๋ฅด๊ฒ ์ปดํ์ผ ์์ ์ ๊ฑด๋๋ฆฌ๋๊ฒ ์์ด์ ๊ฐ์ข ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Lombok)๊ณผ ํธํ์ฑ์ด ๋ฐ์ด๋๋ค.
ํ์ง๋ง Spring AOP๋ ์ปจํ ์ด๋ ์์ Bean๋ง ์กฐ์ํ ์ ์๊ณ , JoinPoint๋ฅผ ๋ฉ์๋ํธ์ถ์์ ๋ฐ์ ์ ์ฉ ๋ชปํ๋ค๋ ๋จ์ ์ด ์๋ค. ๋ฐ๋ฉด์ AspectJ๋ ๋ฐํ์์ด ์๋ ์ปดํ์ผ ์์ ์ ๋์ํ๋ ๋๊ตฌ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด ๋ค์ํ ์์ ์ ์ง์ ํ ์ ์๋ค.
# ๋จธ๋ฆฌ์ํ๋ค.. ์คํ๋ง AOP ์ฌ์ฉ๋ฐฉ๋ฒ์ด๋ ์์๋ณด์
@ ํ๋์ ๋ณด๋ ์คํ๋งAOP
๋ค? ์คํ๋ง๋ถํธ๋ ์ ๋ถ CGLib๋ก ํ๋ก์๋ฅผ ๊ตฌํํ๋ค๊ณ ์?
์ฐธ๊ณ ๋ก ์คํ๋ง 3.2 ์ด์ ์๋ AOP ํ๊น์ด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค๋ฉด JDK๋ฅผ, ์๋๋ผ๋ฉด Class ๋ฐฉ์์ ์ฌ์ฉํ๋๊ฒ ๊ธฐ๋ณธ๊ฐ์ด์๋ค. (๊ถ์ฅ์ ์ํ์ง๋ง ์ง๊ธ๋ ์ค์ ์์ ๋ณ๊ฒฝ๊ฐ๋ฅ)
@ ์คํ๋ง AOP ํต ์คํํฐ
1. ์์กด์ฑ ์ถ๊ฐ
dependencies {
implementation('org.springframework.boot:spring-boot-starter-aop')
}
2. Aspect ํด๋์ค ๋ง๋ค๊ธฐ
- ์คํ๋งAOP๋ Bean(@Component, @Bean)์ผ๋ก ๋ฑ๋ก๋ ๊ฐ์ฒด๋ง Aspect๋ก ๋ง๋ค ์ ์๋ค.
@Component
@Aspect
public class PerfAspect {
// ์์๋ ํ์ง ์์๋๋ฐ logPerf ๋ฉ์๋๋ฅผ ์ฌ์ฉ ํ ์ ์๋ ์ด์ => ๋ฐํ์ ๋์ ํ๋ก์
@Around("@annotation(PerfLogging)")
public Object logPerf(ProceedingJoinPoint joinPoint) throws Throwable { ... }
}
3. Aspect์ ๋์ ์ฝ๋ (Advice) ์์ฑํ๊ธฐ
- @Around๋ฅผ ๋ฉ์๋์ ๋ถ์ฌ ํตํด Target์ ์, ๋ค์ ๊ณตํต๊ด์ฌ๋ถ๋ถ์ ์ฝ๋ (Advice)๋ฅผ ์์ฑํ ์ ์๋ค.
- ๋ฉ์๋์์ Target ๋ฉ์๋๊ฐ ์คํ๋ ์ง์ ์ joinPoint.proceed()๋ฅผ ํธ์ถํด์ฃผ๋ฉด ๋๋ค.
// @Around("execution(* hello.hellospring..*(..))") ์ด๋ ๊ฒ ์ฐ๋ฉด ์ ๊ท์์ผ๋ก ํด๋์ค ํํฐ๊ฐ๋ฅ
@Around("@annotation(PerfLogging)") // @perfLoggin ์ด๋
ธํ
์ด์
์ AOP ์ ์ฉ
public Object logPerf(ProceedingJoinPoint joinPoint) throws Throwable {
//Advice๊ฐ ์ ์ฉ๋ ๋์ (๋ฉ์๋ ๊ทธ ์์ฒด)
long start = System.currentTimeMillis();
Object retVal = joinPoint.proceed(); // Target ๋ฉ์๋๊ฐ ์คํ๋ ์์
System.out.println(System.currentTimeMillis() - start);
return retVal;
}
- ๋ง์ฝ ๋ฉ์๋ ์คํ์ด์ , ์ดํ ๋์์ ๋ถ๋ฆฌํ๊ณ ์ถ๋ค๋ฉด ์์์ ์ธ๊ธํ @Before @After ๋ฑ์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.
@Before("bean(myEventService)")
public void Hello(JoinPoint jp) {
System.out.println("Hello");
}
3-1 Aspect ํด๋์ค ๊ตฌํ ์์
์๋ฅผ ๋ค์ด @LoginAuth ํ๊ทธ๊ฐ ๋ถ์ ๋น์ Session ๊ฒ์ฆ์ ํด์ฃผ๋ Aspect ๋ชจ๋์ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด, ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.
// ์์ค์ ํจํค์ง ๊ฒฝ๋ก๊ฐ ๋ค๋ฅผ ๊ฒฝ์ฐ ํด๋์ค๋ช
๋์ ์ ์ ์ฒด ํจํค์ง๋ช
์ ์
๋ ฅํด์ฃผ๋ฉด ๋จ.
@Around("@annotation(project.board.annotation.LoginAuth)")
public String loginAuth(ProceedingJoinPoint pjp) throws Throwable {
HttpSession session = null;
for(Object o : pjp.getArgs()) {//pjp.getArgs()๋ Target์ ๋๊ฒจ์ง ๋งค๊ฐ๋ณ์๋ค.
if(o instanceof HttpSession) {
session = (HttpSession) o;
}
}
if(session.getAttribute("memberId")==null) {
return "member/login";
}
return (String) pjp.proceed();
}
4. ํฌ์ธํธ์ปท @PointCut("~") ์ ๊ทํํ์ ์ฌ์ฉ
- ํฌ์ธํธ์ปท์ด๋ Aspect๋ฅผ ์ ์ฉ์ํฌ Target ๊ฐ์ฒด๋ฅผ ์ง์ ํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
- ์์๋ ๋งํ์ง๋ง ํฌ์ธํธ์ปท์ @Around("~์ฌ๊ธฐ~")์ ์์ฑํด๋ ๋๋ค.
- ์ ๊ทํํ์์ ์ด๋ค๊ณ ํ๋ค, ์คํ๋ง AOP๋ ๋ฉ์๋์๋ง JoinPoint๋ฅผ ๋ถ์ผ ์ ์๋ค. (ํ๋ ๊ฐ์๊ฑฐ ์๋จ)
@Pointcut("excution(...์ ๊ทํํ์...)")
execution([์ ๊ทผ์ ํ์ํจํด] ๋ฆฌํด๊ฐ_ํจํด [ํ์
ํจํด.] ๋ฉ์๋์ด๋ฆ_ํจํด (ํ๋ผ๋ฏธํฐ_ํ์
_ํจํด))
// [...] ๋ถ๋ถ์ ์๋ตํด์ ์ ์ด๋ ์๊ด์๋ค.
execution(๋ฆฌํด๊ฐ_ํจํด ๋ฉ์๋์ด๋ฆ_ํจํด (ํ๋ผ๋ฏธํฐ_ํ์
_ํจํด))
@Pointcut("execution(* hello(..))") // ์ด๋ฆ์ด hello์ธ ๋ชจ๋ ๋ฉ์๋
@Around("@annotation(project.board.annotation.LoginAuth)") // @LoginAuth๊ฐ ๋ถ์ ๋ฉ์๋
@Around("execution(* hello.hellospring..*(..))") // hello.hellospring. ํจํค์ง ์ ๋ชจ๋ ๋ฉ์๋
ํฌ์ธํธ์ปท์ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ์๋ ์๋ค. all() ๋ฉ์๋์ ํฌ์ธํธ์ปท์ ์ ์ฉ์ํค๊ณ ๋๋ ค์ฐ๋ ๋ฐฉ์
public class Hi{
// ๋ชจ๋ ํ์
[๋ฐํํ์
, ๋ฉ์๋์ด๋ฆ, ๋งค๊ฐ๋ณ์]์ค ์ด๋ฆ์ด hello์ธ ๋์
@Pointcut("execution(* hello(..))")
private void all(){}
@Around("all()")
public Object printParametersAndReturnVal(ProceedingJoinPoint pjp) throws Throwable{
...
Object ret = pjp.proceed();
...
return ret;
}
}
# ๋ ํผ๋ฐ์ค
https://gmoon92.github.io/spring/aop/2019/04/20/jdk-dynamic-proxy-and-cglib.html
https://logical-code.tistory.com/118
https://kils-log-of-develop.tistory.com/638
'๐ฑ Spring Framework > Spring Core' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
DB ํธ๋์ญ์ ๊ณผ ์ปค๋ฅ์ ์ดํดํ๊ธฐ (2) | 2021.08.25 |
---|---|
DB์ @Transactional์ ์ฌ์ฉํ ๋ ์์ฃผ ๋์ค๋ ์ค์ (0) | 2021.08.18 |
@Transactional ์ ๋์์๋ฆฌ, ํธ๋์ญ์ ๋งค๋์ (5) | 2021.08.18 |
์ฝ๊ฒ ์ดํดํ๋ ์คํ๋ง AOP (~์์ฑ์ค~) (0) | 2021.08.18 |
ํ ๋น์์คํ๋ง#2 ์ฑ๊ธํค ๋ ์ง์คํธ๋ฆฌ์ ์ค๋ธ์ ํธ ์ค์ฝํ (0) | 2021.08.14 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev