스프링
Spring AOP
코딩 화이팅
2023. 4. 12. 15:04
AOP(Aspect Oriented Programming)
- OOP에서 모듈화의 핵심 단위는 클래스인 반면, AOP에서 모듈화의 단위는 Aspect.
- Aspect는 여러 타입과 객체에 거쳐서 사용되는 기능(Cross Cutting, 트랜잭션 관리 등)의 모듈
- Spring framework의 필수요소는 아니지만, AOP프레임워크는 Spring IoC를 보완한다.
AOP용어
- Aspect : 여러 클래스에 공통적으로 구현되는 관심사(Concern)의 모듈화
- Join Point : 메서드 실행이나 예외처리와 같은 프로그램 실행중의 특정 지점. Spring에서는 메서드 실행을 의미한다.
- Pointcut : Join Point에 Aspect를 적용하기 위한 조건 서술. Aspect는 지정한 pointcut에 일치하는 모든 join point에서 실행된다.
- Advice : 특정 조인포인트에서 Aspect에 의해서 취해진 행동. Around, Before, After등의 Advice 타입이 존재
- Target 객체 : 하나 이상의 advice가 적용될 객체. Spring AOP는 Runtime Proxy를 사용하여 구현되므로 객체는 항상 Proxy(대행자) 객체가 된다.
- AOP Proxy : AOP를 구현하기 위해 AOP 프레임워크에 의해 생성된 객체
- Weaving : Aspect를 다른 객체와 연결하여 Advice 객체를 생성. 런타인 또는 로딩 시 수행할 수 있지만 Spring AOP는 런타임에 위빙을 수행
package com.ssafy.proxy;
public class OuchException extends Exception{
}
===========================================================
package com.ssafy.proxy;
import java.util.Random;
public class Programmer {
// 필드는 필요없고
// 프로그래머의 일상
public void coding() {
System.out.println("컴퓨터를 부팅한다."); //이전에 해야될것
try {
System.out.println("열심히 코드를 작성한다."); //핵심관심사항
if (new Random().nextBoolean())
throw new OuchException();
System.out.println("Git에 Push 한다."); //아무이상 없이 잘 마쳤을때
} catch (OuchException e) {
System.out.println("반차를 낸다."); //문제가 발생했을 때
}finally {
System.out.println("보람찬 하루를 마무리한다."); //모든게 끝이났을 때
}
}
}
===========================================================
package com.ssafy.proxy;
import java.util.Random;
public class Ssafy {
// 필드는 필요없고
// SSAFY인의 일상
public void coding() {
System.out.println("컴퓨터를 부팅한다."); //이전에 해야될것
try {
System.out.println("열심히 공부를 한다."); //핵심관심사항
if (new Random().nextBoolean())
throw new OuchException();
System.out.println("Git에 Push 한다."); //아무이상 없이 잘 마쳤을때
} catch (OuchException e) {
System.out.println("반차를 낸다."); //문제가 발생했을 때
}finally {
System.out.println("보람찬 하루를 마무리한다."); //모든게 끝이났을 때
}
}
}
===========================================================
package com.ssafy.proxy;
public class Test {
public static void main(String[] args) {
Programmer p = new Programmer();
p.coding();
}
}
//
컴퓨터를 부팅한다.
열심히 코드를 작성한다.
Git에 Push 한다.
보람찬 하루를 마무리한다.
컴퓨터를 부팅한다.
열심히 코드를 작성한다.
반차를 낸다.
보람찬 하루를 마무리한다.
랜덤으로 두 출력이 나온다.
이렇게 코드를 작성할 수는 있지만 이렇게 되면 Ssafy와 Programmer의 중복적인 코딩을 하게 된다.
따로 관심사를 빼서 호출하게 만들기 위해 프록시 패턴을 적용할 수 있다.
나머진 위의 코드와 동일
package com.ssafy.proxy2;
public class Programmer implements Person {
// 필드는 필요없고
// 프로그래머의 일상
@Override
public void coding() {
System.out.println("열심히 코드를 작성한다."); // 핵심관심사항
}
}
==============================================================
package com.ssafy.proxy2;
public class Ssafy implements Person {
// 필드는 필요없고
// SSAFY인의 일상
public void coding() {
System.out.println("열심히 공부를 한다."); // 핵심관심사항
}
}
==============================================================
package com.ssafy.proxy2;
public interface Person {
public void coding();
}
==============================================================
package com.ssafy.proxy2;
import java.util.Random;
import com.ssafy.proxy.OuchException;
public class PersonProxy implements Person {
private Person person;
//생성자 주입
//설정자 주입
public void setPerson(Person person) {
this.person = person;
}
@Override
public void coding() {
System.out.println("컴퓨터를 부팅한다."); //이전에 해야될것
try {
person.coding(); //핵심관심사항
if (new Random().nextBoolean())
throw new OuchException();
System.out.println("Git에 Push 한다."); //아무이상 없이 잘 마쳤을때
} catch (OuchException e) {
System.out.println("반차를 낸다."); //문제가 발생했을 때
}finally {
System.out.println("보람찬 하루를 마무리한다."); //모든게 끝이났을 때
}
}
}
==============================================================
package com.ssafy.proxy2;
public class Test {
public static void main(String[] args) {
Programmer p = new Programmer();
Ssafy s = new Ssafy();
PersonProxy px = new PersonProxy();
px.setPerson(s);
px.coding();
}
}
//
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git에 Push 한다.
보람찬 하루를 마무리한다.
만약
px.setPerson(p);라면
컴퓨터를 부팅한다.
열심히 코드를 작성한다.
Git에 Push 한다.
보람찬 하루를 마무리한다.
Spring AOP Proxy
- 실제 기능이 구현된 Target 객체를 호출하면, target이 호출되는 것이 아니라 advice가 적용된 Proxy 객체가 호출됨.
- Spring AOP는 기본값으로 표준 JDK dynamic proxy를 사용
Spring AOP
- @AspectJ : 일반 Java 클래스를 Aspect로 선언하는 스타일, AspectJ 프로젝트에 의해 소개되었음
- Spring AOP에서는 pointcut 구문 분석, 매핑을 위해서 AspectJ 라이브러리를 사용함
- 하지만 AOP runtime은 순수 Spring AOP이며, AspectJ에 대한 종속성은 없음
Spring AOP시작하기-xml
mvnrepository 사이트에 들어가 aspectj를 검색하여 Aspectj Weaver에 가장 다운로드가 많은 것을 복붙하고
Aspectj Runtime에 Weaver와 같은 버전의 것을 복붙해준다.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Spring_02_AOP_XML</groupId>
<artifactId>Spring_02_AOP_XML</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 이곳에다가 <properties></properties>를 추가하고 -->
<!-- <spring-version>로 spring의 버전과 -->
<!-- <aspectj-version>로 aspectj의 버전을 통합하여 관리가능하다. -->
<!-- 만약 이 properties안에서 버전을 바꾸면 밑에 버전들도 한꺼번에 바뀌기 때문에 -->
<!-- 더 편한 관리가 가능하다. -->
<!-- 각각의 버전을 넣어주면 밑에 <version>에는 -->
<!-- ${spring-version}와 ${aspectj-version}처럼 -->
<!-- 버전의 값을 변경해준다. -->
<properties>
<spring-version>5.3.18</spring-version>
<aspectj-version>1.9.8</aspectj-version>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj-version}</version>
</dependency>
</dependencies>
</project>
Aspect 선언하기-xml 방식
- Aspect는 핵심 관심사항(Core concern)
- @Aspect annotation 또는 xml bean 등록하기
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
public void afterReturning() {
System.out.println("Git Push 한다.");
}
//김보경 서7 / 허유정 서5
public void afterThrowing() {
System.out.println("반차를 낸다.");
}
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
}
Pointcut 선언
- 포인트 컷은 어떤 조인 포인트를 사용할지 결정한다. Spring AOP는 메서드 실행만 지원한다.
- 포인터 컷 선언은 두 내용을 포함한다.
- 조인포인트에 대한 표현식
- 포인트 컷의 이름
<?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-4.3.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<bean class="com.ssafy.aop.Programmer" id="programmer"/>
<bean class="com.ssafy.aop.Ssafy" id="ssafy"/>
<bean class="com.ssafy.aop.MyAspect" id="myAspect"/>
<aop:config>
<aop:pointcut expression="execution(public * com.ssafy.aop.*.coding())" id="mypt"/>
<aop:aspect ref="myAspect">
<!-- <aop:before method="before" pointcut-ref="mypt"/>
<aop:after-returning method="afterReturning" pointcut-ref="mypt" returning="num"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="mypt" throwing="th"/>
<aop:after method="after" pointcut-ref="mypt"/> -->
<aop:around method="around" pointcut-ref="mypt"/>
</aop:aspect>
</aop:config>
</beans>
AOP를 적용한 코드
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
public void afterReturning() {
System.out.println("Git Push 한다.");
}
//김보경 서7 / 허유정 서5
public void afterThrowing() {
System.out.println("반차를 낸다.");
}
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
}
=============================================================
package com.ssafy.aop;
public interface Person {
public void coding();
}
=============================================================
package com.ssafy.aop;
import java.util.Random;
public class Programmer implements Person {
// 필드는 필요없고
// 프로그래머의 일상
@Override
public void coding() {
System.out.println("열심히 코드를 작성한다."); // 핵심관심사항
}
}
=============================================================
package com.ssafy.aop;
import java.util.Random;
public class Ssafy implements Person {
// 필드는 필요없고
// SSAFY인의 일상
public void coding() {
System.out.println("열심히 공부를 한다."); // 핵심관심사항
}
}
=============================================================
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Spring_02_AOP_XML</groupId>
<artifactId>Spring_02_AOP_XML</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 이곳에다가 <properties></properties>를 추가하고 -->
<!-- <spring-version>로 spring의 버전과 -->
<!-- <aspectj-version>로 aspectj의 버전을 통합하여 관리가능하다. -->
<!-- 만약 이 properties안에서 버전을 바꾸면 밑에 버전들도 한꺼번에 바뀌기 때문에 -->
<!-- 더 편한 관리가 가능하다. -->
<!-- 각각의 버전을 넣어주면 밑에 <version>에는 -->
<!-- ${spring-version}와 ${aspectj-version}처럼 -->
<!-- 버전의 값을 변경해준다. -->
<properties>
<spring-version>5.3.18</spring-version>
<aspectj-version>1.9.8</aspectj-version>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj-version}</version>
</dependency>
</dependencies>
</project>
=============================================================
<?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-4.3.xsd">
<!-- <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> -->
<bean class="com.ssafy.aop.Programmer" id="programmer"/>
<bean class="com.ssafy.aop.Ssafy" id="ssafy"/>
<bean class="com.ssafy.aop.MyAspect" id="myAspect"/>
<aop:config>
<aop:pointcut expression="execution(public * com.ssafy.aop.*.coding())" id="mypt"/>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="mypt"/>
<aop:after-returning method="afterReturning" pointcut-ref="mypt"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="mypt"/>
<aop:after method="after" pointcut-ref="mypt"/>
<!-- <aop:around method="around" pointcut-ref="mypt"/> -->
</aop:aspect>
</aop:config>
</beans>
=============================================================
package com.ssafy.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) throws OuchException {
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
Person p = context.getBean("ssafy", Person.class);
p.coding();
}
}
//
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git Push 한다.
보람찬 하루를 마무리 한다.
만약 테스트 클래스에서 출력할 때 클래스를 Person말고 Ssafy로 바꾸고 싶다면?
나머지 코드는 위와 동일
package com.ssafy.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) throws OuchException {
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
Person p = context.getBean("ssafy", Ssafy.class);
p.coding();
}
}
=============================================================
이렇게 바꾸고 출력하면 에러가 뜬다. 이러한 에러를 막기 위해서는
applicationContext에서 코드를 추가해줘야된다.
<?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-4.3.xsd">
이 코드를 추가
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<bean class="com.ssafy.aop.Programmer" id="programmer"/>
<bean class="com.ssafy.aop.Ssafy" id="ssafy"/>
<bean class="com.ssafy.aop.MyAspect" id="myAspect"/>
<aop:config>
<aop:pointcut expression="execution(public * com.ssafy.aop.*.coding())" id="mypt"/>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="mypt"/>
<aop:after-returning method="afterReturning" pointcut-ref="mypt"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="mypt"/>
<aop:after method="after" pointcut-ref="mypt"/>
<!-- <aop:around method="around" pointcut-ref="mypt"/> -->
</aop:aspect>
</aop:config>
</beans>
//
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git Push 한다.
보람찬 하루를 마무리 한다.
인터페이스를 구현한 클래스가 아닌 경우 CGLIB 프록시를 사용
이 한 줄은 계속해서 넣어주는 것이 좋다.
AOP를 적용하여 기능을 추가한 코드
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
public void afterReturning(int num) {
System.out.println("Git Push 한다. : " + num+"개의 코드를");
}
//김보경 서7 / 허유정 서5
public void afterThrowing(Throwable th) {
System.out.println("반차를 낸다.");
if(th instanceof OuchException) {
((OuchException)th).handleException();
}
}
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
}
=============================================================
package com.ssafy.aop;
public class OuchException extends Exception{
public void handleException() {
System.out.println("병원 가자");
}
}
=============================================================
package com.ssafy.aop;
public interface Person {
public int coding() throws OuchException;
}
=============================================================
package com.ssafy.aop;
import java.util.Random;
public class Programmer implements Person {
// 필드는 필요없고
// 프로그래머의 일상(우리가 작성한 코드 수를 반환하는 메서드)
@Override
public int coding() throws OuchException {
System.out.println("열심히 코드를 작성한다."); // 핵심관심사항
if(new Random().nextBoolean())
throw new OuchException();
return (int)(Math.random()*100)+1;
}
}
=============================================================
package com.ssafy.aop;
import java.util.Random;
public class Ssafy implements Person {
// 필드는 필요없고
// SSAFY인의 일상
public int coding() throws OuchException {
System.out.println("열심히 공부를 한다."); // 핵심관심사항
if(new Random().nextBoolean())
throw new OuchException();
return (int)(Math.random()*100)+1;
}
}
=============================================================
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Spring_02_AOP_XML</groupId>
<artifactId>Spring_02_AOP_XML</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 이곳에다가 <properties></properties>를 추가하고 -->
<!-- <spring-version>로 spring의 버전과 -->
<!-- <aspectj-version>로 aspectj의 버전을 통합하여 관리가능하다. -->
<!-- 만약 이 properties안에서 버전을 바꾸면 밑에 버전들도 한꺼번에 바뀌기 때문에 -->
<!-- 더 편한 관리가 가능하다. -->
<!-- 각각의 버전을 넣어주면 밑에 <version>에는 -->
<!-- ${spring-version}와 ${aspectj-version}처럼 -->
<!-- 버전의 값을 변경해준다. -->
<properties>
<spring-version>5.3.18</spring-version>
<aspectj-version>1.9.8</aspectj-version>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj-version}</version>
</dependency>
</dependencies>
</project>
=============================================================
<?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-4.3.xsd">
<!-- 이 코드를 추가 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<bean class="com.ssafy.aop.Programmer" id="programmer"/>
<bean class="com.ssafy.aop.Ssafy" id="ssafy"/>
<bean class="com.ssafy.aop.MyAspect" id="myAspect"/>
<aop:config>
<aop:pointcut expression="execution(public * com.ssafy.aop.*.coding())" id="mypt"/>
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="mypt"/>
밑에 두줄에 returning과 throwing 추가
<aop:after-returning method="afterReturning" pointcut-ref="mypt" returning="num"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="mypt" throwing="th"/>
<aop:after method="after" pointcut-ref="mypt"/>
<!-- <aop:around method="around" pointcut-ref="mypt"/> -->
</aop:aspect>
</aop:config>
</beans>
=============================================================
package com.ssafy.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) throws OuchException {
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
Person p = context.getBean("ssafy", Person.class);
try {
p.coding();
} catch (OuchException e) {
}
}
}
//
출력은 랜덤하게
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git Push 한다.81개의 코드를
보람찬 하루를 마무리 한다.
컴퓨터를 부팅한다.
열심히 공부를 한다.
반차를 낸다.
병원 가자
보람찬 하루를 마무리 한다.
around 메서드에 한번에 넣어서 하는 방법
나머지 코드는 위와 동일
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
public void afterReturning(int num) {
System.out.println("Git Push 한다. : " + num +"개의 코드를");
}
//김보경 서7 / 허유정 서5
public void afterThrowing(Throwable th) {
System.out.println("반차를 낸다.");
if(th instanceof OuchException) {
((OuchException)th).handleException();
}
}
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
//////////////////////////////////////////////////////////
//aroud
public int around(ProceedingJoinPoint pjt) {
int num = 0;
this.before();
try {
num = (int) pjt.proceed();//핵심관심사항
this.afterReturning(num);
} catch (Throwable e) {
this.afterThrowing(e);
}finally {
this.after();
}
return num;
}
}
=============================================================
<?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-4.3.xsd">
<!-- 이 코드를 추가 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<bean class="com.ssafy.aop.Programmer" id="programmer"/>
<bean class="com.ssafy.aop.Ssafy" id="ssafy"/>
<bean class="com.ssafy.aop.MyAspect" id="myAspect"/>
<aop:config>
<aop:pointcut expression="execution(public * com.ssafy.aop.*.coding())" id="mypt"/>
<aop:aspect ref="myAspect">
원래 밑에 있던 네줄이 다 없어져도 상관이 없고 그 밑에 around줄만 있으면 전과 같은 출력 가능
<!-- <aop:before method="before" pointcut-ref="mypt"/> -->
<!-- <aop:after-returning method="afterReturning" pointcut-ref="mypt" returning="num"/> -->
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="mypt" throwing="th"/> -->
<!-- <aop:after method="after" pointcut-ref="mypt"/> -->
<aop:around method="around" pointcut-ref="mypt"/>
</aop:aspect>
</aop:config>
</beans>
//
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git Push 한다. : 55개의 코드를
보람찬 하루를 마무리 한다.
컴퓨터를 부팅한다.
열심히 공부를 한다.
반차를 낸다.
병원 가자
보람찬 하루를 마무리 한다.
Spring AOP 시작하기-Annotation
<?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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<context:component-scan base-package="com.ssafy.aop"></context:component-scan>
</beans>
package com.ssafy.aop;
import java.util.Random;
import org.springframework.stereotype.Component;
@Component
public class Programmer implements Person {
// 필드는 필요없고
// 프로그래머의 일상(여러분들이 작성한 코드 수를 반환)
@Override
public int coding() throws OuchException {
System.out.println("열심히 코드를 작성한다."); // 핵심관심사항
if(new Random().nextBoolean())
throw new OuchException();
return (int)(Math.random()*100)+1;
}
}
===========================================================
package com.ssafy.aop;
import java.util.Random;
import org.springframework.stereotype.Component;
@Component
public class Ssafy implements Person {
// 필드는 필요없고
// SSAFY인의 일상
@Override
public int coding() throws OuchException {
System.out.println("열심히 공부를 한다."); // 핵심관심사항
if(new Random().nextBoolean())
throw new OuchException();
return (int)(Math.random()*100)+1;
}
}
===========================================================
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(public * com.ssafy.aop.*.coding())")
public void mypt() {}
@Before("mypt()")
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
@AfterReturning(value="mypt()", returning = "num")
public void afterReturning(int num) {
System.out.println("Git Push 한다. : " + num +"개의 코드를");
}
@AfterThrowing(value = "mypt()", throwing = "th")
public void afterThrowing(Throwable th) {
System.out.println("반차를 낸다.");
if(th instanceof OuchException) {
((OuchException)th).handleException();
}
}
@After("mypt()")
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
}
Annotation을 이용한 AOP 최종
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(public * com.ssafy.aop.*.coding())")
public void mypt() {}
@Before("mypt()")
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
@AfterReturning(value="mypt()", returning = "num")
public void afterReturning(int num) {
System.out.println("Git Push 한다. : " + num +"개의 코드를");
}
@AfterThrowing(value = "mypt()", throwing = "th")
public void afterThrowing(Throwable th) {
System.out.println("반차를 낸다.");
if(th instanceof OuchException) {
((OuchException)th).handleException();
}
}
@After("mypt()")
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
}
=========================================================
package com.ssafy.aop;
public class OuchException extends Exception{
public void handleException() {
System.out.println("병원이나 가자~~");
}
}
=========================================================
package com.ssafy.aop;
public interface Person {
public int coding() throws OuchException;
}
=========================================================
package com.ssafy.aop;
import java.util.Random;
import org.springframework.stereotype.Component;
@Component
public class Programmer implements Person {
// 필드는 필요없고
// 프로그래머의 일상(여러분들이 작성한 코드 수를 반환)
@Override
public int coding() throws OuchException {
System.out.println("열심히 코드를 작성한다."); // 핵심관심사항
if(new Random().nextBoolean())
throw new OuchException();
return (int)(Math.random()*100)+1;
}
}
=========================================================
package com.ssafy.aop;
import java.util.Random;
import org.springframework.stereotype.Component;
@Component
public class Ssafy implements Person {
// 필드는 필요없고
// SSAFY인의 일상
@Override
public int coding() throws OuchException {
System.out.println("열심히 공부를 한다."); // 핵심관심사항
if(new Random().nextBoolean())
throw new OuchException();
return (int)(Math.random()*100)+1;
}
}
=========================================================
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Spring_02_AOP_Annotation</groupId>
<artifactId>Spring_02_AOP_Annotation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<spring-version>5.3.18</spring-version>
<aspectj-version>1.9.8</aspectj-version>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj-version}</version>
</dependency>
</dependencies>
</project>
=========================================================
<?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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<context:component-scan base-package="com.ssafy.aop"></context:component-scan>
</beans>
=========================================================
package com.ssafy.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
Person p = context.getBean("ssafy", Person.class);
try {
p.coding();
} catch (OuchException e) {
}
}
}
//
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git Push 한다. : 22개의 코드를
보람찬 하루를 마무리 한다.
컴퓨터를 부팅한다.
열심히 공부를 한다.
반차를 낸다.
병원이나 가자~~
보람찬 하루를 마무리 한다.
Around 형식으로 바꾼다면
나머지 코드는 위와 동일
package com.ssafy.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(public * com.ssafy.aop.*.coding())")
public void mypt() {}
public void before() {
System.out.println("컴퓨터를 부팅한다.");
}
public void afterReturning(int num) {
System.out.println("Git Push 한다. : " + num +"개의 코드를");
}
public void afterThrowing(Throwable th) {
System.out.println("반차를 낸다.");
if(th instanceof OuchException) {
((OuchException)th).handleException();
}
}
public void after() {
System.out.println("보람찬 하루를 마무리 한다.");
}
//////////////////////////////////////////////////////////
//aroud
@Around("mypt()")
public int around(ProceedingJoinPoint pjt) {
int num = 0;
this.before();
try {
num = (int) pjt.proceed();//핵심관심사항
this.afterReturning(num);
} catch (Throwable e) {
this.afterThrowing(e);
}finally {
this.after();
}
return num;
}
}
============================================================
package com.ssafy.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
Person p = context.getBean("ssafy", Person.class);
try {
p.coding();
} catch (OuchException e) {
}
}
}
//
컴퓨터를 부팅한다.
열심히 공부를 한다.
Git Push 한다. : 99개의 코드를
보람찬 하루를 마무리 한다.
컴퓨터를 부팅한다.
열심히 공부를 한다.
반차를 낸다.
병원이나 가자~~
보람찬 하루를 마무리 한다.
Advice Type
- before - target 메서드 호출 이전
- after - target 메서드 호출 이후, java exception 문장의 finally와 같이 동작
- after returning - target 메서드 정상 동작 후
- after throwing - target 메서드 에러 발생 후
- around - target 메서드의 실행 시기, 방법, 실행 여부를 결정