스프링 기초

김주언·2022년 8월 31일
0

Spring

목록 보기
3/15
post-thumbnail

1. 스프링 주요 특징

1.1 의존성

의존성 : 하나의 객체가 다른 객체 없이 제대로 된 역할을 수행하지 못하는 것

예를 들어 음식점에서 서빙 직원이 없을 경우 → ㄱㅊ
그런데 주방장이 없을 경우 → 큰일!!

이처럼 A 객체가 B 객체 없이 정상 동작 불가한 경우 A가 B에게 의존적이다

1.2 주입

외부에서 밀어넣는 것.

예를 들어 어떤 음식점은 식재료를 구하기 위해서 직접 시장을 간다. 반면에 다른 프랜차이즈 가게는 본사에서 알아서 갖다 줌

→ 필요한 객체를 얻기 위해서 주체가 능동적인가 수동적인가?

즉, 어떤 객체에게 필요한 객체를 외부에서 밀어 넣는 것이 의존성과 주입의 개념

이러면 무슨 이득을 보는가?

  • 주입을 받는 입장에서 어떤 객체인지 신경 쓸 필요 x
  • 어떤 객체에 의존하든 주체의 역할은 변하지 않는다.

1.3 ApplicationContext

그림으로 보면 아래와 같다.

1.객체 A가 B를 직접 생성
2. A는 B가 필요하다는 신호를 보낸다 → B객체를 주입하는 것은 외부에서 이루어진다.

2번 그림이 의존성 주입을 수행하는 방식인데, 이를 위해서 추가적으로 하나의 외부 존재가 필요하고, 스프링에서는 이 존재가 ApplicationContext라는 존재이다.

ApplicationContext가 관리하는 객체들을 Bean이라고 부르고, 빈과 빈 사이의 의존관계를 처리하는 방식을 지정하기 위해서 XML 설정, 어노테이션 설정, JAVA 설정 방식을 사용가능

1.4 AOP

Aspect Oriented Programming

보안, 로그, 트랜잭션 등 비즈니스 로직은 아니지만 반드시 처리가 필요한 부분들을 횡단 관심사라고 한다. 스프링은 이러한 횡단 관심사를 분리하여 제작 가능하고, 이를 AOP라고 하는 것

AspectJ 문법을 이용하여 작성가능하다.


2. 의존성 주입 예제

식당에서 일하는 주방장..

  • Lombok 이용하여 setter 메서드 자동 구현하기 위해 pom.xml에 라이브러리 추가하기

2.1 pom.xml 수정

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.webproj</groupId>
    <artifactId>springBoard</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--spring-test 추가-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.22</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.22</version>
        </dependency>
        <!--lombok과 log4j 추가-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>


    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <org.springframework-version>5.3.22.RELEASE</org.springframework-version>
    </properties>


</project>

2.2 클래스 추가

package com.example.springboard.sample;

import lombok.Data;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component      // 스프링에게 해당 클래스가 스프링에서 관리해야할 대상임을 표시
@Data           // Lombok의 setter를 생성하는 기능, 생성자, toString() 등 자동으로 생성하도록 한다.
public class Restaurant {
    // 자동으로 setChef()를 컴파일 시 생성
    @Setter(onMethod_ = @Autowired)  // setChef()에 @Autowired 어노테이션 추가
    private Chef chef;
}
package com.example.springboard.sample;

import lombok.Data;
import org.springframework.stereotype.Component;

@Component
@Data
public class Chef {
}

위 코드는 아래와 같은 구조를 가진다.

2.3 스프링 동작 과정

  1. 스프링 프레임워크 시작 시 스프링이 사용하는 메모리 영역인 Context가 생성된다. 이 객체를 ApplicationContext라고 한다.

  2. 스프링이 생성하고 관리해야하는 객체들에 대한 설정 파일인 root-context.xml 파일을 읽는다.

  3. root-context.xml에 설정되어 있는 <context:component-scan> 태그의 내용 읽고 해당되는 패키지를 스캔한다.

  4. 해당 패키지의 클래스 중 @Component 어노테이션이 존재하는 클래스의 인스턴스 생성

  5. Restaurant 객체는 Chef 객체가 필요하다고 알리는 @Autowired 설정이 존재하기에 스프링은 Chef 객체의 레퍼런스를 Restaurant에 주입

2.4 테스트 코드로 확인하기

spring-test 모듈을 사용한다.

  1. root-context.xml에 내용추가
<context:component-scan base-package="com.example.springboard.sample">
</context:component-scan>
  1. resource 디렉터리 아래에 log4j.xml 파일 생성 후 설정 추가
<?mappers version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
<log4j:configuration>

    <!-- Appenders -->
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p: %c - %m%n" />
        </layout>
    </appender>

    <!-- Application Loggers -->
    <logger name="Controller">
        <level value="info" />
    </logger>

    <!-- 3rdparty Loggers -->
    <logger name="org.springframework.core">
        <level value="info" />
    </logger>

    <logger name="org.springframework.beans">
        <level value="info" />
    </logger>

    <logger name="org.springframework.context">
        <level value="info" />
    </logger>

    <logger name="org.springframework.web">
        <level value="info" />
    </logger>

    <!-- Root Logger -->
    <root>
        <priority value="info" />
        <appender-ref ref="console" />
    </root>

</log4j:configuration>
  1. /test/java/ 에 파일 추가

package com.example.springboard.sample;

import lombok.Setter;
import lombok.extern.log4j.Log4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class SampleTests {
    @Setter(onMethod_ = {@Autowired})
    private Restaurant restaurant;

    @Test
    public void testExist(){
        assertNotNull(restaurant);

        log.info(restaurant);
        log.info("------------");
        log.info(restaurant.getChef());

    }
}
  • @RunWith(SpringJUnit4ClassRunner.class)
    현재 테스트 코드가 스프링을 실행하는 역할을 하는 것을 표시

  • @ContextConfiguration
    지정된 클래스나 문자열을 이용하여 필요한 객체를 스프링 내의 객체로 등록한다

  • @Log4j
    Lombok을 이용하여 로그를 기록하는 Logger를 변수로 생성

  • @Test
    테스트 대상 표시, 해당 메서드를 선택하고 JUnit Test 기능 실행

  • assertNotNull(restaurant);
    대상 변수가 null이 아니어야만 테스트가 성공한다.

이를 실행하면 아래와 같은 결과가 나온다.

2.4.1 결과 해석

  1. new 키워드를 사용하지 않았음에도 객체가 생성되었다.
    → 스프링은 객체를 생성하고 관리하는 일종의 컨테이너팩토리의 기능

  2. Restaurant 클래스의 @Data 어노테이션으로 Lombok을 이용하여 여러 메서드가 생성된다
    → getter / setter 등 자동 생성

  3. Restaurant 객체의 Chef 인스턴스 변수에 객체가 주입되어 있다.
    → @Autowired를 이용하여 객체간의 관계 자동 관리

profile
학생 점심을 좀 차리시길 바랍니다

0개의 댓글