[Spring] Spring AOP ๋™์ž‘ ์•Œ์•„๋ณด๊ธฐ

2024. 3. 4. 16:39ยท๐Ÿ“‚ backend/spring
์ด์ „์— ์ž‘์„ฑํ–ˆ๋˜ Spring AOP ๋ธ”๋กœ๊ทธ ๊ธ€ ์˜ฎ๊ธด ๋‚ด์šฉ

 

1. AOP ??

 Spring AOP๋Š” ์Šคํ”„๋ง์—์„œ ์ง€์›ํ•˜๋Š” AOP(Aspect Oriented Programming)์„ ๋งํ•œ๋‹ค. Aspect๋Š” ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์˜๋ฏธํ•œ๋‹ค. ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋ฅผ ๋‹ด๋‹นํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์œ ์ง€๋ณด์ˆ˜์™€ ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด์„œ๋Š” ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด๋‹ค. ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ๋กœ ๋กœ๊น…๊ณผ ํŠธ๋žœ์žญ์…˜์ด๋‹ค. ๋งŒ์•ฝ AOP๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์‚ฌ์ด์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์— ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์‚ฌ์ด์— ์ถ”๊ฐ€๋œ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ฝ”๋“œ๋“ค์„ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ๊ฐ€๋…์„ฑ์„ ๋–จ์–ด๋œจ๋ฆฌ๊ณ  ๊ฐ™์€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ฝ”๋“œ ์ค‘๋ณต์ด ๋ฐœ์ƒํ•ด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค. AOP์„ ํ†ตํ•ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•ด ๋กœ์ง์˜ ์‘์ง‘๋„์™€ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋†’ํž ์ˆ˜ ์žˆ๋‹ค.

 

 

2. Spring AOP ์„ค์ • ๋ฐฉ๋ฒ•

 ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ์Šคํ”„๋ง AOP๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์˜์กด์„ฑ ํ•˜๋‚˜๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด Spring AOP๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ฉด aspectj.weaver์™€ aspectJ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋“ฑ๋กํ•ด asspectj์—์„œ ์ œ๊ณตํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.(e.g. @Pointcut, @AfterThrowing, @Around...)

implementation 'org.springframework.boot:spring-boot-starter-aop'

 

 

 ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ AOP ๊ด€๋ จ ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ  ์‹คํ–‰ํ•  ์„ค์ • ํด๋ž˜์Šค๋“ค์˜ ์ด๋ฆ„์„ ๋‹ด๊ณ  ์žˆ์–ด ๊ด€๋ จ ์„ค์ • ํด๋ž˜์Šค๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค.(at org.springframework.boot.autoconfigure.AutoConfiguration.imports) ์ด ์ค‘ ์Šคํ”„๋ง AOP ์„ค์ •์„ ๋‹ด๋‹นํ•˜๋Š”AopAutoConfiguration ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœ ๋ฐ ์‹คํ–‰์‹œ์ผœ AOP ๊ด€๋ จ ์„ค์ •์„ ์ž๋™์œผ๋กœ ์ง€์›ํ•œ๋‹ค.

//META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}

	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	static class ClassProxyingConfiguration {

		@Bean
		static BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {
			return (beanFactory) -> {
				if (beanFactory instanceof BeanDefinitionRegistry) {
					BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
				}
			};
		}

	}
}

 

 

3. Spring AOP ๊ฐ€ GCLib proxy ๋ฅผ ์„ ํƒํ•œ ์ด์œ 

 ์Šคํ”„๋ง AOP๋Š” ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์Šคํ”„๋ง์—์„œ ์ง€์›ํ•˜๋Š” ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • JDK  Dynamic Proxy : Java Reflection ์—์„œ ์ œ๊ณตํ•˜๋Š” Proxy ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹ (์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋ก์‹œ ์ƒ์„ฑ)
  • CGLlib(Code Generation Library) : ํด๋ž˜์Šค์˜ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ Proxy ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋ก์‹œ ์ƒ์„ฑ)

source : https://www.baeldung.com/spring-aop-vs-aspectj

[1] CGLib proxy ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฐœ์„  ๊ณผ์ •

Spring 4.3(SpringBoot 1.4) ๋ฒ„์ „ ์ด์ „์—๋Š” JDK Dynamic Proxy ๋ฅผ ๊ธฐ๋ณธ ํ”„๋ก์‹œ๋กœ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์ดํ›„์—๋Š” CGLib์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ์ด์ „ ๋ฒ„์ „๊นŒ์ง€๋Š” CGLib ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ๋ณต์žกํ•จ์ด ์กด์žฌํ–ˆ์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

  1. ์™ธ๋ถ€ ์˜์กด์„ฑ(net.sf.cglib.proxy.Enhancer.proxy)๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ spring version 3.2 ๋ถ€ํ„ฐ CGLib์„ Spring Core ํŒจํ‚ค์ง€์— ํฌํ•จ์‹œ์ผœ ๋”์ด์ƒ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.
  2. default constructor ๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ƒ์„ฑ์ž๋ฅผ ๋‘๋ฒˆ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ, spring version 4 ๋ถ€ํ„ฐ Objensis ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋„์›€์„ ๋ฐ›์•„ ์ด ๋ฌธ์ œ ๋˜ํ•œ ๊ฐœ์„ ๋˜์—ˆ๋‹ค.

 

[2] CGLib proxy ์„ ์‚ฌ์šฉํ•œ ์ด์œ  : ์„ฑ๋Šฅ

 CGLib ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ ๊ฐ€์žฅ ์ฃผ๋œ ์ด์œ ๋Š” ์„ฑ๋Šฅ์ด๋‹ค. CGLib์€ ํƒ€๊นƒ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๊ณ  ์ดํ›„์— ํ˜ธ์ถœ์‹œ์— ์กฐ์ž‘๋œ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— relection์„ ์‚ฌ์šฉํ•˜๋Š” JDK Dynamic Proxy์— ๋น„ํ•ด ์„ฑ๋Šฅ์ด ๋น ๋ฅด๋‹ค. (AOP Benchmark) AopAutoConfiguration์„ ํ™•์ธํ•ด๋ณด๋ฉด Default๋กœ Cglib ํ”„๋ก์‹œ ์ƒ์„ฑ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {
    
    	...

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
            matchIfMissing = true)
		static class CglibAutoProxyConfiguration {
		}
	}
	...
}

 

 

4. ProxyFactory

ProxyFactory๋Š” ๋™์  ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ƒ์„ฑํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ProxyFactory ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ ์„ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ  Proxy ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๊ฐ๊ฐ์˜ ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ ์€ ํ•ด๋‹น Advisor ๋ฅผ ํ†ตํ•ด ํ”„๋ก์‹œ ์ƒ์„ฑ์„ ์œ„์ž„ํ•˜๋Š”๋ฐ ๊ฐ ๋™์  ํ”„๋ก์‹œ๋Š” ํ•ด๋‹น ํ•ธ๋“ค๋Ÿฌ์—๊ฒŒ ํ”„๋ก์‹œ ์ƒ์„ฑ ์—ญํ• ์„ ์œ„์ž„ํ•˜์—ฌ ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ ์„ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ  Proxy๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค

  • JDK Dynamic Proxy : (JDKDynamicProxy) adviceInvocationHandler
  • CGLIB : (CglibAopProxy) adviceMethodInterceptor
package org.springframework.aop.framework;

public class ProxyFactory extends ProxyCreatorSupport {
	
    ...
    
	public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
		addInterface(proxyInterface);
		addAdvice(interceptor);
	}
}
@Configuration
public class ProxyFactoryConfig {
    @Bean
    public OrderServiceV1 orderServiceV1(LogTrace logTrace) {
        OrderServiceV1 orderService = new OrderServiceV1Impl(orderRepositoryV1(logTrace));
        ProxyFactory factory = new ProxyFactory(orderService);
        factory.addAdvisor(getAdvisor(logTrace));
        OrderServiceV1 proxy = (OrderServiceV1) factory.getProxy();
        log.info("ProxyFactory proxy={}, target={}", proxy.getClass(), orderService.getClass());
        return proxy;
    }
    
    private Advisor getAdvisor(LogTrace logTrace) {
        //pointcut
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.setMappedNames("request*", "order*", "save*");
        //advice
        LogTraceAdvice advice = new LogTraceAdvice(logTrace);
        return new DefaultPointcutAdvisor(pointcut, advice);
    }    

}

 

5. BeanPostProcessor

BeanPostProcessor๋Š”  ๋นˆ์„ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์—์„œ ProxyFactory์—์„œ ์ƒ์„ฑํ•œ ํ”„๋ก์‹œ๋กœ ๋“ฑ๋กํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค. ์ž๋™์œผ๋กœ ๋นˆ์„ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ๋Œ€์ฒดํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋ก์‹œ๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
    
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

 

 

6. Weaving

source : [์ธํ”„๋Ÿฐ]์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ๊ณ ๊ธ‰ํŽธ (๊น€์˜ํ•œ๋‹˜ ๊ฐ•์˜)

์œ„๋น™(weaving)์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์œ„๋น™ ๋ฐฉ๋ฒ•์—๋Š” ์ปดํŒŒ์ผ ์‹œ์ , ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ , ๋Ÿฐํƒ€์ž„ ์‹œ์ (ํ”„๋ก์‹œ)์ด ์žˆ๋‹ค. ํ˜„์žฌ ์Šคํ”„๋ง AOP๋Š” ๋Ÿฐํƒ€์ž„ ์œ„๋น™์„ ์„ ํƒํ•˜๊ณ  ์žˆ๋‹ค. ๋Ÿฐํƒ€์ž„ ์œ„๋น™์„ ์„ ํƒํ•œ ์ด์œ ๋Š”  ์„ค์ •์ด ํŽธ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ปดํŒŒ์ผ ์‹œ์ ๊ณผ ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์  ์œ„๋น™์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” AspectJ ์ปดํŒŒ์ผ๋Ÿฌ, AspectJ ํด๋ž˜์Šค ๋กœ๋” ์กฐ์ž‘๊ธฐ(๋ฐ”์ดํŠธ ์ฝ”๋“œ ์กฐ์ž‘)์ด ํ•„์š”ํ•˜๋‹ค. 

'๐Ÿ“‚ backend > spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

hibernate.query.in_clause_parameter_padding = true ?  (1) 2024.03.06
JPA ์— UUID version 7 ์ ์šฉํ•˜๊ธฐ  (0) 2024.03.04
[JPA] ์ฝ”๋“œ๋กœ ๋ณด๋Š” OSIV ์™€ ๊ณ ์ฐฐ  (2) 2024.01.30
QueryDSL transform() ์—์„œ ๊ผญ @Transactional ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ   (0) 2024.01.29
ํ…Œ์ŠคํŠธ์—์„œ @Sql ๋กœ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€์ง€ ์•Š์•˜๋˜ ์ด์œ  (with. custom TestExecutionListener)  (1) 2024.01.24
'๐Ÿ“‚ backend/spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • hibernate.query.in_clause_parameter_padding = true ?
  • JPA ์— UUID version 7 ์ ์šฉํ•˜๊ธฐ
  • [JPA] ์ฝ”๋“œ๋กœ ๋ณด๋Š” OSIV ์™€ ๊ณ ์ฐฐ
  • QueryDSL transform() ์—์„œ ๊ผญ @Transactional ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 
cooper25
cooper25
  • cooper25
    dev cooper
    cooper25
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (84)
      • ๐Ÿ“‚ backend (34)
        • spring (19)
        • architecture (10)
        • test (5)
      • ๐Ÿ“‚ computer-science (5)
      • ๐Ÿ“‚ programming-language (12)
        • java (12)
      • ๐Ÿ“‚ infra (9)
        • mysql (4)
        • redis (2)
        • message-queue (3)
      • ๐Ÿ“‚ cloud (2)
        • aws (2)
      • ๐Ÿ“‚ frontend (1)
        • react (0)
      • ๐Ÿ“‚ education & lecture (16)
        • ์ธํ”„๋ผ ๊ณต๋ฐฉ (11)
        • ํ•ญํ”Œ ๋ฐฑ์—”๋“œ 7๊ธฐ (5)
      • ๐Ÿ“‚ ai (1)
        • claude (1)
      • ๐Ÿ“‚ etc (2)
        • ํšŒ๊ณ  (1)
        • ์ปจํผ๋Ÿฐ์Šค (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    ๋™์‹œ์„ฑ
    spring
    ํ•ญํ•ดํ”Œ๋Ÿฌ์Šค
    spring-batch
    kafka
    react
    nGrinder
    ์Šคํ”„๋ง์บ ํ”„ ํ›„๊ธฐ
    spring AOP
    spring camp 2025
    ์ธํ”„๋ผ๊ณต๋ฐฉ
    Redisson
    UUID
    ํšŒ๊ณ 
    gof
    ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„
    mysql
    AWS
    ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์„ค๊ณ„
    JPA
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
cooper25
[Spring] Spring AOP ๋™์ž‘ ์•Œ์•„๋ณด๊ธฐ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”