해당 포스팅의 목차는 다음과 같다.
1. 설치 및 초기설정
2. Spring Framwork란
3. 결합도와 스프링 프레임워크
4. Bean 속성
5. Dependency Injection(의존성 주입)
1. 설치 및 초기설정
1) Spring 설치
아래의 경로로 간다.
위에서 두번째로 보이는 tool을 설치한다. (boot는 나중에 사용 예정)
이때 설치를 진행하면서 보이는 모든 선택목록은 전부 선택하며, 모든 동의 여부는 동의함을 선택하여 설치를 마친다.
아래와 같이 두 사진을 모두 프로그램에서 확인할 수 있다면 정상설치, 하나라도 확인이 되지 않는다면 정상설치 되지 않은 것이다.
2) 초기설정
* Spring에서 모든 작업은 하단 바의 로딩 설정이 100%로 진행이 되어야만 적용이 된다. *
* 만일 로딩 완료 전 다른 정보를 기입하거나 한다면 충돌이 발생하여 이클립스를 재설치해야하는 상황이 올 가능성도 있다. *
* 작업시 하단의 로딩바를 주의깊게 살펴야할 필요가 있다. *
Spring Legacy Project를 생성하고, MVC템플릿을 선택한다.
누가 어떤 작업을 할것인지를 기재하는 란이므로 채워넣는다.
프로젝트 우클릭-프로퍼티스-project Facets의 java의 version을 현재 설치된 버전에 맞게 설정한다.(로딩에 주의)-apply
프로젝트 우클릭-프로퍼티스-project Facets의 java의 Runtime에 서버를 선택해준다. (로딩에 주의)-apply
* 불필요한 목록은 제거한다. *
resources폴더에 log4.xml만 남을 수 있도록 아래의 폴더는 삭제한다.
web.xml파일에서 아래 사진과 같이 드래그 된 부분의 내용을 삭제한다.
WEB-INF하단에 있는 spring폴더와 views폴더는 사용하지 않을 예정이므로 삭제한다.
pom.xml파일에서 java-version(현재 사용중인 자바 버전 : 11)과 springframwork-version(4.2.4)로 수정한다.
수정 완료시 아래와 같이 폴더 하위의 jar파일이 지정 버전으로 적용된다면 설정 성공이다.
2. Spring Framwork란
Spring framwork를 통해 재사용성이 향상된 어플리케이션을 개발할 수 있게 된다. 즉, jsp때보다 더 빠르고 정확하게 개발이 가능해진다.
프레임워크 : 개발의 뼈대, 틀을 제공하는 것이다.
스프링 프레임워크 : 디스패처, mvc 템플릿, 인코딩, 리스너 설정 등 기본적인 개발 틀을 제공하는 프레임워크이므로, 사용자의 기술이 부족하더라도 상향 평준화를 시킬 수 있게 된다.
1) why?
ex) 리모컨
A가 작업하던 리모컨은 음량이 10씩 증가, B가 작업하던 리모컨은 음량이 1씩 증가한다.
당장은 문제가 없으나 B리모컨 AS를 부탁했을때 B가 퇴사하거나 휴가중이라면 ?
A가 대신 수정을 하게 된다면 미세한 컨트롤이 가능하던 리모컨이 10씩 증가하게 될것이다.
->소비자 입장에서 회사에 대한 신뢰도를 감소시키는 일이 됨
ex) 사장
A가 너무 잘해서 팀장으로 승진하게 되었을때, 팀원으로 있는 BCD의 실력을 A팀장이 믿지 못하게 된다.
그래서 A팀장이 "쟤네 맡길바엔 내가 다 할래!"를 시전하게 될텐데, 연봉협상 테이블에서 사장님 입장에선 A가 더 싫을 수 밖에 없다.
개발자의 실력을 상향 평준화 해야하는 사장님의 목표에 어긋나기 때문에 차라리 위의 상황을 발생시키기 보다 "너희들 이렇게 이렇게 일 해!"하고 틀(메뉴얼)을 제공해서 시키는게 더 낫게 된다.
스프링 프레임워크를 사용함으로 관리가 용이하고, 개발 시간이 단축되며, 개발자들의 역량이 획일화 되고, 재사용성이 증가하게 된다.
2) what?
스프링프레임워크 한 줄 정리 "IoC와 AOP를 지원하는 경량(포조를 다루는)의 프레임 워크"
좋은 개발자가 지켜야하는 규칙 "낮은 결합도와 높은 응집도를 갖는, 유지보수에 용이한 코드"
① IoC (Inversion of Control)
제어의 역행을 나타낸다. 객체 생성 및 관리하는 게 컨테이너이며, 이게 IoC의 핵심이다. (기존에는 개발자가 했었으나 이제는 컨테이너가 하므로 제어의 역행이라고 표현한다.)
- 서블릿 컨테이너는 doGet(), doPost()메서드를 수행하는 객체
- 스프링 컨테이너는 POJO를 대상으로 한다. (new:초기화)를 대신 해준다!
- 기존에 jsp에서는 Jsp:useBean으로 dao와 vo를 자동으로 new해줬었다.
- FC개념 도입으로 java에서 작업했을때는 하나씩 우리가 직접 했고! 근데, 이제 다시 스프링 컨테이너로 인해 자동화 된다!
객체 사이의 관계를 스프링 컨테이너가 대신 생성 및 관리 해줄테니 결합도가 낮아질 것 - 즉, 유지보수에 용이해진다.
② AOP(Aspect Oriented Programming)
관점지향 프로그래밍,이라는 의미로 <-> oop(객체지향)의 반대 개념이라고 할 수 있다.
1) 객체지향 프로그래밍
만들다보면 어쩔 수 없이 반복되는 행동이 생길 수 밖에 없다. Ex) 메서드 수행(핵심관심)마다 conn 작동, pstmt 준비, 기능, conn해제를 반복하게 되는데, 그래서 JDBCUtil클래스를 만들었다. 코드는 확실히 유지보수에 용이하게 구성된다. 그렇지만 어쨌든 계속해서 순서를 지켜야 했기 때문에 주어(객체)를 불러내야만 했다.
2) 관점지향 프로그래밍
기능을 하나의 클래스에 정의하는 것이다. 해당 클래스를 불러와서 기능을 수행하게 하는 기법(마치 JDBCUtil처럼), 때 되면 알아서 동작할 수 있도록한다. *때 되면 알아서!* JDBCUtil.connect();이런거 안해도 된다는 의미가 된다. 이때 "때"를 설정 정보로 알려준다. 그럼 객체를 알아서 관리해주는 역할을 해준다. 공통관심(공통로직, 횡단관심)에 대해 설정을 통해 자동으로 처리를 할 수 있다.
로직들을 전부 분리해서 저장할 수 있게 해주기 때문에 응집도가 높아질 것 - 즉, 유지보수에 용이해진다.
3. 결합도와 스프링 프레임워크
다른 회사의 TV를 사용자가 사용한다고 했을때를 가정하고 실습을 진행하였다.
1) 결합도가 낮은 코드
동시 작업이 아닐 것이기 때문에 메서드명이 다를 수 있다. 이때 사용자가 다른 티비로 이관하게 된다면 메서드명까지 전부 수정해야하는 상황이 발생하게 되는데, 이런 코드를 결합도가 낮다고 표현한다. (클래스 객체의 코드 내용 생략)
LgTV tv=new LgTV();
tv.powerOn();
tv.volumeUp();
tv.powerOff();
SamsungTV tv=new SamsungTV();
tv.turnOn();
tv.soundDown();
tv.turnOff();
2) 결합도가 높은 코드_interface(다형성)
위의 코드에서 결합도를 높이기 위한 방법으로 interface를 사용해볼 수 있다. (클래스 객체와 인터페이스의 코드 내용 생략)
이때 초기화시, 사용할 객체에 대해서만 수정을 진행하면 이전의 코드보다 유지보수가 용이해진다.
TV tv=new LgTV();
tv.powerOn;
tv.volumeUp;
tv.powerOff;
3) Spring Framwork의 방식_Factory패턴(디자인패턴)
디자인 패턴이란 객체 생성을 캡슐화 하여 결합을 약하게 만드는 방식이다.
① BeanFactory.class
메서드에 사용할 bean이름을 인자로 두면, 해당 bean에 맞는 로직을 수행한다.
package test;
public class BeanFactory {
// Factory 패턴 : 객체 생성을 캡슐화 하여 결합을 약하게 만듬
// 객체 생성 로직을 캡슐화 할 메서드
// 이게 바로 설정 정보다!
public Object getBean(String beanName) {
if(beanName.equals("lg")) {
return new LgTV();
}else if(beanName.equals("samsung")) {
return new SamsungTV();
}else {
return null;
}
}
}
② Client.class
BeanFactory factory=new BeanFactory();
TV tv= (TV)factory.getBean(args[0]);// 다운캐스팅 필요
tv.powerOn();
tv.volumeUp();
tv.powerOff();
//★new 라는 코드가 캡슐화 되었기 때문에 개발자가 객체 생성을 직접하지 않고 컨테이너가 함★
구동시 아규먼트를 직접 기입하는 방식으로 결과를 다르게 볼 수 있다.
run-run congifurations-arguments에서 드래그 되어있는 부분의 내용을 설정한대로 lg, 혹은 samsung으로 작성 후 컴파일하게 되면 원하는 결과를 확인할 수 있다.
4) Spring Framwork의 사용
디자인 패턴의 기본 구동 순서는 다음과 같다.
1) 어노테이션이나 .xml의 "설정파일"을 로드
2) 브라우저에서 url로 요청 ! , 요청처리 시작
3) .do요청일시 서블릿 객체 없으면 생성 or 이미 생성된 객체 재사용(싱글톤 패턴의 언급) -> doGet()호출
* 이게 제어의 역행 부분 *
4) 호출 후 실행 결과를 사용자에게 전달
① 설정정보 기재_xml파일 생성
생성해야할 파일의 이름은 아래 사진에서 확인이 가능하다.
생성해야할 위치또한 아래의 사진과 같다.
bean태그로 구동시 생성할 객체를 지정할 수 있는데 이때 class와 id속성을 활용한다. 두 속성은 필수 속성이라고 알고 있어야한다.
② 코드 작성
주석을 통해 내용을 이해할 수 있다.
//0. Spring 컨테이너를 실행시킬때 필요한 설정정보 파일(xml)을 생성했기 때문에 1번가능
//1. Spring 컨테이너를 실행시킴(아래 객체는 활용도가 낮으므로 암기할 필요까지는 없음)
AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
//2. 스프링 컨테이너에게 객체 요청 : Lookup한다고 표현 -> 컨테이너 실행되면 일단 객체 생성
TV tv=(TV)factory.getBean("tv"); //이거 안해도 설정파일에서 미리 만들어둬버린다! 그러니 사용하지 않는 bean은 미리 만들지말자
tv.powerOn();
tv.volumeUp();
tv.powerOff();
//3. 컨테이너 연결 해제
factory.close();
4. Bean 속성_xml파일
1) init-method, destroy-method
객체의 멤버변수를 초기화하는 메서드를 참조할 수 있다. / 객체 메모리를 해제하는 메서드를 참조할 수 있다.
samsungTV의 객체를 생성하게 되면서 아래의 메서드를 통해 초기화 및 해제 작업을 진행할 예정이라면,
public void initMethod() {
System.out.println("객체의 멤버변수들 초기화 작업");
// 초기화 : 초기값 생성
// 생성자, setter가 원래 하던 행동
}
public void destoryMethod(){
System.out.println("객체 메모리 해제 작업");
}
아래의 코드와 같이 init메서드와 destroy메서드를 각각 지정할 수 있다.
<bean class="test.SamsungTV" id="tv" init-method="initMethod" destroy-method="destoryMethod"/>
2) lazy-init
지연로딩 방식을 활성화할 수 있다.
Lookup작업을 하지 않아도, 컨테이너가 실행되면 즉시 객체가 생성되게 되는데 이런 방식을 pre-loading(즉시로딩)방식이라고 한다. 이때, lazy-init속성의 설정을 통해서 객체를 요청했을때만 해당 객체를 생성하는 것이 가능해진다.
<bean class="test.SamsungTV" id="tv" lazy-init="true"/><!-- 지연로딩방식 활성화! 즉시로딩을 못하게 함 -->
3) scope
해당 객체를 참조하여 여러개의 객체를 생성할 수 있게 된다.
기존 코드에서 Lookup작업에서 아래와 같이 하더라도 디폴트가 싱글톤패턴이기 때문에 단 하나의 객체만이 생성되게 된다.
TV tv1=(TV)factory.getBean("tv");
TV tv2=(TV)factory.getBean("tv");
TV tv3=(TV)factory.getBean("tv");
이때 아래와 같이 scope속성을 활용하여 여러개의 객체를 생성할 수 있다.
<bean class="test.SamsungTV" id="tv" scope="prototype"/>
5. Dependency Injection(의존성 주입)
IoC를 지원하는 컨테이너에게 객체 생성권을 줄 수 있으니, 이를 이용하여 DI를 할 수 있다.
객체들을 생성하여 작업하다 보면 "의존관계 : Dependency"가 발생한다. 이런 것을 현명하게 잘 풀어나가는 것이 관건이다.
(Ex. 티비/리모컨 , 핸드폰/워치 , 캐릭터/무기) 의존관계를 잘못 주게 되면 리모컨이 있어도 티비 작동을 못해 볼륨 조절하는 기능을 사용하지 못한다는 등의 다양한 에러상황이 발생할 수도 있다.
Dependency Injection(DI:의존성 주입)이 IoC의 핵심이며, 해당 개념으로 내용을 잘 풀어갈 수 있다.
아래와 같이 LgTV의 생성자를 통해 의존관계에 있는 객체(remote)를 주입할 수 있다.
private Remote remote;
private int tvid;
public LgTV() {
System.out.println("LG티비 객체 생성");
}
//TV살때부터 리모컨과 연결(초기화)
// 생성자를 통해 의존관계에 있는 객체를 주입하고 있다. -> 생성자주입, 생성자 인젝션
public LgTV(Remote remote) {
System.out.println("lg티비 객체생성 2");
this.remote=remote;
}
public LgTV(Remote remote, int tvid) {
System.out.println("lg티비 객체생성 3");
this.remote=remote;
this.tvid=tvid;
}
xml파일에서, constructor-arg태그의 ref속성을 통해 주입할 객체를 전달 받을 수 있으며, 이때 주입될 객체는 bean태그를 활용하여 생성이 되어야한다. 만일 객체가 아니라 단순한 값을 초기값을 설정하고 싶다면 value속성을 이용할 수 있다.
*리모트 객체생성이 우선진행되며, 후에 티비 객체 생성됨. 이후 정상작동*
<?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">
<!-- 초기화 작업! new! id는 필수 속성이 아니지만 없으면 참조를 못함 -->
<!-- 컨테이너가 실행되면 즉시 객체 생성됨 == pre-loading(즉시로딩)방식 -->
<bean class="test.LgTV" id="tv">
<constructor-arg ref="remote"/>
<constructor-arg value="1001"/><!-- 객체가 아닌 초기값들은 value로 전달 -->
</bean>
<!-- 이 객체가 위로 전달됨 -->
<bean class="test.RemoteB" id="remote"/>
</beans>
참조할 객체 두개를 놓고 자율적으로 변동하고 싶다면 아래의 코드처럼도 이용해볼 수 있다.
<?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">
<!-- 초기화 작업! new! id는 필수 속성이 아니지만 없으면 참조를 못함 -->
<!-- 컨테이너가 실행되면 즉시 객체 생성됨 == pre-loading(즉시로딩)방식 -->
<bean class="test.LgTV" id="tv">
<constructor-arg ref="ra"/> <!-- 이 부분만 변경해서 사용 가능 -->
<constructor-arg value="1001"/><!-- 객체가 아닌 초기값들은 value로 전달 -->
</bean>
<!-- 이 객체가 위로 전달됨 -->
<bean class="test.RemoteB" id="ra" lazy-init="true"/><!-- 사용할때만 생성됨 -->
<bean class="test.RemoteB" id="rb" lazy-init="true"/>
</beans>
'Spring' 카테고리의 다른 글
[IoC] XML파일 @로 바꾸기 : Controller_2 (0) | 2022.04.01 |
---|---|
[IoC] MVC패턴 이해 실습_2 : Spring제공 클래스 사용 (0) | 2022.03.31 |
[IoC] MVC패턴 이해 실습_1 (0) | 2022.03.30 |
[IoC] 스프링, DB연동_service (0) | 2022.03.29 |
[IoC] 의존성 주입과 어노테이션 (0) | 2022.03.29 |