핵심관심모듈이 선언된 클래스 생성
public class JoinPointBean {
public void add() {
System.out.println("*** JoinPointBean 클래스의 add() 메소드 호출 ***");
}
public void modify(int num, String name) {
System.out.println("*** JoinPointBean 클래스의 modify(int num, String name) 메소드 호출 ***");
}
public void remove(int num) {
System.out.println("*** JoinPointBean 클래스의 remove(int num) 메소드 호출 ***");
}
public String getName() {
System.out.println("*** JoinPointBean 클래스의 getName() 메소드 호출 ***");
return "홍길동";
}
public void calc(int num1, int num2) {
System.out.println("*** JoinPointBean 클래스의 calc(int num1, int num2) 메소드 호출 ***");
System.out.println("몫 = "+(num1/num2));
}
}
실행파일 작성
public class JoinPointApp {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("07-2_param.xml");
System.out.println("===============================================================");
JoinPointBean bean=context.getBean("joinPointBean", JoinPointBean.class);
bean.add();
System.out.println("===============================================================");
bean.modify(1000, "임꺽정");
System.out.println("===============================================================");
bean.remove(2000);
System.out.println("===============================================================");
bean.getName();
System.out.println("===============================================================");
bean.calc(20, 10);
//bean.calc(20, 0);//ArithmeticException 발생
System.out.println("===============================================================");
((ClassPathXmlApplicationContext)context).close();
}
}
횡단관심모듈이 선언된 클래스 생성
- Around Advice 메소드를 제외한 나머지 Advice 메소드는 반환형을 void로 작성하며
- 매개변수를 작성하지 않거나 JoinPoint 인터페이스를 자료형으로 하는 매개변수 선언 가능
- 횡단관심모듈의 매개변수를 비정상적으로 선언한 경우 IllegalArgumentException 발생
- JoinPoint : 타겟메소드(핵심관심모듈)의 정보를 저장하기 위한 객체
- => Spring Container가 Advice 메소드를 호출할 때 타겟메소드의 정보(JoinPoint 객체)를 매개변수에 자동 저장
- Advice 메소드(횡단관심모듈)에서 타겟메소드의 정보가 필요한 경우 JoinPoint 매개변수 작성
- 횡단관심 반환형이나 매개변수를 비정상적으로 선언한 경우 IllegalArgument 발생
- JoinPoint.getTarget() : 타겟메소드를 호출하는 Spring Bean 객체를 반환하는 메소드
- => 타겟메소드가 선언된 클래스의 객체를 Object 타입으로 반환
- Object.getClass() : 객체에 대한 클래스 정보(Clazz)를 반환하는 메소드
- Class.getName() : Class 객체(Clazz)의 클래스명(패키지 포함)을 반환하는 메소드
System.out.println(joinPoint.getTarget().getClass().getName());
- Class.getSimpleName() : Class 객체(Clazz)의 클래스명(패키지 미포함)을 반환하는 메소드
[System.out.println](notion://system.out.println/)(joinPoint.getTarget().getClass().getSimpleName());
- JoinPoint.getSignature() : Signature 객체(타겟메소드 정보)를 반환하는 메소
- Signature.getName() : 타겟메소드의 이름을 반환하는 메소드
[System.out.println](notion://system.out.println/)(joinPoint.getSignature().getName());
- JoinPoint.getArgs() : 타겟메소드의 매개변수에 저장된 모든 값(객체)을 Object 배열로 반환하는 메소드
Object[] objects=joinPoint.getArgs();
- After Returning Advice 메소드에는 JoinPoint 매개변수외에 Object 매개변수 작성 가능
- Object 매개변수에는 타겟메소드의 반환값을 전달받아 저장
- 타겟메소드 반환값의 자료형이 고정되어 있는 경우 Object 타입 대신 반환값의 자료형으로 매개변수 작성
- Bean Configuration File의 AOP 설정에서 after-returning 엘리먼트의 returning 속성에 매개변수명을속성값으로 반드시 설정해야만 타겟메소드의 반환값을 매개변수로 전달받아 저장 가능
public void displayName(Object object) {//After Returning Advice
if(object instanceof String) {//매개변수가 String 클래스로 형변환될 수 있는 경우
String name=(String)object;
System.out.println("[after-returning]"+name+"님, 환영합니다.");
}
}
- After Throwing Advice 메소드에는 JoinPoint 매개변수외에 Exception 매개변수 작성 가능
- Exception 매개변수에는 타겟메소드에서 발생된 예외(Exception 객체)를 전달받아 저장
- Bean Configuration File의 AOP 설정에서 after-throwing 엘리먼트의 throwing 속성에 매개변수명
- 속성값으로 반드시 설정해야만 타겟메소드의 예외를 매개변수로 전달받아 저장 가능
public void displayException(Exception exception) {//After Throwing Advice
System.out.println("[after-throwing]타겟메소드에서 발생된 예외 메세지 = "+exception.getMessage());
}
- Around Advice 메소드는 반환형을 void 또는 Object 타입으로 작성하고 ProceedingJoinPoint 인터페이스를 자료형으로 작성된 매개변수를 반드시 선언
- Around Advice 메소드는 타겟메소드의 반환값을 제공받아 반환하기 위해 Object 타입으로 선언
- ProceedingJoinPoint : 타겟메소드(핵심관심모듈)의 정보를 저장하기 위한 객체
- JoinPoint 객체와 다른점은 타겟메소드를 호출할 수 있는 기능 제공
- ProceedingJoinPoint.proceed() : 타겟메소드를 호출하는 메소드 - 핵심관심모듈 동작
- 타겟메소드 호출시 반환되는 결과값을 제공받아 저장 가능
- 프로그램 실행시 발생되는 모든 오류 정보를 저장한 객체(Throwable) 발생 가능 - 예외 처리
public Object display(ProceedingJoinPoint joinPoint) throws Throwable {//Around Advice
System.out.println("[around]핵심관심모듈 동작 전에 삽입되어 실행될 횡단관심모듈");
Object object=joinPoint.proceed();
System.out.println("[around]핵심관심모듈 동작 후에 삽입되어 실행될 횡단관심모듈");
return object;
}
핵심관심모듈이 선언된 클래스를 Spring Bean으로 등록
<?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"
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.xsd">
<bean class="xyz.itwill07.aop.JoinPointBean" id="joinPointBean"/>
<bean class="xyz.itwill07.aop.JoinPointAdvice" id="joinPointAdvice"/>
<aop:config>
<aop:aspect ref="joinPointAdvice">
<aop:before method="displayTarget" pointcut="execution(* *(..))"/>
</aop:aspect>
</aop:config>
</beans>
시간초 예제
public class ExecutionTimeAdvice {
private static final Logger logger=LoggerFactory.getLogger(ExecutionTimeAdvice.class);
public Object timeWatchLog(ProceedingJoinPoint joinPoint) throws Throwable {
long beginTime=System.currentTimeMillis();
Object object=joinPoint.proceed();
long endTime=System.currentTimeMillis();
String className=joinPoint.getTarget().getClass().getSimpleName();
String methodName=joinPoint.getSignature().getName();
logger.info(className+" 클래스의 "+methodName+" 메소드 실행 시간 = "
+(endTime-beginTime)+"ms");
return object;
}
}
메일 예제
- Spring Context 확장 기능을 제공하는 라이브러리
org.springframework
spring-context-support
${org.springframework-version}
- Java Mail 기능을 제공하는 라이브러리
com.sun.mail
javax.mail
1.6.2
메일 전송 기능을 제공하는 클래스
- 라이브러리 다운!
- 메일을 전송하는 JavaMailSender 객체를 저장하는 필드, getter,setter
private JavaMailSender mailSender;
public JavaMailSender getMailSender() {
return mailSender;
}
public void setMailSender(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
- 메일을 전송하는 메소드 - 핵심관심모듈
- 받는 사람 이메일 주소, 제목, 내용을 매개변수로 전달받아 저장
- 받는 사람 이메일 주소 반환 - 메세지 출력
- MimeMessage.setSubject(String subject) : MimeMessage 객체의 메일 제목을 변경하는 메소드-
- MimeMessage.setText(String content) : MimeMessage 객체의 메일 내용(텍스트)을 변경하는 메소드
- MimeMessage.setRecipients(RecipientType type, InternetAddress email) : MimeMessage 객체의 메일을 수신하는 사용자에 대한 정보를 변경하는 메소드
- RecipientType : 메일 수신 사용자 대상을 표현하기 위한 상수
- InternetAddress : 수신 사용자의 이메일 주소를 저장한 객체 - InternetAddress 대신 String 사용 가능
- InternetAddress.parse(String mail) : 문자열을 전달받아 InternetAddress 객체로 변환하여 반환하는 메소드
- JavaMailSender.send(MimeMessage message) : SMTP 서비스를 사용하여 메일을 전송하는 메소드
public String sendEmail(String email, String subject, String content) {
MimeMessage message=mailSender.createMimeMessage();
try {
message.setSubject(subject);
message.setText(content);
message.setRecipients(MimeMessage.RecipientType.TO, InternetAddress.parse(email));
mailSender.send(message);
} catch (MessagingException e) {
e.printStackTrace();
}
return email;
}
}
- 메일 전송기능을 제공하는 JavaMailSenderImpl 클래스를 Spring Bean으로 등록
- SMTP 서비스를 제공하는 메일 서버의 정보(값)를 JavaMailSenderImpl 객체의 필드에 전달하여 저장(Value Injection)
<bean class="org.springframework.mail.javamail.JavaMailSenderImpl" id="javaMailSender">
<property name="host" value="smtp.gmail.com"/>
<property name="port" value="587"/>
<property name="username" value="abc123"/>
<property name="password" value="123456"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.ssl.trust">smtp.gmail.com</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
- 핵심관심모듈이 선언된 클래스를 Spring Bean으로 등록
- mailSender 필드에 JavaMailSenderImpl 클래스의 Spring Bean으로 의존관계 설정 - DI(Dependency Injection)
<bean class="xyz.itwill07.aop.EmailSendBean" id="emailSendBean">
<property name="mailSender" ref="javaMailSender"/>
</bean>
<bean class="xyz.itwill07.aop.EmailSendAdvice" id="emailSendAdvice"/>
<aop:config>
<aop:pointcut expression="execution(* sendEmail(..))" id="emailSendPointcut"/>
<aop:aspect ref="emailSendAdvice">
<aop:before method="beforeMessage" pointcut-ref="emailSendPointcut"/>
</aop:aspect>
</aop:config>
</beans>
실행파일
package xyz.itwill07.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class EmailSendApp {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("07-4_email.xml");
System.out.println("===============================================================");
EmailSendBean bean =context.getBean("emailSendBean", EmailSendBean.class);
bean.sendEmail("jmaster1020@gmail.com", "눈누랄랄ㅎㅎ"
, "JavaMail 기능을 이용한 이메일 전송 테스트입니다.");
System.out.println("===============================================================");
((ClassPathXmlApplicationContext)context).close();
}
}
메일 전송 관련 메세지 기능을 제공하는 클래스 - Advice
- 메일 전송 전 실행될 명령을 작성한 메소드 - Before Advice
- 타겟메소드(EmailSendBean 클래스의 sendEmail 메소드)의 매개변수에 저장된 값을 메세지 출력 기능으로 제공받아 사용하기 위해 JoinPoint 매개변수선언
public void beforeMessage(JoinPoint joinPoint) {
String email=(String)joinPoint.getArgs()[0];
String subject=(String)joinPoint.getArgs()[1];
System.out.println("[메세지]<"+email+">님에게 <"+subject+"> 제목의 이메일을 전송합니다.");
}
- 메일 전송이 성공한 경우 실행될 명령을 작성한 메소드 - After Returning Advice
- 타겟메소드(EmailSendBean 클래스의 sendEmail 메소드)의 반환값을 제공받아 메세지 출력 기능으로 사용하기 위해 매개변수 선언
public void successMessage(String email) {
System.out.println("[메세지]<"+email+">님에게 이메일을 성공적으로 전송 하였습니다.");
}
- 메일 전송이 실패한 경우 실행될 명령을 작성한 메소드 - After Throwing Advice
- 타겟메소드(EmailSendBean 클래스의 sendEmail 메소드)에서 발생된 예외정보를 제공받아 메세지 출력 기능으로 사용하기 위해 매개변수 선언
public void failMessage(Exception exception) {
System.out.println("[에러]메일 전송 실패 = "+exception.getMessage());
}
<bean class="org.springframework.mail.javamail.JavaMailSenderImpl" id="javaMailSender">
<property name="host" value="smtp.gmail.com"/>
<property name="port" value="587"/>
<property name="username" value="abc123"/>
<property name="password" value="123456"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.ssl.trust">smtp.gmail.com</prop>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
<bean class="xyz.itwill07.aop.EmailSendBean" id="emailSendBean">
<property name="mailSender" ref="javaMailSender"/>
</bean>
<bean class="xyz.itwill07.aop.EmailSendAdvice" id="emailSendAdvice"/>
<aop:config>
<aop:pointcut expression="execution(* sendEmail(..))" id="emailSendPointcut"/>
<aop:aspect ref="emailSendAdvice">
<aop:before method="beforeMessage" pointcut-ref="emailSendPointcut"/>
<aop:after-returning method="successMessage" pointcut-ref="emailSendPointcut" returning="email"/>
<aop:after-throwing method="failMessage" pointcut-ref="emailSendPointcut" throwing="exception"/>
</aop:aspect>
</aop:config>
</beans>
'일상 > 일기장' 카테고리의 다른 글
TIL22.03.15 - Spring : Spring MVC -annotation (0) | 2022.03.15 |
---|---|
TIL22.03.14 - Spring : Spring DAO, Spring MVC (0) | 2022.03.14 |
TIL.22.03.03 - Spring : 환경설정, Log (0) | 2022.03.04 |
TIL22.03.02 - MyBatis : 동적 SQL (0) | 2022.03.03 |
TIL22.03.01 - MyBatis : ResultMap (0) | 2022.02.28 |
댓글