열심히 끝까지

디바이스 융합 자바(Java) day64(2) - Spring (IoC[제어의 역행], AOP[관점지향 프로그래밍]) 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(수업내용)

디바이스 융합 자바(Java) day64(2) - Spring (IoC[제어의 역행], AOP[관점지향 프로그래밍])

노유림 2022. 9. 13. 17:34

[ 프레임워크 ]
개발을 어떻게 해야하는지 아웃라인을 제공
   > Spring 프레임워크
         a) 프레임워크를 사용하기 때문에 개발시간 단축
         b) 관리가 용이 == 유지보수 용이
         c) ★ 개발자들의 실력이 상향 평준화
         d) "IoC와 AOP를 지원하는 경량의 프레임워크"
                  IoC 제어의 역행 -> 낮은 결합도
                  AOP 관점지향 프로그래밍 -> 높은 응집도
                  경량 -> 원래는 .jsp .servlet

 

[ IoC - 제어의 역행 ]
   Inversion of Control
설명 -> ㅁㅁㅁㅁㅁㅁㅁㅁ -> 설명
insert.do 요청 -> new InsertAction() (=> FC에서 작성됨)
                        new InsertAction(req, res);
                       >> 유지보수 불리...
                       >> 이 문제를 container에게 맡김
   >> 컨테이너에게 객체화를 담당시키자!
        -> 자바 코드로 new 하는 것이 아니라, 컨테이너가 객체화 처리
        -> 소스 코드에 new가 없음 -> 결합도가 낮아짐 -> 유지보수 용이
                     소스코드에 new 가 있다 == 의존관계를 명시
>> new가 없어야 함!

1) web.xml 은 서블릿 컨테이너에게 설정을 알려주는 파일
2) 무슨 설정? 만들어야할 서블릿에 관련된 설정
             뭘 만들까? 언제 호출할까?
3) new를 작성하지 않음! 근데 객체화가 되었다!!!!
             => 서블릿 컨테이너가 했다!!!!
4) 기본 생성자 필요
5) .xml --->> @
6) 스프링 프레임워크가 @을 적극 사용하는 프레임워크 임

동작순서
web.xml이 로딩 
-> /test.do 요청 
-> a.Test 클래스를 객체화, doGet()메서드 호출(서블릿 컨테이너)
-> 브라우저(사용자, client)에 실행 결과 출력됨


결합도가 높은 코드의 결합도를 낮춰보자!
1) 인터페이스
       객체지향 - 다형성을 사용
       "설계"
2) 디자인 패턴 : 팩토리(Factory) 패턴 - 사용하는 것이 Spring
       "Client에서 직접적으로 new 소스코드 xxx"
       Factory의 역할
             : 요청에 맞는 객체를 반환해줌

>> run > run configurations > java Application > Arguments에서 program argument 바꾸어서 실행도 가능

- IoC와 관련된 설정을 알려준다고 가정
      >> .xml 파일 만들기
          > src/main/resource에 제작
          > IoC와 관련된 설정을 applicationContext.xml로 작성
              -> 스프링 설정 파일

<bean id="phone" class="test.IPhone" />
== test.IPhone phone = new test.IPhone();

 

- 동작 순서
   1) 클라이언트가 컨테이너를 로딩(9번 라인)
   2) 이 때, 스프링 설정 파일을 참고하여 로드
   3) 스프링설정파일의 <bean>을 보고 객체화
              == 즉시 로딩(pre-loading) 방식
   4) "phone" 객체 요청 == Lookup 행위 진행
   5) 요청한 객체 반환
   >> 객체를 요청하는 행위를 "Lookup" 한다고 한다.
      >> 9번 라인 시점에서 객체화 완료
             > Lookup 하기

<bean 여부에 따라 S가 파일에 뜨면 무조건 작동>
init-method="initMethod"
>> 초기화 작업을 처리하는 메서드


destroy-method="destroyMethod"
>> 객체 메모리를 해제할 때 호출하는 메서드


lazy-init="false"
>> Default 값, 무조건 값을 출력


lazy-init="true"
>> 호출할 때만 생성시키는 메서드(한번 더 검색)

 

 

<과거 방법>  
DeleteAction da = new DeleteAction();
da.execute();
DeleteAction da = new DeleteAction();
da.execute();
DeleteAction da = new DeleteAction();
da.execute();

<Spring 방법>
DeleteAction da = new DeleteAction();
da.execute();
da.execute();
da.execute();

> 즉,
  DeleteAction da1 = new DeleteAction();
  DeleteAction da2 = da1;
  DeleteAction da3 = da2;
    >> da1,2,3는 같은 주소를 가지고 있음 == 하나의 객체를 공유하고 있음
    >> "싱글톤 패턴" 유지
             : new를 작성하는 사람(컨테이너)이 책임지고 싱글톤 패턴을 유지해야 함!
                 >> <bean id="iphone" class="test.IPhone" lazy-init="true" scope="singleton"/>
             : 컨테이너에게 싱글톤 패턴을 유지할 수 있도록 설정이 되어있음!!


- 의존 관계를 IoC하는 방법 == 의존성을 주입하는 방법
[1] 생성자 주입(인젝션)

 

<주입 전>

public void volumeUp() {
	watch = new AppleWatch();
	// 객체화를 할 수 밖에 없음
	// 이 것을 IoC 지원을 받아 처리해보기
	watch.volumeUp();
}

 


<주입 후>

public IPhone(AppleWatch watch) {
	// 미리 선언해주면 객체화 안해줘도 괜찮음
	System.out.println("아이폰 객체 생성완료22");
	this.watch=watch;
}

public void volumeUp() {
	watch.volumeUp();
}
<bean id="iphone" class="test.IPhone">
	<!-- 인자를 알아서 맞춰줌 -->
	<constructor-arg ref="aw"/>
</bean>
<bean id="aw" class="test.AppleWatch"/>

 

<전체 코드>

- client.java

package test;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Client {
	public static void main(String[] args) {
		// Spring 컨테이너를 동작시킬 수 있도록 코드 작성
		AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		// Spring 컨테이너야, 나 폰 객체가 필요해(아이폰 객체 가지고 싶어..)!
		// 형변환 필요
		Phone phone=(Phone)factory.getBean("iphone");
		
		phone.powerOn();
		phone.volumeUp();
		phone.volumeDown();
		phone.powerOff();
		factory.close();
		
		/*
		BeanFactory bf = new BeanFactory();
		Phone phone = (Phone)bf.getBean("galaxy");
		phone.powerOn();
		phone.volumeUp();
		phone.volumeDown();
		phone.powerOff();
		*/
	}
}

- IPhone.java

package test;

public class IPhone implements Phone{
	
	private AppleWatch watch;
	// 애플워치로 소리를 업,다운 한다고 가정
	
	private int battery;
	
	public IPhone() {
		System.out.println("아이폰 객체생성완료");
	}
	
	public IPhone(AppleWatch watch) {
		// 미리 선언해주면 객체화 안해줘도 괜찮음
		System.out.println("아이폰 객체 생성완료22");
		this.watch=watch;
	}
	public IPhone(AppleWatch watch, int battery) {
		System.out.println("아이폰 객체 생성완료333");
		this.battery=battery;
		System.out.println("아이폰 전원 On : " + battery);
		this.watch=watch;
	}
	
	public void powerOn() {
		System.out.println("아이폰 전원 ON");
	}
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
	}
	
	public void volumeUp() {
		// System.out.println("아이폰 소리++");
		// watch = new AppleWatch();
		// 객체화를 할 수 밖에 없음
		// 이 것을 IoC 지원을 받아 처리해보기
		watch.volumeUp();
	}
	public void volumeDown() {
		// System.out.println("아이폰 소리--");
		// watch = new AppleWatch();
		// 객체화를 할 수 밖에 없음
		watch.volumeDown();
	}
}

- Galaxy.java

package test;

public class Galaxy implements Phone{
	
	public void initMethod() {
		System.out.println("객체를 초기화하는 작업을 처리하는 메서드...");
		// bean할 때 불러오는 것 가능
	}
	public void destroyMethod() {
		System.out.println("객체 메모리를 해제할 때 호출하는 메서드...");
		// bean할 때 불러오는 것 가능
	}
	
	// @Override 진행된 것
	public void powerOn() {
		System.out.println("갤럭시 전원 ON");
	}
	public void powerOff() {
		System.out.println("갤럭시 전원 OFF");
	}
	public void volumeUp() {
		System.out.println("갤럭시 소리++");
	}
	public void volumeDown() {
		System.out.println("갤럭시 소리--");
	}
}

- Phone.java

package test;

public interface Phone {
	public void powerOn();
	public void powerOff();
	public void volumeUp();
	public void volumeDown();
}

- BeanFactory.java

package test;

public class BeanFactory {
	// 이름을 들으면 객체를 반환
	public Object getBean(String beanName) {
		if(beanName.equals("galaxy")) {
			return new Galaxy();
		}
		else if(beanName.equals("iphone")) {
			return new IPhone();
		}
		return null;
	}
}

- AppliactionContext.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">
	
	<!-- IPhone을 설정하면 main/java의 IPhone에 s 불이 들어옴 -->
	<!-- 소속 클래스로 변경 -->
	<!-- test뒤에 IPhone을 Galaxy로도 변경 가능, 이 부분 덕분에 new 하지 않아도 결과 출력 -->
	<bean id="phone" class="test.Galaxy" init-method="initMethod" destroy-method="destroyMethod"/>
	<!-- 디폴트 설정으로 singleton이 들어감 -->
	<!-- 여러개를 쓰는게 맞을 때, scope에 prototype으로 작성 -->
	<!-- <bean id="iphone" class="test.IPhone" lazy-init="true" scope="singleton"/> -->
	
	<!-- 생성자 인젝션 : 기존의 기본생성자를 쓰던 방법이 아니라서 tag로 인자를 알려주어야 함 + 객체 생성해야 함 -->
	<!-- 컨테이너의 관리에 들어가게 됨 -->
	<bean id="iphone" class="test.IPhone">
		<!-- 인자를 알아서 맞춰줌 -->
		<constructor-arg ref="aw"/>
		<constructor-arg value="99"/>
		
	</bean>
	<bean id="aw" class="test.AppleWatch"/>

</beans>

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

[ AOP - 관점지향 프로그래밍 ]
      : Aspect Oriented Programming
      : 기존에 진행과정 코드를 뽑아내고 다음과 같이 남기는 것

진행 과정
DAO             핵심 로직(비즈니스 메서드, CRUD) + 횡단관심(공통 로직)(무조건 실행하는 로직)

(변경 전)
conn (횡)
pstmt (횡)
sql
rs
close (횡)
close (횡) -> JDBCUtil

(변경 후)
.
.
sql
rs
.
.
각각의 로직에 맞는 코드 공간에 생기므로, 응집도가 높아짐 -> 유지보수 용이