newlec Spring

1. 스프링 소개와 학습안내

스프링을 이용하지 않고 웹개발하는 일이 거의 없다. 그래서 필수로 사용해야한다.
스프링이 무엇이고 그런건지 알아보도록 하자.

스프링 프레임워크는 언젠가 갑자기 확 들어오게 되었다.
스프링에는 굉장히 많은 것들이 프로젝트화되어 있다.
처음 다가왓을때는 그냥 스프링 프레임워크만 잇엇다.

스프링이 기본적으로 DI(객체주입) 트랜젝션 관리 등 dao 알아서 해주게 되면서 필요성이 높아졌다.

물론 이것을 위한 java editon이 있다. java ee가 이것을 지원했느데 사용방법이 복잡했었다.
스프링은 단순히 라이브러리로 깔끔한 처리가 가능하게 되었다.
그래서 java ee를 잠식하고 스프링과 java se를 활용해서 만들게 되었다.

우리는 java se를 사용하며 ee를 스프링으로 바꾸어서 사용중인 거엿다.
java ee가 유료화되고 스프링의 기능이 많이 생겼지만 관심이 거의 없어졌다.

웹 MVC 트랜잭션 인증과 권한 등등을 쉽게 사용할수 있게 바뀌었다.
MVC - DI - 느슨한 결합력과 인터페이스
트랜잭션 -AOP
인증과권한 Servlet Filter
이 과정을 이해할 필요가 있다.

스프링 => 분산형 기업형 응용프로그램 개발을 위한 API 결합력을 낮추는 DI, DB Transaction 처리, 로그처리 등등
java se => 일반적인 로컬 응용프로그램 개발을 위한 API 파일I/O 콘솔I/O 윈도우 I/O 네트워크 I/O Thread

2. 느슨한 결합력과 인터페이스

프로그램을 만들때 결합력과 인터페이스에 대해서 배워보자.

웹 프로그램은 사용자 가 원하는 서비스 레이어와
자바로만 db를 받는 DAO가 있다.

사용자 요청 -> 서비스 -> DAO -> DB로 이어진다.
프로그램이라는 것은 항상 수정이라는게 이루어지는 것이다.
만약 B1을 수정해야할때 1.B1 코드수정 2. B2라는 코드추가하는 방법(덮어쓰기)이 있다.
2를 하면 서비스도 수정을 하는 것이 필요해진다.

수정에 대한 범위가 더 늘어나게 된 것이다.
또한 수정을 하려면 소스코드가 잇어야한다. 그런데 소스코드를 구해서 재배포하는 것은 위험한것이다.
이런경우를 결합력이 높은 것이라고 한다.

B라는 인터페이스를 만들면 된다.
이 인터페이스는 기능에만 준해서만 사용하는 것이다.
내부적인 B1 B2로 나뉘더라도 결합하는 객체에 따라서 다른 프로그램이 되는 것이다.

그럼 B와 B2를 결합 하는 작업을 누가하느냐? UI에서 하게되는것이다.
객체 생성과 조립을 위해 외부 파일 XML과 Annotation으로 하게 된다.

스프링은 이런 객체 조립방법과 조립도구를 제공하고 있다.

3. DI(Dependency Injection)

스프링의 가장 기본적인 기능은 객체를 생성해주고 객체를 조립해주는 것이다.
여기서 사용되는 것이 DI와 IoC Container이다.

먼저 DI에 대해서 알아보고자 한다.
DI는 종속성 주입이라고 번역되는데 부품 조립이라고 보면 쉽다.

두가지가 있다.

class A    {
    private B b;

    public A() {
        b=new B();
    }    
}

A가 B를 생성해서 가진다. 이것을 일체형 Compostion has a 관계라고 한다.
이관계를 Dependency라고 한다. 그냥 부품이라고 보면 된다.
이 부품을 사용할때는 A객체로 직접 생성해서 사용해야한다.

class A {
    private B b;
    public A() {
    }
    public void setB(B b){
        this.b = b;
    }
}

직접생성하지않고 외부에서 생성해서하는 Association has a 조립형 관계이다.

스프링에서 DI가 왜 중요한지 스프링이 왜 이것때문에 중요해졌는지를 알 필요가 있다.

프로그램을 만들때 일체형보다는 조립형이 결합력이 낮아지고 부품을 쉽게 갈아끼울 수 있게 해준다.
업데이트를 하게 된다면 조립형이 좋다.

일체형은 A a = new A(); 얘만 만들어쓰고 그밑에 부품이 뭐가 있는지 모르고 바꿔낄수가 없다.

조립형은 A라는 객체를 만들때 부품을 따로 만들어서 이것을 꽃아줘야한다.
A a = new A(); B b = new B();-> Dependency a.setB(b);
A입장에선 B가 부품이고 이것을 우리가 꽃아줘야한다.
그래서 이 과정을 주입 Injection이라고 한다. 이 부품을 Dependency라고 한다.
그래서 Dependency Injection DI라고 한다.

장점은 부품을 쉽게 바꿀수잇고 단점은 부품을 조립해야한다는 것이다.

조립은 Setter Injection / Construction Injection(A a = new A(b))이 있다.
Setter로 조립하거나 생성자로 조립하는 것이다.

조립하는게 불편하면 조립하는 서비스를 받는 것이다. 이것을 조립해주는게 스프링이다.
우리는 조립된 결과물만 가져다 쓰는 것이다. 스프링의 DI는 부품을 조립해준다.

4. IoC(Inversion Of Control) 컨테이너

조립하는데 부품을 담아 놓을 컨테이너가 필요하다. 이 컨테이너를 IoC 컨테이너라고 한다.
우리는 여러 부품들을 생성해서 스프링에게 주문서로 제공을 해줘야한다.

외부 설정 파일인 XML/ Annotation으로 이 주문서를 작성한다.

주문서대로 부품을 구매해서 박스에 담는다.
스프링도 DI 부품을 조립하는데 주문을 하고 이 내용들을 객체로 생성하고 담는데 이것을 컨테이너 라고 한다.
이 컨테이너를 부품 컨테이너 Dependency 컨테이너라고 할 수 있다.
그런데 굳이 IoC 컨테이너라고 하는데 강조하고 싶은 내용이 있기때문이다.

부품들을 조립해서 생성까지 해줘서 담아준다. 작은부품 - 큰부품 -더큰부품 의 순서대로 조립된다.
심지어는 더 큰 부품에 조립도 된다.
부품조립이라 생각하면 이 순서가 맞다.

그런데 일체형이라고 생각하면 A->B>C->D로 만들어진다.

결합형은 반대로 생성이 된다. 이것이 Inversion of Contorl(역순)이라는 뜻이다.
이 부품들이 결합도 되니 IoC 컨테이너라고 한다.

5. Dependency를 직접 Injection하기

부품조립작업을 맨땅에서 해보자.
Exam 인터페이스 NewlecExam();구현 객체의 형태로 만들어보자.

public interface Exam {
    int total();
    float avg();
}

public class NewlecExam implements Exam {
    private int kor;
    private int eng;
    private int math;
    private int com;

    @Override
    public int total() {
        return kor + eng + math + com;
    }

    @Override
    public float avg() {
        return total() / 4.0f;
    }
}

프로그램을 만드는데 출력하는 객체를 InlineExamConsole, GridExamConsole 두개 만든다.

public interface ExamConsole {
    void print();
}

public class GridExamConsole implements ExamConsole {
    private Exam exam;

    public GridExamConsole() {
    }

    public GridExamConsole(Exam exam) {
        this.exam = exam;
    }

    @Override
    public void print() {
        System.out.println("┌──────────┬──────────┐");
        System.out.println("│   total  │    avg   │");
        System.out.println("├──────────┼──────────┤");
        System.out.printf("│   %3d    │   %3.2f   │\n", exam.total(), exam.avg());
        System.out.println("└──────────┴──────────┘");
    }
}

public class InlineExamConsole implements ExamConsole {
    private Exam exam;

    public InlineExamConsole() {
    }

    public InlineExamConsole(Exam exam) {
        this.exam = exam;
    }

    @Override
    public void print() {
        System.out.printf("total is %d, avg is %f", exam.total(), exam.avg());
    }
}

마지막으로 출력하는 프로그램을 짜는데 ExamConsole에 들어오는 객체에 따라서 다르게 출력된다.

public class Program {
    public static void main(String[] args) {
        Exam exam = new NewlecExam();
        //ExamConsole console = new InlineExamConsole(exam); //DI
        ExamConsole console = new GridExamConsole(exam); //DI
        console.print();
    }
}

이 InlineExamConsole와 GridExamConsole을 바꿔서 꽃는 작업을 DI라고 하는데
이 과정을 외부 파일을 통해서 꽃는 것을 스프링이 하는 것이다.
소스코드를 변경하지 않고도 꽃아 넣는 것이 스프링이 DI를 하는 것이다.
부품을 바꾸든 뭘하든 소스코드를 수정하지 않아도 되는 것이다.

6. 스프링 DI 설정을 위해 이클립스 플러그인 설치하기

지시사항을 해놓고 주문을 해야한다. 주문을 하는 대상이 스프링이다.
이 주문서가 바로 XML 혹은 어노테이션이다.
이 설정을 직접 만들 수도 있지만 잘 정리된 프레임워크를 쓰는 것도 이점이다.

최근에는 스프링 부트가 있다.
스프링부트는 이 앞의시작부분을 편하게 해줄뿐이고 스프링과 다를 게 없다.
스래서 스프링 부트가 편하게 해주지만 스프링을 배워야 이해가 쉽다.
스프링 부트만 배우면 스프링 자체에 대한 이해도가 떨어지게 된다.

우리는 제멋대로 만드는 것이아니라 스프링이 이해하고 잇는 지시서 양식에 따라 해줘야한다.
지시서를 예제 사이트에 들어가면 있었다. 요즘에는 이 레퍼런스가 잘 없어서 플러그인의 도움을 받아야한다.

상단메뉴에 Help - Eclipse marketplace가면 이클립스에서 사용할 수 있는 플러그인을 검색해서 다운받을 수 있다.
4.0은 스프링부트 기반이고 이 수업에선 스프링 3.0 을 다운받아 사용해야한다.

스프링부트는 자바 config를 기반으로 하기 때문에 Spring Bean Configuration File를 지원하지 않는다.

7. 스프링 DI 지시서 작성하기(Spring Bean Configuration)

스프링이 우리에게 어떤 도움을 주는지를 알아보자.
Exam과 Console객체가 서로 결합되서 사용되는 프로그램을 만들었다.

일반적으로는 이렇게 생성자로 결합하는게 아니라 setter로 결합을 한다.
이전에 생성자로 결합을 했다면 이번에는 setter로 결합을 해보자.

@Override
public void setExam(Exam exam) {
    this.exam = exam;
}

이렇게 하면 injection이 setter를 사용하는 것이나 생성자를 사용하는 두가지 방법 모두 가능해졌다.
만약 Exam이라는 객체(NewlecExam)가 바뀌거나 콘솔객체( GridExamConsole)바뀐다면 이 결합관계도 바꿔야하니 코드들을 다 바꿔야한다.

ExamConsole console = ?;을 설정으로 빼서 해줘야하는 것이 있는데 그것이 스프링이다.
이 기능을 이용해서 둘 사이의 관계를 분리하는 것이다.

setting.xml에 작성해줘야한다.
지시서이기 때문에 데이터 기반으로 작성해줘야한다.
스프링은 Bean라는 태그를 통해서 지시한다.

어떤 클래스를 객체화할것인지?=class 객체를 어떤이름으로쓸것인지?=id로 매핑해준다.
같은 이름으로 클래스가 있을수잇으니 패키지명까지 반드시 작성해줘야한다.

console.setExam(exam); 햇듯이 GridExamConsole에 exam을 넣어줘야한다.

jsp에서 useBean햇던거와 비슷한 모양이라고 할 수 있다.
setExam이라는 함수를 호출하는 것인데 property를 넣는 것이라고 보면된다.
name="setExam" -> name="exam" value와 ref는 넣을 객체 이름(id)를 넣는다.
넣는 객체가 밸류타입이면 value에 레퍼런스타입이면 ref에 넣는다.
"spring.di.entity.NewlecExam"이기때문에 ref형식으로 넣어줘야한다.
property에 값을 넣는 부분이 injection이다.

속성을 사용하는게아니라 setter함수를 사용하는 것이니
꼭 setter함수를 만들어줘야한다. 속성을 사용하는게아니다.
이 지시사항을 가지고 스프링에게 지시서를 넘기고 만들어 달라고 해야한다.
지시사항을 ApplicationContext를 통해서 전달해야하는데 이것은 다음 강의에서 부터 알아보자.

8. 스프링 IoC 컨테이너 사용하기(ApplicationContext 이용하기)

지시서를 읽어서 구체적으로 만들어주는것이 스프링읙 구체적인 객체가 ApplicationContext 객체이다.
ApplicationContext context = new ClassPathXmlApplicationContext("spring/di/setting.xml")ting.xml")
ApplicationContext는 인터페이스고 인터페이스 = 구현객체이다.

이 구현객체는 매우 다양하다.

이름이 조금씩 다른데 구체화된 이름이다. 지시서를 어떻게 주는지를 알려주는 대에 대한 것이다.
class(xml) 어플리키이션 루트에 둿다면 ClassPathXmlApplicationContext
c드라이브의 어딘가에있는 File이라면 FileSystemXmlApplicationContext
웹에있다면 XmlWebApplicationContext 웹의 url을 기준으로 제공한다.
어노테이션을 사용한다면 Annotaitonconfig 어노테이션으로 지시사항을 넘길때 사용한다.

프로젝트에 스프링이 없어서 빨간줄이 나온다. 메이븐프로젝트로 바꿔주자.
프로젝트 우클릭 - configure - convert to maven
pom.xml에 depencency를 추가해줘야한다.

<dependencies>
      <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.7</version>
    </dependency>
</dependencies>

지시한 지시서를 읽어서 가져와 보자
getBean 메소드로 가져온다.
1.이름으로찾기
ExamConsole console = (ExamConsole) context.getBean("console");
이름으로 꺼내면 object로 나오기때문에 형변환을 해줘야한다.

2.examconsole의 클래스로 가져오기 자료형으로 꺼내기
ExamConsole console = context.getBean(ExamConsole.class);

외부설정에 대한 권한을 가지고 프로그램을 바꿀수 있게 된것이다.
클래스가 겹칠경우 오류가 날수있는데 이것은 나중에 처리하는 방법이 따로있으니 괜찮다.
2번째가 타입변환을 하지 않아도되서 자주 사용된다.
지시서를 inline~으로 바꾸면? 그것이 실행된다.
지시서만 바꿔도 실행되는 내용이 바뀌는 것을 알 수 있다.
일어나는 변화를 지시서만 바꾸면된다.

<?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">

    <!-- Exam exam = new NewlecExam(); -->
    <bean id="exam" class="spring.di.entity.NewlecExam" />

    <bean id="console" class="spring.di.ui.GridExamConsole">
        <property name="exam" ref="exam"/>    <!-- console.setExam(exam); -->
    </bean>
</beans>

public class Program {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring/di/setting.xml");
        //ExamConsole console = (ExamConsole) context.getBean("console");
        ExamConsole console = context.getBean(ExamConsole.class);

        console.print();
    }
}

'기초단계 > SPRING' 카테고리의 다른 글

2023.04.16 Spring  (0) 2023.04.17
2023.04.14 Spring  (0) 2023.04.17
2023.01.25-1 Spring  (0) 2023.01.25
2023.01.24-1 Spring  (0) 2023.01.24
2023.01.22 Spring  (0) 2023.01.22

+ Recent posts