/Chapter_03/src/acQuickStart.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="messageBeanImpl" class="sample01.MessageBeanImpl">
<property name="str" value="Have a nice day!!"/>
</bean>
<bean id="loggingAdvice" class="sample01.LoggingAdvice"></bean>
<!-- AOP -->
<aop:config>
<aop:pointcut
expression="execution(public void *.*.*Before(..))"
id="beforeMethod"/>
<aop:pointcut
expression="execution(public * *.*.*After(..))"
id="afterMethod"/><!-- public * *.*.* = public void등 *(패키지).*(클래스).*After(메소드 이름이 뭘로 시작하든 After로 끝나는 메소드) (..)파라미터 상관 없다. -->
<aop:pointcut
expression="execution(public * *.*.*Print*(..))"
id="aroundMethod"/>
<aop:aspect ref="loggingAdvice">
<aop:before method="beforeTrace" pointcut-ref="beforeMethod"/>
<aop:after method="afterTrace" pointcut-ref="afterMethod"/>
<aop:around method="aroundTrace" pointcut-ref="aroundMethod"/>
</aop:aspect>
</aop:config>
</beans>
aop
<!-- AOP -->
<aop:config>
<aop:pointcut
expression="execution(public void *.*.*Before(..))"
id="beforeMethod"/>
<aop:pointcut
expression="execution(public * *.*.*After(..))"
id="afterMethod"/><!-- public * *.*.* = public void등 *(패키지).*(클래스).*After(메소드 이름이 뭘로 시작하든 After로 끝나는 메소드) (..)파라미터 상관 없다. -->
<aop:pointcut
expression="execution(public * *.*.*Print*(..))"
id="aroundMethod"/>
<aop:aspect ref="loggingAdvice">
<aop:before method="beforeTrace" pointcut-ref="beforeMethod"/>
<aop:after method="afterTrace" pointcut-ref="afterMethod"/>
<aop:around method="aroundTrace" pointcut-ref="aroundMethod"/>
</aop:aspect>
</aop:config>
expression
지정해둔 메소드의 조건 (public (void) (패키지).(클래스).(메소드(파라미터)) )에 맞는 메소드가 실행되면
지정해둔 id를 pointcut-ref로 참조하는 aop가 작동한다.
* = 와일드카드
*Before는 이름이 ~before로 끝나는 메소드를 말한다. printBefore(), viewBefore 등..
*Print*는 viewPrintMethod() showPrint2() 등~
aop:before, after, around
pointcut-ref로 참조하던 id의 pointcut이 작동되었을 경우,
before, after는 작동 트리거가 된 메소드의 각각 앞과 뒤,
around는 앞뒤 모두
원하는 메소드가 실행되도록 할 수 있다.
aop가 동작하는 메소드 조건을 이용해
여러 페이지에 똑같이 작동하는 코드들을 한꺼번에 처리할 수 있다.
# /Chapter_03/src/sample01/LoggingAdvice.java
package sample01;
import java.text.DecimalFormat;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
//공통관심사항, 공통모듈, 부가기능, Aspect
public class LoggingAdvice {
public void beforeTrace() {
System.out.println("before trace 작동");
}
public void afterTrace() {
System.out.println("after trace 작동");
}
public void aroundTrace(ProceedingJoinPoint joinPoint) throws Throwable {
// 공통
System.out.println("핵심코드 작동 전");
String methodName = joinPoint.getSignature().toShortString();
System.out.println("메소드 = " + methodName);
StopWatch sw = new StopWatch();
sw.start(methodName);
// 핵심 코드 호출
joinPoint.proceed();
// 공통
System.out.println("핵심코드 작동 후");
sw.stop();
System.out.println("처리시간 : " + new DecimalFormat("#ms").format(sw.getTotalTimeMillis()));
}
}
# 어노테이션 이용하기
/Chapter_03/src/acQuickStart.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="sample01"></context:component-scan>
<aop:aspectj-autoproxy/>
</beans>
component-scan
지정 패키지("sample01")에 @Component가 달린 클래스를 bean으로 생성한다.
<aop:aspectj-autoproxy/>
@Aspect 가 달린 클래스를 찾아 pointcut시 작동시킬 메소드들을 읽어온다.
# /Chapter_03Chapter03_SpringMaven/src/sample01/LoggingAdvice.java
@Aspect // 공통모듈이라고 xml에 알림
@Component
public class LoggingAdvice {
@Before("execution(public void *.*.*Before(..))")
public void beforeTrace() {
System.out.println("before trace...");
}
@After("execution(public * *.*.*After(..))" )
public void afterTrace() {
System.out.println("after trace...33");
}
@Around("execution(public * *.*.*Print*(..))")
public void aroundTrace(ProceedingJoinPoint joinPoint) throws Throwable {
//공통
String methodName = joinPoint.getSignature().toShortString();
System.out.println("메소드 = "+ methodName);
StopWatch sw = new StopWatch();
sw.start(methodName);
// 핵심 관심사항 호출
Object ob = joinPoint.proceed();
System.out.println("# 핵심 리턴 : " + ob);
// 공통
sw.stop();
System.out.println("처리시간 : " + new DecimalFormat("#,###ms").format( sw.getTotalTimeMillis()));
}
}
@Before(..), After(..), Around(..)
execution(메소드 조건)은 xml에 적었던 코드와 같다.
aroundTrace(ProceedingJoinPoint joinPoint)
에서 파라미터로 받는 joinPoint는 execution(메소드 조건)에 걸려 들어오는 메소드이다.
출력시키면,
joinPoint = execution(String sample01.MessageBean.showPrint2())
joinPoint.getSignature() = String sample01.MessageBean.showPrint2()
joinPoint.getSignature().toShortString() = MessageBean.showPrint2()
이렇게 메소드 경로가 나온다.
Stopwatch 클래스
시간 재는 기능
# SpringConfiguration 생성해서 하기
/Chapter_03/src/acQuickStart.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="sample01"></context:component-scan>
<context:component-scan base-package="spring.conf"></context:component-scan>
</beans>
+ spring.conf 패키지를 읽어오게 해서 SpringConfiguration.java의 설정을 적용시킨다.
src/spring/conf/SpringConfiguration.java
package spring.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sample01.LoggingAdvice;
import sample01.MessageBeanImpl;
@Configuration // 해당 클래스를 xml에서 읽어들일때 설정파일로써 인식하게 한다.
@EnableAspectJAutoProxy
public class SpringConfiguration {
// @Bean 어노테이션을 달아야 리턴되는 객체를 bean으로 인식해 getBean메소드로 호출이 가능하다.
// 메소드명(getSungJukDTO)을 객체명으로 인식하므로 @Bean에서 name설정을 하지 않으면 호출할때 context.getBean("getSungJukDTO"); 이렇게 불러야 한다.
@Bean(name = "messageBeanImpl")
public MessageBeanImpl getMessageBeanImpl() {
return new MessageBeanImpl();
}
@Bean(name = "loggingAdvice")
public LoggingAdvice getLoggingAdvice() {
return new LoggingAdvice();
}
}
@EnableAspectJAutoProxy
xml의 <aop:aspectj-autoproxy/>를 어노테이션으로 붙이는 방법이다.
xml에서 이 태그는 제거한다.
# @Component를 @ComponentScan으로 바꿔 직접 spring.conf 패키지 안의 설정파일을 읽어오게 한다.
/Chapter_03Chapter03_SpringMaven/src/sample01/LoggingAdvice.java
package sample01;
import java.text.DecimalFormat;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.util.StopWatch;
//공통관심사항, 공통모듈, 부가기능, Aspect
@Aspect // 공통모듈이라고 xml에 알림
@ComponentScan("spring.conf")
public class LoggingAdvice {
@Before("execution(public void *.*.*Before(..))")
public void beforeTrace() {
System.out.println("before trace...");
}
@After("execution(public * *.*.*After(..))" )
public void afterTrace() {
System.out.println("after trace...33");
}
@Around("execution(public * *.*.*Print*(..))")
public void aroundTrace(ProceedingJoinPoint joinPoint) throws Throwable {
//공통
String methodName = joinPoint.getSignature().toShortString();
System.out.println("메소드 = "+ methodName);
System.out.println("joinPoint = "+ joinPoint);
System.out.println("joinPoint.getSignature() = "+ joinPoint.getSignature());
System.out.println("joinPoint.getSignature().toShortString() = "+ joinPoint.getSignature().toShortString());
StopWatch sw = new StopWatch();
sw.start(methodName);
System.out.println("앞");
// 핵심 관심사항 호출
Object ob = joinPoint.proceed();
System.out.println("# 핵심 리턴 : " + ob);
System.out.println("뒤");
// 공통
sw.stop();
System.out.println("처리시간 : " + new DecimalFormat("#,###ms").format( sw.getTotalTimeMillis()));
}
}
/Chapter03_SpringMaven/src/sample01/MessageBeanImpl.java
package sample01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
//핵심관심사항, Target
//@Component
@ComponentScan("spring.conf")
public class MessageBeanImpl implements MessageBean {
private String str;
// autowire로 자동으로 setter메소드가 호출되도록
@Autowired
public void setStr(@Value("Have a nice day!!") String str) {
this.str = str;
}
@Override
public void showPrintBefore() {
System.out.println("showPrintBefore 메시지 = "+str);
}
@Override
public void viewPrintBefore() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("viewPrintBefore 메시지 = "+str);
}
@Override
public void showPrintAfter() {
System.out.println("showPrintAfter 메시지 = "+str);
}
@Override
public void viewPrintAfter() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("viewPrintAfter 메시지 = "+str);
}
@Override
public void display() {
System.out.println("display 메시지 = "+str);
}
@Override
public String showPrint2() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("showPrint 메시지! = "+str);
return "## 리턴메세지 스프링";
}
@Override
public void viewPrint2() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("viewPrint 메시지!! = "+str);
}
}
# Proxy 클래스 이용 1
/Chapter_03/src/sample02_Java/HelloSpring.java
package sample02_Java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HelloSpring {
public static void main(String[] args) {
MessageBean messageBean = new MessageBeanImpl();
MessageBean proxy = (MessageBean) Proxy.newProxyInstance(
MessageBeanImpl.class.getClassLoader(),
new Class[] {MessageBean.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 공통
System.out.println("입실 체크");
//핵심코드 호출
Object ob = method.invoke(messageBean, args);
// 공통
System.out.println("퇴실 체크");
return ob;
}
});
proxy.study(); // 호출
System.out.println("-----------------");
System.out.println("결과 : " + proxy.game());
}
}
public static Object newProxyInstance(
ClassLoader loader,
Class<?>[] interfaces,
) throws IllegalArgumentException
package sample02_Java;
public interface MessageBean {
public void study();
public String game();
}
///////////////////////////////////////////////////////////////////
package sample02_Java;
public class MessageBeanImpl implements MessageBean {
@Override
public void study() {
System.out.println("수업시간 공부");
}
@Override
public String game() {
System.out.println("수업시간 몰래 게임");
return "바부팅이";
}
}
# Proxy 클래스 이용 2
/Chapter_03/src/applicationContext03.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="messageBeanImpl" class="sample03_Advice.MessageBeanImpl"></bean>
<bean id="loggingBeforeAdvice" class="sample03_Advice.LoggingBeforeAdvice"></bean>
<bean id="loggingAfterAdvice" class="sample03_Advice.LoggingAfterAdvice"></bean>
<bean id="Arounding" class="sample03_Advice.LoggingAroundAdvice"></bean>
<!-- ProxyFactoryBean 클래스로 aop기능을 대신한다.
target은 aop를 적용할 클래스
interceptorNames에는 before, After, Around할 클래스를 불러온다.
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="messageBeanImpl"></property>
<property name="interceptorNames">
<list>
<value>loggingBeforeAdvice</value>
<value>loggingAfterAdvice</value>
<value>Arounding</value>
</list>
</property>
</bean>
</beans>
org.springframework.aop.framework.ProxyFactoryBean 클래스를 bean 생성하며,
클래스 안에 들어있는 target setter에는 aop를 적용할 bean( "messageBeamImpl" ),
interceptorNames의 setter에는 Before, After, Around로 사용할 bean을 불러온다.
/Chapter_03/src/sample03_Advice/LoggingAroundAdvice.java
package sample03_Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LoggingAroundAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//핵심 호출
System.out.println("# 어라운드 입실체크 start");
long start = System.currentTimeMillis();
Object ob = invocation.proceed(); // 핵심코드
System.out.println("# 어라운드 입실체크 end");
long end = System.currentTimeMillis();
// System.out.println("start : " + start);
// System.out.println("end : " + end);
System.out.println("걸린 시간 : " + (long)(end - start));
return ob;
}
}
/Chapter_03/src/sample03_Advice/MessageBeanImpl.java
package sample03_Advice;
public class MessageBeanImpl implements MessageBean {
@Override
public void study() {
System.out.println("수업시간에 공부한다");
}
@Override
public String game() {
System.out.println("수업시간에 몰래 게임한다");
return "바부팅이";
}
}
/Chapter_03/src/sample03_Advice/HelloSpring.java
package sample03_Advice;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext03.xml");
MessageBean messageBean = (MessageBean) context.getBean("proxy");
messageBean.study();
System.out.println("===================");
String str = messageBean.game();
System.out.println("결과 = " + str);
}
}
# Proxy 클래스 이용 3
/Chapter_03/src/sample04_Advisor/HelloSpring.java
/Chapter_03/src/applicationContext04.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="messageBeanImpl" class="sample04_Advisor.MessageBeanImpl"></bean>
<bean id="loggingBeforeAdvice" class="sample04_Advisor.LoggingBeforeAdvice"></bean>
<bean id="loggingAfterAdvice" class="sample04_Advisor.LoggingAfterAdvice"></bean>
<bean id="beforeAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="loggingBeforeAdvice"></property>
<property name="mappedNames">
<list>
<value>study</value>
<value>lesson</value>
</list>
</property>
</bean>
<bean id="afterAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="loggingAfterAdvice"></property>
<property name="mappedNames" value="study, game"></property>
</bean>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="messageBeanImpl"></property>
<property name="interceptorNames">
<list>
<value>beforeAdvisor</value>
<value>afterAdvisor</value>
</list>
</property>
</bean>
</beans>
NameMatchMethodPointcutAdvisor
org.springframework.aop.support.NameMatchMethodPointcutAdvisor 클래스
NameMatchMethodPointcutAdvisor또한 aop 기능을 사용할 수 있는 클래스이다.
advice의 setter로 참조할 클래스를 받아오고
mappedNames의 setter로 적용할 메소드의 리스트를 담는다.
그리고 ProxyFactoryBean 클래스를 bean 생성해
target과 작동시킬 NameMatchMethodPointcutAdvisor의 bean id 리스트를 담는다.
beforeAdvisor bean은 실행시킬 loggingBeforeAdvice bean을 참조하고
실행 조건으로 study와 lesson 메소드를 담아둔다.
study와 lesson 메소드는 proxy bean의 target으로 참조하는 클래스에서 찾는다.
afterAdvisor bean 처럼 mappedNames에 리스트 대신 value를 써서 ,콤마로 여러 메소드를 넣어 똑같이 동작시킬 수 있다.
/Chapter_03/src/sample04_Advisor/MessageBeanImpl.java
package sample04_Advisor;
public class MessageBeanImpl implements MessageBean {
@Override
public void study() {
System.out.println("수업시간에 공부한다");
}
@Override
public String game() {
System.out.println("수업시간에 몰래 게임한다");
return "바부팅이";
}
@Override
public void lesson() {
System.out.println("컴퓨터 수업을 듣는다");
}
}
/Chapter_03/src/sample04_Advisor/HelloSpring.java
package sample04_Advisor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext04.xml");
MessageBean messageBean = (MessageBean) context.getBean("proxy");
messageBean.study();
System.out.println("------------");
System.out.println("결과 = " + messageBean.game());
System.out.println("------------");
messageBean.lesson();
}
}
After, Before
package sample04_Advisor;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class LoggingAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println("퇴실 체크");
}
}
////////////////////////////////////////////////////////////////////////////////////////////
package sample04_Advisor;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class LoggingBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("입실 체크");
}
}
'Dev > Spring' 카테고리의 다른 글
스프링 MVC with @Annotation (0) | 2021.01.14 |
---|---|
스프링 MVC + Maven + Tomcat 프로젝트 생성 (0) | 2021.01.12 |
스프링 MVC 기본구조 정리 (0) | 2021.01.10 |
[ 스프링 연습 ] txt파일로 Export (0) | 2020.12.27 |
STS3 정리 (0) | 2020.12.22 |