[목차]
5. AOP (Aspect Oriented Program)
* 스프링 AOP에서 용어
① AOP 구현
[내용]
5. AOP (Aspect Oriented Program)
: 핵심 로직에서 임의의 동작을 진행할 경우 사용.
: 별도의 클래스로 정의하여 메소드를 탈부착식으로 사용한다.
: ex) 시큐리티, 로그인, 트랜잭션
1) 설정
ⓛ 사이트 접속 - search.maven.org/
② search창에 aspectjweaver 검색
③ version 선택
④ Apache Maven 내용 copy & paste
⑤ search창에 cglib 검색
⑥ version 선택
⑦ Apache Maven 내용 copy & paste
⑧ pom.xml에 Code 추가
<!-- aop -->
<dependencies>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
⑨ 경로에 생성됨. C:\Users\wonh\.m2\repository\
2) code
- HelloInter
public interface HelloInter {
void hello();
void hi();
}
- HelloInterImpl
public class HelloInterImpl implements HelloInter{
public HelloInterImpl() {
System.out.println("HelloInterImpl 생성자");
}
public void hello() {
System.out.println("hello 처리");
}
public void hi() {
System.out.println("hi 처리");
}
}
- WriteInter
public interface WriteInter {
void write();
}
- WriteInterImpl
public class WriteInterImpl implements WriteInter{ // 핵심 로직을 가진 클래스
public WriteInterImpl() {
System.out.println("WriteInterImpl 생성자");
}
public void write() {
System.out.println("write 수행");
}
}
- MyAspect
public class MyAspect { // 관심사항을 가진 클래스
public void myLogOn() {
System.out.println("핵심 메소드 수행전 로그온 작업");
}
public void myLogOut() {
System.out.println("핵심 메소드 수행후 로그아웃 작업");
}
public void mySecurity() {
System.out.println("핵심 메소드 수행전 보안설정");
}
}
- AspectProcess
public class AspectProcess { // 여러개의 관심사항들을 모아 처리하는 클래스
private MyAspect myAspect; // 관심사항 클래스. 여러개 가능
public void setMyAspect(MyAspect myAspect) {
this.myAspect = myAspect;
}
public Object logging(ProceedingJoinPoint joinPoint) throws Throwable{
Object object = null;
myAspect.myLogOn();
object = joinPoint.proceed(); // 메타파일에서 설정한 핵심 메소드 수행.
myAspect.myLogOut();
return object;
}
public Object logging2(ProceedingJoinPoint joinPoint) throws Throwable{
Object object = null;
myAspect.mySecurity();
object = joinPoint.proceed(); // 메타파일에서 설정한 핵심 메소드 수행.
return object;
}
}
=> logging() 메소드는 myLogOn() -> 핵심로직 -> myLogOut() 순 호출
=> logging2() 메소드는 mySecurity() -> 핵심로직 순 호출
- main
public static void main(String[] args) {
//String[] configs = new String[] {"aop1core.xml"}; // 핵심만 수행
String[] configs = new String[] {"aop1core.xml", "aop1.xml"}; // 핵심 + Aop 수행.
ApplicationContext context = new ClassPathXmlApplicationContext(configs);
WriteInter writeInter = (WriteInter)context.getBean("writeInterImpl");
writeInter.write();
System.out.println();
HelloInterImpl helloInter = (HelloInterImpl)context.getBean("helloInterImpl"); // 방법 1
HelloInter helloInter = context.getBean("helloInterImpl", HelloInter.class); // 방법 2
helloInter.hi();
helloInter.hello();
}
- aop1core.xml
<bean id="writeInterImpl" class="aop1.WriteInterImpl"/>
<bean id="helloInterImpl" class="aop1.HelloInterImpl"/>
- aop1.xml
<!-- Aspect(Advice) -->
<bean id="aspectProcess" class="aop1.AspectProcess">
<property name="myAspect" ref="myAspect"/>
</bean>
<bean id="myAspect" class="aop1.MyAspect"/>
<!-- Aop 설정 -->
<aop:config>
<aop:pointcut expression="execution(public void wri*(..))" id="poi1"/>
// wri로 시작하고 매개변수가 0개 이상인 메소드
// <aop:pointcut expression="execution(public void write())" id="poi1"/>
<aop:aspect ref="aspectProcess">
<aop:around method="logging" pointcut-ref="poi1"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:pointcut expression="execution(public void hel*(..)) or execution(public void hi*(..))" id="poi2"/>
// or || and &&
<aop:aspect ref="aspectProcess">
<aop:around method="logging2" pointcut-ref="poi2"/>
</aop:aspect>
</aop:config>
=> 핵심 로직의 wri로 시작하고 메개변수가 0개 이상인 메소드가 호출될때 AspectProcess(Aspect를 처리하는) 클래스의 logging() 메소드가 실행된다.
=> 핵심 로직의 hel로 시작하고 메개변수가 0개 이상인 메소드 또는 hi로 시작하는 메소드가 호출될때 AspectProcess클래스의 logging2() 메소드가 실행된다.
- ArticleInter
public interface ArticleInter {
void select();
}
- ArticleDao
//@Component
//@Repository
@Repository("articleDao")
public class ArticleDao implements ArticleInter{
public void select() {
System.out.println("db의 상품 자료를 read");
}
}
- LogicInter
public interface LogicInter {
void selectData_process();
}
- LogicImpl
public class LogicImpl implements LogicInter{
private ArticleInter articleInter;
public LogicImpl() {
}
public LogicImpl(ArticleInter articleInter) {
this.articleInter = articleInter;
}
public void selectData_process() {
System.out.println("selectData_proces 수행");
articleInter.select();
}
}
@Service
public class LogicImpl implements LogicInter{
@Autowired
//@Qualifier("aticleDao")
private ArticleInter articleInter;
public void selectData_process() {
System.out.println("selectData_proces 수행");
articleInter.select();
}
}
- ProfileAdvice
public class ProfileAdvice { // Advice, Aspect
public Object abc(ProceedingJoinPoint joinPoint) throws Throwable{
//핵심 메소드 이름 얻기
String methodName = joinPoint.getSignature().toString();
System.out.println(methodName+" 시작 전 작업");
Object object = joinPoint.proceed(); // 핵심 메소드
System.out.println(methodName+" 처리 후 작업");
return object;
}
}
@Aspect
@Component
public class ProfileAdvice { // Advice, Aspect
@Around("execution(public void selectData_process())")
public Object abc(ProceedingJoinPoint joinPoint) throws Throwable{
//핵심 메소드 이름 얻기
String methodName = joinPoint.getSignature().toString();
System.out.println(methodName+" 시작 전 작업");
Object object = joinPoint.proceed(); // 핵심 메소드
System.out.println(methodName+" 처리 후 작업");
return object;
}
}
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop2.xml");
LogicInter inter = (LogicInter)context.getBean("logicImpl");
inter.selectData_process();
}
- aop2.xml
<!-- 핵심 로직 처리용 클래스 -->
<bean id="logicImpl" class="aop2.LogicImpl">
<constructor-arg>
<ref bean="articleDao"/>
</constructor-arg>
</bean>
<bean id="articleDao" class="aop2.ArticleDao"></bean>
<!-- Aop 설정 -->
<bean id="profileAdvice" class="aop2.ProfileAdvice"/>
<aop:config>
<aop:aspect ref="profileAdvice">
<aop:pointcut expression="execution(public void selectData_process())" id="poi"/>
<aop:around method="abc" pointcut-ref="poi"/>
</aop:aspect>
</aop:config>
=> 핵심로직의 selectData_process()메소드 호출 시 profileAdvice클래스의 abc()메소드가 호출.
<!-- 객체 생성 : 어노테이션 -->
<context:component-scan base-package="aop3"/>
<!-- Aop 설정 -->
<aop:aspectj-autoproxy/>
* 스프링 AOP에서 용어
- Joinpoint : ‘클래스의 인스턴스 생성 시점’, ‘메소드 호출 시점’ 및 ‘예외 발생 시점’ 과 같이 어플리케이션을 실행할 때 특정 작업이 시작되는 시점을 의미.
- Advice : 조인포인트에 삽입되어 동작할 수 있는 코드를 말함.
- Pointcut : 여러 개의 조인포인트를 하나로 결합한(묶은) 것을 말함.
- Advisor : 어드바이스와 포인트컷을 하나로 묶어 취급한 것을 말함.
- Weaving : 어드바이스를 핵심 로직 코드에 삽입하는 것을 말함.
- Target : 핵심 로직을 구현하는 클레스.
- Aspect : 여러 객체에 공통으로 적용되는 공통 관점 사항을 말함.
1) AOP 구현
- LogicInter
public interface LogicInter {
void startProcess();
}
- LogicImpl
@Service // @Component와 동일하지만 가독성을 위해 Service기능을 사용하면 @Service를 사용.
public class LogicImpl implements LogicInter{
public LogicImpl() {
}
public void startProcess() {
System.out.println("핵심 로직 수행");
}
}
- aop4.xml
<!-- 어노테이션을 사용하여 객체 생성 -->
<context:component-scan base-package="aop4"/>
<!-- aop를 사용하도록 설정 -->
<aop:aspectj-autoproxy/>
<context:component-scan base-package="패키지명"/>
<aop:aspectj-autoproxy/>
- main
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("aop4.xml");
LogicInter inter = (LogicInter)context.getBean("logicImpl");
// getBean의 매개변수 : @객체 생성할 클래스명을 첫글자 소문자로 변경하여 생성.
inter.startProcess();
}
- RunAspect
// 아이디가 같으면 핵심로직 수행, 다르면 수행하지않도록 구현.
@Component
@Aspect // 독립적으로 동작할 관심 로직 클래스에 사용
public class RunAspect {
@Around("execution(public void startProcess())")
// 핵심로직의 메소드를 선택. 해당메소드 호출시 관심 메소드 호출.
//@Around는 핵심로직 실행 전/후 모두 기능을 추가할 수 있다.
public Object trace(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("AOP 시작 : 핵심 로직 처리전 id 검증");
System.out.print("input id : ");
Scanner scanner = new Scanner(System.in);
String id = scanner.nextLine();
if(! id.equalsIgnoreCase("aa")) { //equalsIgnoreCase() 대소문자 구분하지않고 비교.
System.out.println("id 불일치하여 작업을 종료합니다.");
return null;
}
Object obj = joinPoint.proceed(); // 핵심 로직 수행.
return obj;
}
}
@Component
@Aspect
@Around("excution(핵심 로직의 메소드)")
public Object 관심메소드명(ProceedingJoinPoint joinPoint) throws Throwable{ .. }
Object obj = joinPoint.proceed();
str1.equalsIgnoreCase(str2)
'BACK END > Spring' 카테고리의 다른 글
[Spring] 스프링 정리6 - Controller 처리 (0) | 2021.01.13 |
---|---|
[Spring] 스프링 정리5 - MVC Pattern (0) | 2021.01.13 |
[Spring] 스프링 정리4 - DB연동 (0) | 2021.01.12 |
[Spring] 스프링 정리2 - 생성자 주입(Constructor Injection), setter 주입(setter injection) (0) | 2021.01.12 |
[Spring] 스프링 정리1 - spring 환경구축 (0) | 2021.01.08 |