ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] 스프링 프레임워크 특징/ POJO / IoC / DI / AOP / PSA
    DEV/Spring 2024. 5. 8. 01:09

    지난번 Java 스터디에서 POJO에 대해 알아보았는데, 스프링 프레임워크 특징에 대해 자세히 알아보고자 정리한다.

     

    1. POJO (Plain Old Java Object) : 순수 자바 객체

    POJO는 스프링에서 사용되는 일반적인 자바 객체를 의미합니다. 스프링은 POJO를 이용하여 애플리케이션을 구성하고 관리합니다.

    • 데이터를 캡슐화하고 해당 데이터에 대한 접근 및 수정을 위한 getter 및 setter 메서드를 제공하는 간단한 Java 클래스를 지칭합니다.
    • 애플리케이션에서 데이터 객체를 표현하는 데 사용되며, Hibernate나 Spring과 같은 프레임워크와 함께 자주 사용됩니다.

    사용 예시

    public class Car {
        private String model;
    
        // 생성자
        public Car() {}
        
        public Car(String model) {
            this.model = model;
        }
    
        // Getter
        public String getModel() {
            return model;
        }
    
        // Setter
        public void setModel(String model) {
            this.model = model;
        }
    }
    
    

     

    2. IoC(Inversion of Control) : 제어의 역전

    IoC는 의존성 주입(DI)을 포함하는 개념으로 객체의 생성과 관리를 개발자가 직접하지 않고 프레임워크 또는 컨테이너에 위임하여 의존성을 해결하는 디자인 패턴입니다. 스프링 프레임워크에서는 IoC를 구현하기 위해 ApplicationContext와 같은 컨테이너를 사용합니다.

     

    제어 흐름의 결정 권한이 ‘프레임워크나 컨테이너’에 있으면 무엇이 좋을까?

    1. 객체 간의 결합도를 낮춤
    2. 유연한 코드 작성 가능
    3. 테스트 용이성 향상

    사용 예시

    1) Spring 설정 파일 작성 (applicationContext.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- Car 객체를 빈으로 등록 -->
        <bean id="car" class="com.example.Car">
            <property name="model" value="Hyundai"/>
        </bean>
    
    </beans>

    : IoC 컨테이너에 등록할 빈(Bean)을 설정하는 XML 파일을 작성합니다.

     

    2) 스프링 IoC 컨테이너를 이용하여 의존성 주입

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
        public static void main(String[] args) {
            // 스프링 IoC 컨테이너 초기화
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            // Car 객체를 IoC 컨테이너로부터 가져오기
            Car car = (Car) context.getBean("car");
    
            // Car 객체 사용
            car.setModel("Toyota");
            System.out.println("Car Model: " + car.getModel());
        }
    }

     

    : IoC 컨테이너를 사용하여 Car 객체를 생성하고 의존성을 주입합니다.

     

    ApplicationContext 인터페이스의 구현체인 ClassPathXmlApplicationContext를 사용하여 IoC 컨테이너를 초기화합니다. 그리고 XML 파일을 사용하여 Car 객체를 빈으로 등록하고 초기화합니다. context.getBean("car")을 통해 Car 빈을 가져온 후에는 스프링 컨테이너가 관리하는 Car 객체를 사용할 수 있습니다.

     

    💡 스프링 컨테이너 (= IoC 컨테이너)
    컨테이너의 일종으로, 제어의 역전 개념을 기반으로 동작합니다.
    스프링 컨테이너는 설정 파일에서 정의한 빈을 생성하고 의존성을 자동으로 주입하여 사용할 수 있도록 해줍니다. 이렇게 함으로써 개발자는 객체의 생성과 의존성 관리에 대한 부담을 줄일 수 있고, 코드의 유지보수성과 확장성을 향상시킬 수 있습니다.

     

    3. DI (Dependency Injection) : 의존성 주입

    객체가 필요로 하는 의존 관계를 직접 생성하는 대신 외부에서 주입받도록 합니다. 이를 사용하면 컴포넌트 간의 결합도를 낮추고 테스트 용이성, 재사용성, 유지보수성을 향상시킵니다.

     

    3-1. 생성자 주입(Constructor Injection)

    : 종속성을 ‘클래스의 생성자’를 통해 의존성을 주입하는 방법을 의미합니다.

    • 의존성을 인스턴스화하는 동안에만 사용이 가능
    • 클래스가 필요한 종속성을 생성자 매개변수로 명시적으로 선언하여 의존성을 주입하는 방식
    • 필드에 final 키워드를 사용하여 불변성을 보장 가능
    • 객체 생성 시점에 모든 필수 의존성이 주입되도록 함
    • 생성자의 매개변수가 많아질 경우 코드의 가독성이 떨어짐
    @Service
    public class CarService {
        private final Car car;
    		
        //의존성 주입
        public CarService(Car car) {
            this.car = car;
        }
        
        public void start() {
            System.out.println("Starting " + car.getModel());
        }
    }

     

    3-2. 필드 주입(Field Injection)

    : 종속성을 ‘클래스의 필드’에 직접 의존성을 주입하는 방법을 의미합니다.

    • @Autowired 어노테이션을 직접 필드에 붙여서 사용
    • 의존성을 클래스의 속성으로 선언하고, 해당 속성에 직접적으로 의존성을 할당하는 방식
    • 코드의 간결성을 유지할 수 있음
    • 테스트하기 어렵고, 의존성 주입의 불변성을 보장하지 않으며, 의존성 주입이 필수적으로 이루어지지 않을 수 있음
    • 권장되는 방법은 아님
    @Service
    public class CarService {
        
        //의존성 주입
        @Autowired
        private Car car;
        
        // 다른 메서드들...
    
    }

     

    3-3. 세터 주입(Setter Injection)

    : 종속성을 ‘클래스의 Setter 메서드’를 통해 의존성을 주입하는 방법을 의미합니다.

    • 주입할 필드가 많거나 선택적일 때 유용
    • 객체 생성 후에도 세터를 통해 의존성을 변경할 수 있는 가능성이 있음
    • 세터 메서드를 호출하지 않을 경우 의존성이 설정되지 않을 수 있음
    @Service
    public class CarService {
        private Car car;
    	
        //의존성 주입
        public void setCar(Car car) {
            this.car = car;
        }
    
        // 다른 메서드들...
    }

     

    4. AOP (Aspect-Oriented Programming) : 관점 지향 프로그래밍

    AOP는 관점 지향 프로그래밍을 의미하며, 핵심 로직과 공통된 관심 사항을 분리하여 모듈화합니다.

    로깅, 보안, 트랜잭션 관리 등과 같은 공통적인 관심사를 모듈화 하여 코드 중복을 줄이고 유지 보수성을 향상하는데 도움을 줍니다. 분리한 공통 관심사를 Aspect로 정의하고 Aspect를 적용할 메서드나 클래스에 Advice를 적용하여 공통 관심사와 핵심 관심사를 분리할 수 있습니다.

     

    4-1. 주요 용어

    용어 설명
    Aspect - 공통적인 기능들을 모듈화 한것
    Target - Aspect가 적용될 대상(메소드, 클래스 등)
    Join point - Aspect가 적용될 수 있는 시점( 메소드 실행 전, 후 등)
    Advice - Aspect의 기능을 정의한 것 (실행되는 코드)
    Point cut - Advice를 적용할 메소드의 범위를 지정하는 것

     

    4-2. 주요 어노테이션

    메서드 설명
    @Aspect 해당 클래스를 Aspect로 사용하겠다는 것을 명시
    @Before 메서드가 실행되기 전에 Advice를 실행
    @AfterReturning 메서드가 정상적으로 실행되고 반환된 후에 Advice를 실행
    @AfterThrowing 메서드에서 예외가 발생했을 때 Advice를 실행
    @After 메서드가 실행된 후에 Advice를 실행
    @Around 메서드 실행 전, 후 또는 예외 발생 시에 Advice를 실행

     

    사용 예시

    1) Aspect 클래스 정의

    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.JoinPoint;
    
    @Aspect
    public class LoggingAspect {
    
        @Before("execution(* com.example.*.*(..))")
        public void beforeMethodExecution(JoinPoint joinPoint) {
            String methodName = joinPoint.getSignature().getName();
            System.out.println("Before method: " + methodName);
        }
    }
    • @Aspect 어노테이션을 사용하여 LoggingAspect 클래스가 Aspect 역할을 한다고 선언
    • @Before 어노테이션은 지정된 포인트컷(여기서는 com.example 패키지의 모든 메서드)이 실행되기 전에 beforeMethodExecution 메서드가 실행된다는 것을 나타냄
    • JoinPoint 객체를 이용하여 실행되는 메서드의 정보(이름 등)를 얻을 수 있음

     

    2) AOP 설정 및 적용 : Aspect를 스프링 빈으로 등록하고 AOP를 설정하여 적용

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
    
        @Bean
        public LoggingAspect loggingAspect() {
            return new LoggingAspect();
        }
    }
    • @EnableAspectJAutoProxy 어노테이션으로 스프링 AOP를 사용하도록 활성화
    • loggingAspect() 메서드를 통해 LoggingAspect 빈을 생성하여 스프링 컨테이너에 등록

     

    3) 테스트

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import com.example.service.CarService;
    
    public class MainApp {
        public static void main(String[] args) {
            // 스프링 컨테이너 초기화
            ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
            // CarService Bean 가져오기
            CarService carService = context.getBean(CarService.class);
    
            // CarService의 메서드 호출
            carService.start();
        }
    }
    
    • CarService는 AOP가 적용된 대상(com.example.*)
    • start() 메서드를 호출할 때 AOP 설정에 따라 해당 메서드 실행 전에 LoggingAspect의 beforeMethodExecution() 메서드가 실행되어 로그가 출력됨

     

    5. PSA (Portable Service Abstraction) : 일관된 서비스 추상화

    PSA는 스프링 프레임워크에서 제공하는 추상화 인터페이스의 집합으로, 다양한 기술을 표준화된 방식으로 사용할 수 있도록 도와줍니다. PSA는 특정 기술에 종속되지 않고 표준 인터페이스를 제공하여 코드의 이식성과 유연성을 높이는 데 도움이 됩니다.

     

    사용예시

    // JDBC Template을 이용한 DB 접근
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    List<Car> cars = jdbcTemplate.query("SELECT * FROM cars", (rs, rowNum) ->
            new Car(rs.getString("model"))
    );
    
    • JDBC Template은 스프링이 제공하는 데이터베이스 액세스 추상화 인터페이스 중 하나로, 데이터베이스 액세스를 단순화하고 표준화된 방식으로 처리할 수 있도록 함
    • PSA는 JDBC Template을 포함하여 다양한 기술에 대해 추상화 인터페이스를 제공함
    • 이를 통해 개발자는 특정 기술에 종속되지 않고 스프링의 표준 인터페이스를 활용하여 다양한 기술을 사용할 수 있음
    • PSA를 사용하면 코드의 이식성과 유연성이 향상되며, 유지보수가 용이해짐

    참고문헌 :

    https://adjh54.tistory.com/298

    https://adjh54.tistory.com/133

     

    댓글

Designed by Tistory.