[Spring] Spring Framwork 란?
Spring Framwork 란?
자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 경량급 애플리케이션 프레임워크
만약, Spring Framwork를 왜 사용하냐는 질문이 들어온다면?
1. 프레임워크를 사용하기때문에 개발시간 단축
2. 관리가 용이 == 유지보수 용이
3. ★★★★★ 개발자들의 실력이 상향 평준화
4. "IOC와 AOP를 지원하는 경량의 프레임워크" == SPRING 프레임 워크를 한마디로 표현한다면 ?
IOC : 제어의 역행 -> 낮은 결합도
AOP : 관점지향 프로그래밍 -> 높은 응집도
경량 -> .java 파일을 사용 == POJO(서블릿이 아닌 일반 .java 파일)
1. IoC(Inversion of Control) - 제어의 역행
insert.do 요청 -> new InsertAction() (=> FC에서 작성됨)
new InsertAction(req,res);
↓
컨테이너에게 객체화를 담당시키자!
자바 코드로 new 하는것이 아니라, 컨테이너가 객체화 처리
소스 코드에 new가 없음(의존관계를 명시) -> 결합도가 낮아짐 -> 유지보수 용이
1) web.xml은 서블릿 컨테이너에게 설정을 알려주는 파일
2) 무슨설정? 만들어야할 서블릿에 관련된 설정 - 뭘 만들까? 언제 호출할까?
3) new를 작성하지 않음! 근데 객체화가 되었다!! => 서블릿 컨테이너가 했다!!!!!
4) 기본 생성자가 필요
5).xml ---->> @
6) 스프링 프레임워크가 @을 적극 사용하는 프레임워크임
2. AOP(Aspect Oriented Programming) - 관점지향 프로그래밍
Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지
- 결합도가 낮은 코드
Spring Legacy Projet 프로젝트 생성
Galaxy
package test;
public class Galaxy {
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("갤럭시 소리 --");
}
}
IPhone
package test;
public class IPhone {
public void turnOn() {
System.out.println("아이폰 전원 ON");
}
public void turnOff() {
System.out.println("아이폰 전원 OFF");
}
public void soundUp() {
System.out.println("아이폰 소리 ++");
}
public void soundDown() {
System.out.println("아이폰 소리 --");
}
}
Client
package test;
public class Client {
public static void main(String[] args) {
Galaxy phone = new Galaxy();
phone.powerOn();
phone.powerOff();
phone.volumeUp();
phone.volumeDown();
}
}
만약, 사용자가 Galaxy가 아닌 IPhone으로 수정한다면 서로의 메서드가 다르기 때문에 오류 발생
오류를 해결하기 위해서는 메서드명을 전부 수정하여야 하기 때문에 유지보수에 불리! 이러한 코드는 결합도가 높은 코드!
결합도가 높은 코드의 결합도를 낮춰보자!
1) 인터페이스
객체지향 - 다형성을 사용
"설계"
- 인터페이스 파일 생성
package test;
public interface Phone {
public void powerOn();
public void powerOff();
public void volumeUp();
public void volumeDown();
}
- 클라이언트가 원하는 객체로만 수정해주면 되므로 이전보다 유지보수에 용이
package test;
public class Client {
public static void main(String[] args) {
Phone phone = new IPhone();
phone.powerOn();
phone.powerOff();
phone.volumeUp();
phone.volumeDown();
}
}
2) 디자인 패턴 : 팩토리(Factory) 패턴
"Client에서 직접적으로 new 소스코드 xxx"
Factory의 역할 : 요청에 맞는 객체를 반환해줌
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;
}
}
- 개발자가 직접 객체생성을 하지 않고 컨테이너가 이를 대신해줌
package test;
public class Client {
public static void main(String[] args) {
BeanFactory bf=new BeanFactory();
Phone phone=(Phone)bf.getBean(args[0]);
phone.powerOn();
phone.volumeUp();
phone.volumeDown();
phone.powerOff();
}
}
- Run -> Run Configurations-> Arguments에 getBean에 넣은 "galaxy" 혹은 "iphone"을 입력하면
원하는 결과가 나옴!
< 디자인 패턴 동작 순서 >
1) 클라이언트가 컨테이너를 로딩
2) 이때, 스프링설정파일을 참고하여 로드
3) 스프링설정파일의 <bean> -> 객체화
== 즉시 로딩(pre-loading) 방식
4) "phone" 객체 요청 == Lookup
5) 요청한 객체 반환
- 설정파일 (.xml) 생성
scr/main/resource에 Spring Bean Configuration File을 생성
- 기본 Spring Bean Configuration File
<?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">
</beans>
- id, class는 필수 속성
<bean id="phone" class="test.IPhone"/> == IPhonephone=new IPhone();
<?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">
<bean id="phone" class="test.IPhone"/>
</beans>
- 클라이언트에서 phone 호출
package test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Client {
public static void main(String[] args) {
//1. Spring 컨테이너를 동작시킬 수 있도록 코드작성
AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
//2. Spring 컨테이너야, 나 폰 객체가지고싶어!
// = Lookup
Phone phone=(Phone)factory.getBean("phone");
phone.powerOn();
phone.volumeUp();
phone.volumeDown();
phone.powerOff();
//3. 컨테이너 연결 해제
factory.close();
}
}
- 설정파일에서 설정한 IPhone이 출력됨
<bean> 의 여러 속성들
1) init-method, destroy-method
package test;
public class Galaxy implements Phone{
public Galaxy () {
System.out.println("갤럭시 객체 생성완료");
}
public void initMethod() {
System.out.println("객체를 초기화하는 작업을 처리하는 메서드...");
}
public void destroyMethod() {
System.out.println("객체 메모리를 해제할때 호출하는 메서드...");
}
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("갤럭시 소리 --");
}
}
- 설정 파일에 init-method, destroy-method 하기와 같이 추가
<bean id="phone" class="test.Galaxy" init-method="initMethod" destroy-method="destroyMethod"/>
- 컴파일 시 하기와 같이 출력
2) lazy-init ( 지연로딩)
- 클라이언트에서 객체를 요청(Lookup방식)하지 않더라도 스프링의 설정파일의 <bean>에서 객체화를 하게되는데
이를 즉시 로딩(pre-loading) 방식이라도 함
하지만, lazy-init 을 true로 설정하게 되면 객체 생성을 하지않고 Lookup을 했을 때 생성하게 됨
<?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">
<bean id="phone" class="test.Galaxy" lazy-init="true" />
</beans>
- 클라이언트에서 Lookup부분은 주석처리
package test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Client {
public static void main(String[] args) {
//1. Spring 컨테이너를 동작시킬 수 있도록 코드작성
AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
//2. Spring 컨테이너야, 나 폰 객체가지고싶어!
// = Lookup
/*
* Phone phone=(Phone)factory.getBean("phone"); phone.powerOn();
* phone.volumeUp(); phone.volumeDown(); phone.powerOff();
*/
//3. 컨테이너 연결 해제
factory.close();
}
}
- lazy-init 을 true로 설정되었기 때문에 Lookup을 하지 않으면 하기와 같이 객체가 생성되지 않음
3. scope
- Lookup (객체화) 3번하여도 scope의 디폴트는 singleton이기 때문에
객체 생성이 한번만 이루어지게 됨
package test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class Client {
public static void main(String[] args) {
//1. Spring 컨테이너를 동작시킬 수 있도록 코드작성
AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
//2. Spring 컨테이너야, 나 폰 객체가지고싶어!
// = Lookup
Phone phone1=(Phone)factory.getBean("phone");
Phone phone2=(Phone)factory.getBean("phone");
Phone phone3=(Phone)factory.getBean("phone");
//3. 컨테이너 연결 해제
factory.close();
}
}
하기와 같이 객체 생성이 한번 실행됨
설정파일에 scope를 prototype로 수정하면 객체 생성이 클라이언트에서 생성한 대로 3번 실행 됨
<bean id="phone" class="test.Galaxy" scope="prototype"/>
DI (Dependency Injection ) - 의존관계 주입
의존관계를 IoC하는 방법 == 의존성을 주입하는 방법