Spring

j0yy00n0·2025년 3월 13일

2025.03.11 ~ 03.13

Spring

Spring Projects는 여러가지가 있는데 먼저 Spring Framework에 대해 공부한다.
그 뒤 Spring Boot에 대해 배운다.

스프링 삼각형

  • POJO(Plain Old Java Object)
  • IoC/DI : 제어의 역전/의존성 주입
  • AOP(Aspect-Oriented Programming) : 관점 지향 프로그래밍
  • PSA(Portable Service Abstraction) : 일관성 있는 서비스 추상화

IoC/DI

  • DI(Dependecy Injection) : 클래스를 직접 생성해서 사용하는 것이 아니라 외부에서 클래스의 인스턴스를 생성해서 주입해준다.
  • IoC(Inversion of control) : 직접 의존성을 제어하지 않고 제어권을 역전한다.(프로그램의 제어 흐름 구조를 뒤바꾸는 것), 객체의 생성, 관리, 의존성 처리 등을 대신 처리해준다.
  • IoC Container : IoC 를 구현한 구체적인 프레임워크, 객체의 생성, 초기화, 의존성 처리를 자동으로 수행
  • @Autowired, XML 설정을 통해 느슨한 결합으로 변경해주고 코드를 유연하게 해준다.

AOP

  • 비즈니스 로직으로부터 중복된 관심사를 분리하는 것에 목적
  • 부가기능을 따로 관리하는 것

PSA

  • 일관성 있는 서비스 추상화
  • 어떠한 데이터 베이스를 사용하더라도 일관성 있는 방식으로 제어할 수 있도록 공통의 인터페이스를 제공하는 것이 서비스 추상화

프레임워크 & 라이브러리

프레임워크

  • 애플리케이션의 구조와 흐름을 정의하는 큰 틀
  • 전체적인 흐름을 제어하고, 개발자의 코드를 호출함
  • 애플리케이션 개발을 위한 도구, 가이드라인, 템플릿 제공
  • 여러 라이브러리를 포함하고 있다.

라이브러리

  • 개발자가 필요한 시점에 호출하여 사용할 수 있는 함수나 클래스의 집합
  • 개발자가 프로그램의 흐름을 제어하며, 언제 어디서 사용할 지 결정

차이점

  • 개발자는 프레임워크의 규칙을 따르며 필요한 부분만 코드를 작성
  • 개발자가 프로그램의 흐름을 제어하며, 언제 어디서 사용할지 결정, 특정한 구조를 강제하지 않는다.
  • 프레임워크는 개발자의 코드를 호출하고, 라이브러리는 개발자가 라이브러리를 직접 호출한다.
  • 제어
  • 유연성

Spring Framework

Java 기반의 Application을 위한 Open Source 프레임워크

  • 동적인 Web 사이트를 개발하기 위한 여러 서비스를 제공, 대한민국 공공기관의 웹 서비스 개발 시 권장되는 전자정부 표준 프레임워크의 기반 기술
  • 애플리케이션의 요구 사항에 따라 다양한 종류의 Java 기반 아키텍처를 생성할 수 있는 유연성
  • 버전 호환성, 유지 보수성

Spring Framework 주요 모듈


Spring Framework에서 핵심적으로 봐야하는 것은 Core technologies 부분이다.

  • Spring Core Container
  • AOP
  • Data Access/Integration
  • Web
  • Test

intellij로 SpringFramwork 사용하기

주요 설정

  • Build System -> Gradle : Java 용 Build System 으로 Maven 방식 보다 빠르며 유연성이 높다는 특징
  • Maven Repository : 라이브러리 저장소로서 필요한 Java 라이브러리를 쉽게 가져올 수 있다.
  • https://mvnrepository.com/
  • spring-context:6.1.14 -v : spring 의 핵심인 Core Container 를 구성할 수 있게 해주는 라이브러리

Core technologies

  • DI(dependency injection)
  • Ioc Container
    -Bean
    -Dependencies
    -Bean Scopes

IoC Container

Bean

Spring IoC Container 에서 관리되는 객체

  • Spring Container가 Bean의 생성, 소멸, 주입을 담당한다.
  • Bean 은 초기화(init), 소멸화(destroy) 의 생명 주기를 가지고 있다
  • BeanFactory : Spring IoC Container 의 가장 기본적인 형태, Bean의 Life-Cycle 관리
    -ApplicationContext보다 더 가벼운 컨테이너로 메모리 사용량이 적다.
    -지연 로딩 방식으로 동작하여, 필요할 때만 Bean 생성
    -BeanFactory 를 구성하기 위해 Configuration Meta-Data를 사용

DTO(Data Transfer Object)

계층간 데이터 전달을 위한 객체, 데이터를 단순히 담는 역할

  • 일반적으로 Getter/Setter만 포함하는 단순한 구조
  • 데이터를 담아 DAO로 전달

DAO(Data Access Object)

데이터베이스와 직접 상호작용하는 객체, 데이터 저장, 조회 역할

  • 데이터를 저장하고 조회해서 DTO로 반환

Context

Spring이 애플리케이션의 환경을 관리하는 중심 역할을 하는 객체
일반적으로 "환경" 또는 "설정"을 의미하며, Spring에서는 애플리케이션 환경을 관리하는 객체

  • Context는 "Spring 컨테이너"이며, Bean을 관리하는 환경이다.
    우리가 ApplicationContext(인터페이스)를 사용하면 Context가 애플리케이션 환경을 설정하고 Bean을 관리
= context.getBean("bean id", 클래스명.class);
// spring 컨테이너(context)에서 "bean id"을 찾음
// 찾은 Bean을 맞는 타입으로 변환하여 반환

ApplicationContext

Spring의 대표적인 IoC 컨테이너(Bean 관리 객체)

  • BeanFactory를 확장한 인터페이스
  • Spring 애플리케이션에서 "메인 컨테이너" 역할
  • BeanFactory보다 ApplicationContext를 사용

ApplicationContext 주요 메서드

  • getBean(Class<T> requiredType) : 특정 타입의 Bean 가져오기
  • getBean(String name, Class<T> requiredType) : 특정 이름과 타입을 가진 Bean 가져오기
  • containsBean(String name) : 특정 이름의 Bean이 존재하는지 확인
  • getBeanDefinitionNames() : 등록된 모든 Bean의 이름 가져오기

Spring에서 Bean 등록하는 방식 3가지

Configuration Metadata(설정 메타데이터)를 사용하여 Bean을 등록하는 방식에 따라 Context 객체의 구현체가 달라진다.
ApplicationContext 구현체

  • XML 기반
  • Java 기반
  • Annotation 기반

XML 기반

.xml에서 Bean을 직접 설정

  • xml 파일은 Spring의 빈(bean) 설정 파일로 스프링 컨테이너에 등록하는 역할
  • .xml 파일은 main > resources 안에 저장하고 설정한다.
  • 사용되는 컨텍스트 : GenericXmlApplicationContext("XML Configuration Metadata 파일 경로");
<bean id="스프링 컨테이너에서 관리할 빈의 이름" class="빈 클래스 주소">
<constructor-arg index="빈객체의인덱스" value=""/>
<constructor-arg name="필드변수명" value=""/>
<constructor-arg index="빈객체의인덱스" <value></value></constructor-arg>
<constructor-arg name="필드변수명"<value></value></constructor-arg>

이제 위와 같은 정보로 Spring이 자동으로 객체를 생성하고 해당 빈을 bean id 로 관리하게 된다.
여러가지 설정하는 방법을 적어놓은 것이다. 편한 방법으로 값을 다 넣어주면 된다.

bean을 실행하는 방법

ApplicationContext context = new GenericXmlApplicationContext("XML Configuration Metadata 파일 경로"); // 주로 bean 객체 명과 혼동되지 않게 ApplicationContext 객체 명은 일반적으로 context로 작성
// new를 사용하는 이유는 ioc container를 만들기 위해서 생성
  • bean의 id를 이용해서 bean을 가져오는 방법
DTO명 변수명 = (DTO명) context.getBean("bean id"); // getBean은 Object로 받기 때문에 형변환을 해준다.
// 잘못된 클래스로 캐스팅할 경우 오류 발생 가능
  • bean의 클래스 메타 정보를 전달하여 가져오는 방법
DTO명 변수명 = context.getBean(DTO명메타정보.class);
// 단, 같은 타입의 Bean이 여러 개 있으면 오류 발생 가능
  • bean의 id와 클래스 메타 정보를 전달하여 가져오는 방법
DTO명 변수명 = context.getBean("bean id",DTO명메타정보.class)
// 가장 명확하고 안전한 방식
// .class : 클래스의 정보를 담고있는 Class 타입 객체

Java 기반

@Configuration 클래스에서 @Bean을 사용

  • @Configuration : 이 클래스가 Spring 설정 클래스, 빈을 생성하는 클래스임을 의미, Spring이 이 클래스를 기반으로 IoC 컨테이너를 구성할 수 있도록 도와주는 역할
  • @Bean : 직접 Bean을 생성하고 관리, 해당 메소드의 반환 값을 스프링 컨테이너에 빈으로 등록한다는 의미
  • 사용되는 컨텍스트 : AnnotationConfigApplicationContext(빈클래스명.class);
    xml 없이 java 코드만으로 설정 가능하므로 유지보수가 더 쉽다.
    @Bean을 사용하여 직접 객체를 생성하고 관리할 수 있다.
@Configuration
public class 클래스명{
	@Bean(name="bean id")
    public DTO명 메서드명(){
    	return new DTO명(값들,값들...);
  • @Bean() : 이름을 별도로 지정하지 않으면 메소드 이름을 bean의 id로 자동인식
  • @Bean("bean id"), @Bean(name="bean id") 두가지 방법으로 id를 설정할 수 있음
ApplicationContext context
                = new AnnotationConfigApplicationContext(빈클래스명.class); // @Configuration 어노테이션이 달린 설정 클래스의 메타 정보를 전달
DTO명 변수명 = context.getBean("bean id",DTO명메타정보.class);

Annotation 기반

Spring에서 Annotation을 사용하면 자동으로 Bean을 등록할 수 있다.
@ComponentScan : base package 로 설정 된 하위 경로에 특정 어노테이션(@Component, @Service, @Repository 등이 붙은)을 가지고 있는 클래스를 Bean 으로 등록하는 기능, 상위 패키지를 설정하는 것을 추천

  • @Component의 대표적인 종류 : @Component, @Controller, @Service, @Repository, @Configuration
  • @Component :객체를 나타내는 일반적인 타입 @Bean과 동일한 역할, 자동으로 Spring Bean으로 등록됨, Bean 등록 클래스에서 사용
  • @Controller : 프레젠테이션 Layer, WebApplication에서 View에서 전달 된 요청과 응답을 처리하는 계층
  • @Service : Service Layer, 비즈니스 로직(애플리케이션의 핵심 기능을 수행하는 코드) 처리 계층
  • @Repository : Persistence Layer, 영속성을 가지는 속성(DB) DAO 타입의 객체에 사용
  • @Configuration : Bean을 등록하는 Config 클래스(의존성 주입@Autowired, @Qualifier), 환경설정 등
  • 사용되는 컨텍스트 : AnnotationConfigApplicationContext
    가장 많이 사용되는 방식, xml을 사용하지 않고 코드만으로 Bean을 설정할 수 있어서 유지보수가 쉬움
@Configuration // Spring이 이 클래스를 기반으로 IoC 컨테이너를 구성할 수 있도록 도와주는 역할
@ComponentScan(basePackages="패키지경로")
public class bean클래스명
ApplicationContext context
                = new AnnotationConfigApplicationContext(빈클래스명.class);
String[] 변수명 = context.getBeanDefinitionNames(); // getBeanDefinitionNames : 스프링 컨테이너에서 생성 된 bean들의 이름을 배열로 반환, 어떤 bean들이 있는지 출력해보고 아래 bean클래스명을 이용하면 된다.
bean클래스명 변수명 = context.getBean("bean id",bean클래스명메타정보.class);      

참조

String[] beanNames = context.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            System.out.println("beanNames = " + beanName);
        }
  • spring 컨테이너에 등록된 모든 Bean의 이름을 String[]배열로 반환
  • beanNames 배열의 요소(Bean 이름들)를 하나씩 beanName 변수에 저장하면서 반복 실행
  • beanNames는 배열 전체, beanName은 개별 요소
  • beanName은 beanNames 배열에서 하나씩 꺼낸 Bean 이름

DI(Dependecy Injection)

객체와 객체 간의 의존 관계를 Bean 의 설정 정보를 바탕으로 Container 가 자동으로 연결해주는 것

  • bean끼리 연결해준 것! 의존성 주입
  • 객체 간의 결합도를 낮출 수 있고 유지보수성과 유연성을 증대
  • 인터페이스를 만들어서 bean 객체들은 인터페이스들을 받을 수 있도록 작성한다.
  • 클래스가 의존하는 객체를 interface로 정의하고 실제 구현체를 Class타입로 지정 -> 인터페이스를 받는 클래스의 경우 "클래스명Impl"이라고 작성하는 것이 관념적

주입 받는 방식

  • 필드(Field) 주입 : 의존성을 추가할 객체를 field 로 선언 후 @Autowired 어노테이션 추가, final 사용 불가
  • 생성자(Constructor) 주입 : 의존성을 추가할 객체를 field 로 선언 후 생성자를 통해 주입, final 사용 가능(객체 불변성 보장) 객체가 생성될 때 모든 의존성이 주입되기 때문에 의존성 보장
    코드의 가독성 향상
    '순한 참조'에 대해 필드/세터 주입은 메소드 실행 시점에 오류 발생, 생성자 주입은 어플리케이션 실행 시점에 오류 발생
  • Setter 주입 : Setter 메소드를 사용해서 field 로 선언한 객체를 주입
  • 참고 -> final은 시간에 따라 값이 바뀔 위험이 있을 때 고정하고 싶다면 사용한다.

의존성 주입 방법 .xml

  • bean 태그의 클래스 속성은 인터페이스 타입이 아닌 구현 클래스 타입으로 작성해야 한다.
<bean id="bean id" class="구현 클래스 타입 주소">
	<constructor-arg index="index 번호" value=""/>
  • 생성자 주입
<bean id="bean id" class="DTO클래스 주소">
	<constructor-arg name="필드변수명" value=""/>
    <constructor-arg name="필드변수명" ref="연결할 bean id"/>
  • setter 주입
<bean id="bean id" class="DTO클래스 주소">
	<property name="필드변수명" value=""/>
    <property name="필드변수명" ref="연결할 bean id"/>

생성 된 다른 bean을 의존성 주입할 경우에는 value 속성이 아닌 ref 속성을 사용하여 bean id를 전달한다.

의존성 주입 방법 java 설정

@Configuration
public class 빈클래스이름 {
	// 독립적인 객체 생성(Bean 등록)
	@Bean
    public 객체명1 객체1생성() {
    	return new 객체명9("값");
    }
  • 생성자 주입
    @Bean
    public 객체명2 객체2생성() {
    	return new 객체명2("값",객체1생성());
    }
  • setter 주입
    @Bean
    public 객체명2 객체2생성() {
    	객체명2 변수명 = new 객체명2();
        변수명.set필드1("값");
        변수명.set필드2(객체1생성());
        
        return 변수명;
	}
}

의존성 주입 방법 Annotation

  • @Autowired : Type을 이용한 DI를 할 때 사용, Spring Container가 알아서 해당 타입의 Bean을 찾아서 주입
    spring이 @Autowired 를 보고 해당 타입의 Bean을 컨테이너에서 찾아서 자동으로 주입

  • @Primary : 하나의 Interface 를 상속 받는 여러 개의 Class 중 우선 순위가 높은 Bean 을 지정

  • @Qualifier : 하나의 Interface 를 상속 받는 여러 개의 Bean 객체 중 특정 Bean 을 이름으로 지정, Primary보다 우선 순위 -> @Qualifier가 지정되면 @Primary는 무시됨

  • Collection : List 타입 , Map 타입으로 여러 개의 Bean 을 동시에 주입 받을 수 있다
    @Autowired를 사용하여 List<>, Map<> 타입으로 자동 주입

  • 필드 주입

@Service("bean id")
public class 빈클래스 이름{
	@Autowired
    private DAO객체 필드명;
    
    // 서비스 로직
    public List<DTO객체> 메서드1() {
        return 필드명.메서드();
    }

    // 서비스 로직
    public DTO객체 메서드2(자료형 매개변수) {
        return 필드명.메서드(매개변수);
    }
}
ApplicationContext context = new AnnotationConfigApplicationContext("패키지명"); //컨퍼넌트스캔 기능 활성화
빈클래스명 변수명 = context.getBean("bean id", 빈클래스명.class);
  • 생성자 주입
@Service("bean id")
public class 빈클래스 이름{
	
    private DAO객체 필드명;
    
    @Autowired
    public 빈클래스 이름(DAO객체 필드명) {
        this.필드명 = 필드명;
    }
    // 서비스 로직
    public List<DTO객체> 메서드1() {
        return 필드명.메서드();
    }

    // 서비스 로직
    public DTO객체 메서드2(자료형 매개변수) {
        return 필드명.메서드(매개변수);
    }
}
ApplicationContext context = new AnnotationConfigApplicationContext("패키지명");
빈클래스명 변수명 = context.getBean("bean id", 빈클래스명.class);

변수명.빈메서드().forEach(System.out::printIn)
  • setter 주입
@Service("bean id")
public class 빈클래스 이름{
	
    private DAO객체 필드명;
    
    @Autowired
    public void set필드명 이름(DAO객체 필드명) {
        this.필드명 = 필드명;
    }
    // 서비스 로직
    public List<DTO객체> 메서드1() {
        return 필드명.메서드();
    }

    // 서비스 로직
    public DTO객체 메서드2(자료형 매개변수) {
        return 필드명.메서드(매개변수);
ApplicationContext context = new AnnotationConfigApplicationContext("패키지명");
빈클래스명 변수명 = context.getBean("bean id", 빈클래스명.class);

변수명.빈메서드().forEach(System.out::printIn)
  • 참고 -> forEach() : 컬렉션이나 배열을 반복하면서 각 요소에 대해 특정 작업을 수행하는 메서드

생성자 주입의 장점

  • 객체가 생성 될 때 모든 의존성이 주입 되므로 의존성을 보장할 수 있다.
    -'순환 참조' 에 대해 필드 주입/세터 주입은 메소드 실행 시점에 오류가 발생한다.
    -생성자 주입은 어플리케이션 실행 시점에 오류가 발생한다.
  • 객체의 불변성을 보장할 수 있다.
    -필드에 'final' 사용 가능하고 객체 생성 이후 의존성을 변경할 수 없어 안정성이 보장 된다.
  • 코드 가독성이 좋다.
    -해당 객체가 어떤 의존성을 가지고 있는지 명확히 알 수 있다.
  • DI 컨테이너와의 결합도가 낮기 때문에 테스트 하기 좋다.
    -스프링 컨테이너 없이 테스트를 할 수 있다.

@Primary, @Qualifier, Collection

  • @Primary
@Configuration 클래스 내부 @Bean 메서드 위
@Service, @Repository, @Component 클래스 위
  • @Qualifier
//필드주입
@Autowired
@Qualifier("빈 id")
private 필드자료형 필드명;
//생성자 주입
@Autowired
public 빈클래스명(@Qualifier("빈 id") 필드자료형 필드명){
	this.필드명 = 필드명;
}
// setter 주입
@Autowired
public set필드명(@Qualifier("빈 id") 필드자료형 필드명){
	this.필드명 = 필드명;
}
  • Collection 주입
//list
@Autowired
private List<객체명> 변수명;
//Map
@Autowired
private Map<자료형, 객체명> 변수명; 

Bean Scope

스프링 빈이 생성될 때 생성되는 인스턴스의 범위

Singleton(Default Scope)

  • 하나의 인스턴스만 생성을 하고, 모든 Bean 이 해당 인스턴스를 공유하여 사용
  • Spring 의 Bean 의 Default Scope 는 Singleton

Prototype

  • 매번 요청 시 새로운 인스턴스를 생성
@Bean
@Scope("prototype")
public ~

Request

  • Http 요청을 할 때마다 새로운 인스턴스 생성, 요청 처리 완료 시 폐기

Session

  • Http Session 당 하나의 인스턴스 생성, 세션 종료 시 폐기

Bean Life-Cycle

Bean 은 초기화(init), 소멸화(destroy) 의 생명 주기를 가지고 있다.

java 방식

@Bean(initMethod = "시작할 때 실행되길 원하는 메서드명", destroyMethod = "종료될 때 실행되길 원하는 메서드명")

ApplicationContext는 jvm이 종료가 되더라도 자동으로 종료를 시키지 않는다. -> close()메서드를 제공하지 않음.
실제 close() 메서드를 제공하는 건 AnnotationConfigApplicationContext 클래스
-> 따라서 context를 AnnotationConfigApplicationContext로 다운캐스팅한 후 close() 호출해야 함

((AnnotationConfigApplicationContext) context).close();

컨테이너 강제로 종료시킨 것이다.

Annotation 방식

implementation("javax.annotation:javax.annotation-api:1.3.2") - gradle에 추가

@Component
public class 클래스명{
	@PostConstruct
    public void 시작시실행메서드() {
        // Bean 생성 후 실행할 코드
    }
    @PreDestroy
    public void 종료시실행메서드() {
        // Bean 소멸 전에 실행할 코드
    }
}
((AnnotationConfigApplicationContext) context).close();
// AnnotationConfigApplicationContext으로 context를 선언했으면 context.close()만 작성해도 된다.

Properties

Key - Value 쌍으로 이루어진 간단한 파일

  • security 사용 시 많이 사용, 설정파일을 공개하지 않도록 github .gitignore 쪽에 관리, 설정값을 키값으로만 가지고 오게 할 수 있도록 하는 설정파일
  • 보통 소프트웨어 설정 정보을 저장할 때 사용
  • Spring에서는 Properties를 사용해서 Bean의 속성 값을 외부 설정 파일에서 저장 후 불러오는 용도로 사용

Properties 값을 Spring Bean에 주입하는 방법

Spring에서는 @Value, @ConfigurationProperties를 사용하여 Properties 파일의 값을 Spring Bean에 주입할 수 있다

  • 설정 파일은 resources 하위에 디렉토리 형식으로 만든다.(디렉토리는 .이 아닌 /으로 하위를 나눈다.)
  • @Value("${키}") : Properties 파일의 값을 Spring Bean에 주입
  • @ConfigurationProperties(설정값 = "키") : 그룹 단위로 설정 값 가져오기, @Value보다 더 구조적으로 설정 값을 다룰 수 있음
  • 치환자(placeholder) 문법 : properties에 저장된 key를 입력하면 value에 해당하는 값을 꺼내온다
    -공백을 사용하면 값을 읽어오지 못하니 주의
    -: 을 사용하면 값을 읽어오지 못하는 경우 사용할 대체 값을 작성할 수 있다
resources 하위에 디렉토리 형식으로 properties설정파일 만든다.
key-value 형식으로 데이터들 작성
@Configuration
@PropertySource("classpath:properties파일경로 ")
public class ContextConfiguration {
	// 필드 주입 방식
	@Value("${properties안 key값}")
    private 자료형 필드명;
    
    @Value("${properties안 key값 잘못적을 시:대체값}")
    private 자료형 필드명2;
    
    @Bean
    public bean객체명 메서드1(){
    	return new 메서드2(필드명1, 필드명2, 필드명3);
    }
    /// 매개변수 주입 방식
    @Bean
    public bean객체명 메서드3(@Value("${properties안 key값}") 자료형 필드명,@Value("${properties안 key값 잘못적을 시:대체값}")자료형 필드명2){
    	return new 메서드4(필드명4, 필드명5, 필드명6);
    } 
}

AOP

관점 지향 프로그래밍(Aspect Oriented Programming)

  • 중복되는 공통 코드 분리, 코드 실행 전/후 시점에 해당 코드를 삽입 함으로서 소스 코드의 중복을 줄인다.
  • 필요 시에 가져다 쓸 수 있게 객체화 하는 기술을 의미

AOP 의 핵심 용어

  • Aspect : 핵심 비즈니스 로직과는 별도로 수행되는 횡단 관심사

  • Advice : Aspect 의 기능 자체 의미

  • Join Point : Advice 가 적용될 수 있는 위치를 의미

  • Pointcut : Join Point 중에서 Advice 가 적용 될 가능성이 있는 부분 선별 의미

  • Weaving : Advice 를 핵심 비즈니스 로직에 적용하는 것을 의미

  • @EnableAspectJAutoProxy(proxyTargetClass = true) : Spring AOP를 활성화하고, 프록시(proxy)를 사용하여 핵심 로직을 감싸겠다

  • @Aspect를 사용하려면 반드시 @EnableAspectJAutoProxy가 필요!

  • proxyTargetClass = true : CGLIB 기반 프록시를 사용

  • proxyTargetClass = false : JDK 동적 프록시 (기본값) 사용

Aspect

핵심 비즈니스 로직과는 별도로 수행되는 횡단 관심사

  • 비즈니스 로직과는 독립적인 기능(ex. 로깅, 트랜잭션, 보안, 예외 처리)
  • @Aspect

Advice

Aspect가 수행하는 기능 자체

  • 실제로 실행되는 코드 부분
    모두 일반적으로 void로 반환받음
  • @Before(클래스명.포인트컷) : 대상 메서드 실행 전에 실행
@Before("포인트컷")
public void 메서드1(JoinPoint 매개변수) {}
  • @After(포인트컷) : 대상 메서드 실행 후에 실행
@After("포인트컷")
public void 메서드2(JoinPoint 매개변수) {}
  • @AfterReturning(pointcut = "포인트컷", returning ="매개변수") : 대상 메서드가 정상적으로 실행된 후 실행, 예외발생 시 실행하지 않음
@AfterReturning(pointcut = "포인트컷", returning = "매개변수")
public void 메서드3(JoinPoint 매개변수, Object result) {}
  • @AfterThrowing(pointcut = "포인트컷", throwing = "매개변수") : 대상 메서드에서 예외가 발생한 후 실행
@AfterThrowing(pointcut = "포인트컷", throwing = "매개변수")
public void 메서드4(JoinPoint 매개변수, Exception exception) {}

Object로 반환 받음

  • @Around : 대상 메서드 실행 전후에 실행 (가장 강력함)
@Around("포인트컷")
public Object 메서드(ProceedingJoinPoint 매개변수) throws Throwable {
	Object 변수 = 매개변수.proceed();
    return 변수;
}

Join Point

Advice가 적용될 수 있는 위치

  • Spring AOP에서는 메서드 실행 시점만 Join Point가 될 수 있음
  • .getTarget() : 프록시(proxy) 내부의 실제 대상 객체(target)를 반환하는 메서드
  • .getSignature() : Spring AOP에서 조인포인트(JoinPoint)의 메서드 정보를 가져올 때 사용, @Before, @After, @Around 어드바이스에서 메서드 정보를 출력할 때 유용
  • .getArgs()[index값] : Spring AOP에서 조인포인트(JoinPoint)로 전달된 메서드의 매개변수를 가져올 때 사용, AOP가 적용된 메서드의 인자(arguments)를 배열 형태로 반환하고, getArgs()[index]로 특정 값을 가져올 수 있음, 메서드 실행 시 전달된 첫 번째 인자 값을 가져옴

Pointcut

Join Point 중에서 특정 조건을 만족하는 부분만 선별

  • Advice가 실행될 위치를 결정하는 필터 역할, 실행되는 부분이 아니다.
  • Advice 부분 메서드 안에 아래 값들을 넣어서 실행
  • execution(), within(), bean() 등의 표현식을 사용하여 설정
  • @Pointcut("execution(패키지.클래스.메서드.*(..))") : 모든 매개변수를 포함하는 메서드 실행
  • execution(패키지.클래스.메서드.*()) : 매개변수가 없는 매서드 실행
  • execution(패키지.클래스.메서드.*(특정 파라미터)) : 특정 매개변수가 있는 메서드 실행
  • within(패키지..*) : 특정 패키지 내의 모든 클래스 적용
  • bean(빈이름) : 특정 빈 이름을 가진 객체에 적용
  • @annotation(어노테이션) : 특정 어노테이션이 붙은 메서드 실행 시 적용

Weaving

Advice를 핵심 비즈니스 로직에 적용하는 과정

  • Spring AOP는 런타임(실행 중) 위빙을 사용
  • Spring AOP는 proxy 기반 위빙을 사용 -> 메서드 실행 시점에 Advice가 실행되도록 프록시 객체를 생성

정리

  • @Aspect → 이 클래스는 부가 코드(횡단 관심사)를 담당하는 AOP 설정 클래스임을 명시
  • @Component → Spring이 이 클래스를 Bean으로 등록할 수 있도록 함
  • @Pointcut → AOP가 적용될 대상(JoinPoint)을 지정하는 필터 역할 (Advice가 실행될 위치 결정)
  • @Before, @After → JoinPoint(실제 실행 지점)에서 실행될 부가 코드(Advice)를 정의
  • JoinPoint → 실제 실행될 메서드 정보, 매개변수 등을 가져와서 로깅할 수 있음
  • 모든 Weaving(AOP 적용 과정)이 끝나면 핵심 비즈니스 로직 실행으로 넘어감

Spring AOP 특징

  • 프록시 기반의 AOP 구현체 : Taget Object 에 대한 프록시를 만들어 제공하며, 프록시는 Runtime 시 생성
  • Method 조인 포인트만 제공 : 핵심 기능(대상 객체) 의 메소드가 호출되는 Runtime 시점에만 Advice 적용 가능

Proxy

Java에서 프록시는 대리자를 의미

  • 기존의 객체를 감싸서 그 객체의 기능을 확장하거나, 변경할 수 있게 해준다.
  • 주로 AOP에서 사용되는 개념
  • ex) 객체 접근 제어, 객체 메소드 호출 전후에 Logging
    Logging : 프로그램 실행 중 발생하는 다양한 정보를 기록하는 것

참고

  • alt + insert 단축키
profile
잔디 속 새싹 하나

0개의 댓글