JiwonDev

์ž๋ฐ” AOP์˜ ๋ชจ๋“  ๊ฒƒ(Spring AOP & AspectJ)

by JiwonDev

์ด ๊ธ€์€ ์‚ฌ์ „์ง€์‹์ด ์—†๋‹ค๋ฉด ์ฝ๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค. ๋ฐ”์ดํŠธ์ฝ”๋“œ์™€ ๋ฆฌํ”Œ๋ ‰์…˜์„ ๋ชจ๋ฅธ๋‹ค๋ฉด ์•„๋ž˜์˜ ๊ธ€์„ ๊ผญ ์ฝ์–ด๋ณด๋„๋กํ•˜์ž.

2021.08.17 - [๊ธฐ๋ณธ ์ง€์‹/Java ๊ธฐ๋ณธ์ง€์‹] - ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘(๋ฆฌํ”Œ๋ ‰์…˜, ๋‹ค์ด๋‚˜๋ฏน ํ”„๋ก์‹œ, ์• ๋…ธํ…Œ์ด์…˜ ํ”„๋กœ์„ธ์„œ)

 

๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘(๋ฆฌํ”Œ๋ ‰์…˜, ๋‹ค์ด๋‚˜๋ฏน ํ”„๋ก์‹œ, ์• ๋…ธํ…Œ์ด์…˜ ํ”„๋กœ์„ธ์„œ)

์Šคํ”„๋ง์—์„œ ๋‹ค์–‘ํ•œ ์„ค์ •๊ธฐ๋Šฅ๋“ค (@Autowried ๋“ฑ)์€ ์–ด๋–ป๊ฒŒ ์ฝ”๋“œ์—†์ด ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•˜๊ณ , ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ผ๊นŒ? ๋˜ Lombok๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ผ๊นŒ? ๊ทธ ๋น„๋ฐ€์€ ๋ชจ๋‘

jiwondev.tistory.com

 

์Šคํ”„๋ง์˜ ๋นˆ ํฌ์ŠคํŠธ ํ”„๋กœ์„ธ์„œ

๋”๋ณด๊ธฐ

๐Ÿ“Œ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 ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

ApplicationContext๋Š” ์ด 5๊ฐœ์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.
// ์ƒ๋žตํ•œ๊ฒŒ ์•„๋‹ˆ๋ผ, ์ „์ฒด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์˜์™ธ๋กœ ์‹ฌํ”Œํ•ฉ๋‹ˆ๋‹ค.
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 ๊ฐœ๋…์ด๋‹ค.

spring AOP, ์•„๋ž˜์—์„œ ์ฐจ๊ทผ์ฐจ๊ทผ ์„ค๋ช…ํ•  ์˜ˆ์ •์ด๋‹ค.

๋‹ค๋งŒ ์Šคํ”„๋ง AOP๋ฅผ ํ™œ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ ํ”„๋ก์‹œ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ตฌํ˜„ํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. @AspectJ๊ณผ ์–ด๋–ป๊ฒŒ Advice๋ฅผ ์ง€์ •ํ•  ๊ฑด์ง€์— ๋Œ€ํ•œ ์„ค์ •(@Before, @Around, @AfterThrowing...) ๊ทธ๋ฆฌ๊ณ  ํŠน์ • ์กฐ๊ฑด์„ ํ•„ํ„ฐ๋งํ•  Expression์„ ๊ธฐ๋ฐ˜์œผ๋กœ PointCut ์„์„ค์ •ํ•œ๋‹ค.

 


 

# ์Šคํ”„๋ง AOP์— ๋Œ€ํ•ด ๊ฐ์„ ์žก์•„๋ณด์ž

@ AOP ๋ž€?

๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Aspect Oriented Progamming) ๊ธฐ๋ฒ•์€ ๊ฐ์ฒด์ง€ํ–ฅ์„ ๋ณด์™„ํ•˜๋Š” ์ˆ˜๋‹จ์œผ๋กœ, ํฉ์–ด์ง„ ๊ด€์ (Aspect)๋ฅผ ๋ชจ๋“ˆํ™” ํ•˜์—ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ—ค์น˜์ง€ ์•Š๊ณ  ์žฌ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ•์ด๋‹ค.

AOP์˜ ์˜ˆ์ œ) [๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ๊ด€์‹ฌ์‚ฌ]์™€ [์„ค์ •, ๋กœ๊ทธ๋ถ€๋ถ„์˜ ๊ด€์‹ฌ์‚ฌ]๋ฅผ ๋ชจ๋“ˆ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์—†์„๊นŒ?

์Šคํ”„๋ง์—์„œ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด 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(..))"

์˜ˆ์ œ) ์‹œ๊ฐ„์ธก์ •๋กœ์ง์ด๋ผ๋Š” ๊ณตํ†ต๊ด€์‹ฌ์‚ฌํ•ญ์„ Aspect๋กœ ๋ชจ๋“ˆํ™” ํ•˜๊ณ  ์‹ถ๋‹ค.
@Aspect ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ๋‹ค์ด๋‚˜๋ฏน ํ”„๋ก์‹œ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๊ณตํ†ต๊ด€์‹ฌ์‚ฌํ•ญ์„ TimeTraceAOP๋กœ ๋ถ„๋ฆฌ์‹œ์ผฐ๋‹ค.

 


@ 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๋Š” ์ด 3๊ฐ€์ง€ ์œ ํ˜•์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ weaving์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

# 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๋ฐฐ์ •๋„ ๋น ๋ฅด๋‹ค. 

์ฐธ๊ณ ๋กœ ์˜› ์Šคํ”„๋ง์€ AOP ํƒ€๊นƒ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด JDK๋ฅผ, ์•„๋‹ˆ๋ผ๋ฉด Class ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค. (๊ถŒ์žฅ์€ ์•ˆํ•˜์ง€๋งŒ ์ง€๊ธˆ๋„ ์„ค์ •์—์„œ ๋ณ€๊ฒฝ๊ฐ€๋Šฅ)

 

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๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ์กฐ์ž‘์„ ํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ์ถฉ๋Œํ•˜์—ฌ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ๋†’๋‹ค. (์‚ฌ์‹ค์ƒ ๊ฐ™์ด ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค.)

์ปดํŒŒ์ผํƒ€์ž„, classLoader ํƒ€์ž„, ๋Ÿฐํƒ€์ž„


@3. ๊ฒฐ๋ก 

Spring AOP๊ฐ€ ์„ฑ๋Šฅ๊ณผ ๊ธฐ๋Šฅ์€ ๋งค์šฐ ๋ถ€์กฑํ•˜์ง€๋งŒ, Spring Bean์— ์ž๋™์œผ๋กœ ์ ์šฉ๋˜๊ณ  ์„ค์ •ํ•˜๊ธฐ ๋งค์šฐ ํŽธ๋ฆฌํ•˜๋‹ค. ๋˜ํ•œ AspectJ์™€ ๋‹ค๋ฅด๊ฒŒ ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ฑด๋“œ๋ฆฌ๋Š”๊ฒŒ ์—†์–ด์„œ ๊ฐ์ข… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Lombok)๊ณผ ํ˜ธํ™˜์„ฑ์ด ๋›ฐ์–ด๋‚˜๋‹ค.

Spring AOP๊ฐ€ ์‚ฌ์šฉ๋ฐฉ๋ฒ•๋„ ๊ฐ„๋‹จํ•˜๊ณ , ํ”Œ๋Ÿฌ๊ทธ์ธ ํ˜ธํ™˜์„ฑ๋„ ์ข‹๋‹ค. ํ•˜์ง€๋งŒ Bean์—๋งŒ ์ ์šฉ๊ฐ€๋Šฅํ•˜๊ณ  ์„ฑ๋Šฅ์ด ๋ณ„๋กœ..

ํ•˜์ง€๋งŒ Spring AOP๋Š” ์ปจํ…Œ์ด๋„ˆ ์•ˆ์˜ Bean๋งŒ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ณ , JoinPoint๋ฅผ ๋ฉ”์„œ๋“œํ˜ธ์ถœ์‹œ์ ๋ฐ–์— ์ ์šฉ ๋ชปํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ๋ฐ˜๋ฉด์— AspectJ๋Š” ๋Ÿฐํƒ€์ž„์ด ์•„๋‹Œ ์ปดํŒŒ์ผ ์‹œ์ ์— ๋™์ž‘ํ•˜๋Š” ๋„๊ตฌ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์–‘ํ•œ ์‹œ์ ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 


 

# ๋จธ๋ฆฌ์•„ํ”„๋‹ค.. ์Šคํ”„๋ง AOP ์‚ฌ์šฉ๋ฐฉ๋ฒ•์ด๋‚˜ ์•Œ์•„๋ณด์ž

@ ํ•œ๋ˆˆ์— ๋ณด๋Š” ์Šคํ”„๋งAOP

์Šคํ”„๋ง3.2 ์ดํ›„ CGlib๊ฐ€ Spring-Core์— ํฌํ•จ๋˜์—ˆ๊ณ , ์Šคํ”„๋ง๋ถ€ํŠธ์—์„œ๋Š” ์ „๋ถ€ CGLib๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

ํ”„๋ก์‹œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

 

๋„ค? ์Šคํ”„๋ง๋ถ€ํŠธ๋Š” ์ „๋ถ€ CGLib๋กœ ํ”„๋ก์‹œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๊ณ ์š”?

๋”๋ณด๊ธฐ

์ฐธ๊ณ ๋กœ ์Šคํ”„๋ง 3.2 ์ด์ „์—๋Š” AOP ํƒ€๊นƒ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด JDK๋ฅผ, ์•„๋‹ˆ๋ผ๋ฉด Class ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๊ธฐ๋ณธ๊ฐ’์ด์—ˆ๋‹ค. (๊ถŒ์žฅ์€ ์•ˆํ•˜์ง€๋งŒ ์ง€๊ธˆ๋„ ์„ค์ •์—์„œ ๋ณ€๊ฒฝ๊ฐ€๋Šฅ)

https://gmoon92.github.io/spring/aop/2019/04/20/jdk-dynamic-proxy-and-cglib.html

 

@ ์Šคํ”„๋ง 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 ๋ง๊ณ  ๋‹ค์–‘ํ•œ Advice ํƒœ๊ทธ๋“ค์„ ์ œ๊ณตํ•ด์ค€๋‹ค. ํ•„์š”ํ•˜๋ฉด ์‚ฌ์šฉํ•˜๋„๋กํ•˜์ž.
     

@Around๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋ชจ๋“ ๊ฒŒ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ํ•„์š”์— ๋”ฐ๋ผ ๋ฒ”์œ„๋ฅผ ์ œํ•œํ•ด๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

 

// @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

https://www.inflearn.com/course/the-java-code-manipulation

https://www.baeldung.com/aspectj

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ