본문 바로가기
수업내용

20230710 SpringBoot/Bean/AOP

by titlejjk 2023. 7. 10.

@Configuration

Spring이 어떤 객체를 spring이 생성해서 관리할지 설정(bean설정)

xml문서로 설정하던 bean설정을 class기반으로 한다.

@Bean

메서드에서 리턴되는 객체를 Spring이 관리하는 bean이 되도록 한다.

xml문서로 적용해보자면

<bean id="myCar" class="com.example.demo.Car"/>

와 같다.

@Bean
	public Car myCar() {//메서드의 이름이 bean의 이름(id)역할을 한다.
		System.out.println("myCar()메서드 호출됨");
		Car c1= new Car();
		return c1;

여기서 myCar메서드의 이름은 bean의 이름(id)역할을 해준다.

package com.example.hello2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Boot01Hello2Application {

	public static void main(String[] args) {
		//run()메서드가 리턴해주는ApplicationContext객체의 참조값을 변수에 담고
		ApplicationContext ctx = SpringApplication.run(Boot01Hello2Application.class, args);
		//해당 객체로 부터 Car type객체 얻어내기
		Car car1=ctx.getBean(Car.class);
		car1.drive();
	}

}

싱글톤으로 관리하기 때문에 메서드를 두개로 만들어도 한번만 호출이 된다.

여러번 호출해도 Car객체는 하나만 생성된다는 의미 이다.

하나의 인터페이스로 두 개의 타입을 받아 사용할 경우 나타나는 error이다.

이럴 경우에는 메서드의 이름이 곧 bean의 이름(id)이

 

 

@SpringBootApplication어노테이션이 붙어있는main메서드가 존재하는 이 패키지를 포함해서 하위의 모든 패키지에 component scan이 자동으로 일어난다.


 AOP

package com.example.aop.util;

public class WritingUtil {
	
	//생성자
	public WritingUtil() {
		System.out.println("writingUtil 생성자");
	}
	
	public void wirteLetter() {
		System.out.println("파란색 Pen을 준비해요!");
		
		System.out.println("편지를 써요");
		
		System.out.println("Pen을 닫고 마무리해요!");
	}
	
	public void writeReport() {
		System.out.println("파란색 Pen을 준비해요!");
		
		System.out.println("보고서를 써요");
		
		System.out.println("Pen을 닫고 마무리해요!");
	}
	public void writeDiary() {
		System.out.println("파란색 Pen을 준비해요!");
		
		System.out.println("일기를 써요");
		
		System.out.println("Pen을 닫고 마무리해요!");
	}
}

메서드를 횡단하면서 공통적으로 수행하고 있는 것을 횡단관심사라 한다.

AOP를 적용하면 다른 곳에서 적용할 수 있다.

공통적으로 무언가 작업할 것이 수십군데 존재한다면 관리하기가 힘든데 AOP를 활용하여 효율적으로 관리할 수 있다.

 

횡단 메서드를 따로 관리하는 작업을 해보겠다.

AOP는 Aspect Oriented Programming 즉 관심지향프로그래밍이라는 뜻이다.

현재 수업은 maven으로 진행 중이여서 

pom.xml에서 dependency를 추가해준다.

 

공통관심사를 작성할 aspect package를 만들어주고 그안에 WritingAspect Class를 만들어준다.

.

 

그리고 기존에 WritingUtil에 작성해 두었던 메서드 핵심 구문을 제외하고 모두 제거해준다.(중복된 구현을 제거해준다.)

 

 

package com.example.aop.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect //AOP사용 어노테이션
@Component
public class WritingAspect {
	/*
	 *	Spring이 관리하는 bean의 메서드가 수행되기 이전 Before에 적용되는 Aspect
	 *	[메서드의 pattern]
	 *	리턴type => void
	 *	메서드명 => write 로 시작하는 메서드
	 *	메서드의 매개변수 => 없음
	 */
	@Before("execution(void write*())")
	public void repare() {
		System.out.println("파란색 Pen을 준비해요!");
	}
	
	@After("execution(void write*())")
	public void end() {
		System.out.println("Pen을 닫고 마무리 해요!");
	}
}

 

@Before("execution(void write*())")

Spring이 관리하는 Bean의 메서드가 수행되는 메서드 중에

void타입

write로 시작하는 모든 메서드를 수행하기 전에 구현부를 적용해라 라는 뜻이다.

메서드의()는 메서드 모양을 뜻하는데 반드시 비어있어야 한다.=>매개변수(인자)로 아무것도 전달하지 않아야 한다.

 

### Aspect가 적용되는 위치를 "Point Cut"이라고 부른다. ###

 

Aspectj Expression

  1. execution(**(..))
    => 접근 가능한 모든 메서드가 point cut
  2. execution(* test.service.*.*(..))
    =>test.service 패키지의 모든 메서드가 point cut
  3. execution(void insert*(..))
    =>리턴 type은 void이고 메서드명이 insert로 시작하는 모든 메서드가 point cut
  4. execution(*delete*(*))
    =>메서드 명이 delete로 시작하고 인자로 2개 전달받는 메서드가 point cut (aop가 적용되는 위치)
  5. execution(*delete*(*,*))
    =>메서드명이 delete로 시작하고 인자로 2개 전달받는 메서드가 point cut (aop가 적용되는 위치)
  6. excution(String update*(Integer,*))
    =>메서드의 첫번째 인자는 Integer type, 두번째 인자는 아무 type이나 다되는 메서드가
    point cut (aop가 적용되는 위치)

위의 메서드를 예제로 설명해 보자면

sendGreeting 즉 send로 시작하는 모든 모양의 메서드에서, 그리고 메신저 메서드가 Bean으로 등록된 메서드 중에서 수행할 메서드들을 찾아 본뒤에 AOP를 실행한다.

 

joinPoint.prceed( ) 는 각 메서드를 수행하기 전에 수행 할 메서드들을 조사해보고 return할지 않할지를 판단한다.

ProceddingJoinPoit는 @Around 어노테이션에서만 가능하다.

 

package com.example.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MessengerAspect {

	@Around("execution(void send*(..))")
	public void checkGreeting(ProceedingJoinPoint joinPoint) throws Throwable {
		
		//aspect가 적용된 메서드가 호출 되기 직전에 할 작업은 여기서
		//joinPoint.proceed();메서드 호출전에 aspect가 적용된 메서드가 실행된다.
		joinPoint.proceed();
		
		//aspect가 적용된 메서드가 호출 되고 나서 할 작업은 여기서 proceed()호출 이후에 한다.
		
		System.out.println("aspect가 함께한다.😒😒😒");
	}
}

 

 

Dto객체를 만들어서 joinPoint.proceed()메서드를 활용해 return해보기

 

package com.example.aop.util;

import org.springframework.stereotype.Component;

/*
 *	MemberService 메서드의 getMember()메서드에 적용할Aspect클래스를만들어서
 *	getMember()가 리턴해주는 MemberDto객체에 1, "김구라", "노량진"을 담아서
 *	리턴이 되도록 프로그래밍 해보세요.
 *
 */
@Component
public class MemberService {
	
	public MemberDto getMember(int num) {
		//객체 생성을 해서 바로 리턴해주기
		MemberDto dto = new MemberDto();
		return dto;
	}

}
package com.example.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import com.example.aop.util.MemberDto;

@Aspect
@Component
public class MemberAspect {

	@Around("execution(com.example.aop.util.MemberDto get*(..))")
	public MemberDto pushMemberDto(ProceedingJoinPoint joinPoint)throws Throwable{
		
		joinPoint.proceed();
		MemberDto dto = new MemberDto();
		dto.setNum(1);
		dto.setName("김구라");
		dto.setAddr("노량진");
		return dto;
	}
}

 

🧏‍♂️🧏‍♂️🧏‍♂️주의!!

Aspect할 Class를 만들어 줄때에도 @Component(Bean으로등록)를 꼭해주자! 안해주니까 안돌아가지 ㅡㅡ

 

'수업내용' 카테고리의 다른 글

20230711 SpringBoot Controller/JSP/MyBatis  (0) 2023.07.11
20230711 CSS3 Animate  (0) 2023.07.11
20230710 CSS3  (0) 2023.07.10
20230707 CSS3  (0) 2023.07.07
20230706 vue2->jQuery로 바꿔보기  (0) 2023.07.06

댓글