본문 바로가기

Dev/[Java]

[Spring] 1. 라이브러리와 프레임워크의 차이점? DI전략1

반응형

 

라이브러리(Library)와 프레임워크(Framework)의 차이점?

 

: 라이브러리는 주도권을 개발자가 가지고 있다.

: 프레임워크는 개발자가 작성한 클래스를 역으로 호출하기 때문에, 주도권을 프레임워크가 가지고 있다.

 

 

 

프레임 워크의 정의

 

비기능적 요구사항(성능, 보안,확장성,안정성 등)을 만족하는 구조와 

구현된 기능을 안정적으로 실행하도록 제어해주는 잘 만들어진 구조의 라이브러리 덩아리

 

스프링 쓰는 이유?

초기 개발 단계마다 구현해야 하는 귀찮은 작업들을 알아서 해준다..

뭔 용어가 이렇게 많냐;;

 

 

IoC(Inversion of Control)?

제어의 역전, 즉 인스턴스 생성부터 소멸까지의 생명주기관리를 개발자가 아닌 컨테이너가 대신해줌.

 

POJO(Plain Old Java Object)?

오래 된 방식의 간단한 자바 오브젝트.. JavaEE등의 중량 프레임웤들을 사용하게 되면서.. 무거운거 쓰지말자.. 라고 해서 생겨난 용어. 2000년 9월에 Martin Fowler  등이 사용함. 

자바 모델이나기능, 프레임워크 등을 따르지 않은 자바 오브젝트를 지정하는 말이다.

굳이 서블릿 엔진 쓰지말자..!

그니까 얘네가 제안한 이 방법을 스프링이 채택한거다.

뭘 상속받지 않는 대신에 어노테이션이 되게 많아졌다.

 

DI(Dependency Injection

설정파일이나 어노테이션을 통해 객체 간의 의존관계를 설정할 수 있다.

 

DI용어..

빈(Bean)  스프링이 IoC방식으로 관리하는 객체라는 뜻.

빈팩토리 스프링의 IoC를 담당하는 핵심 컨테이너

애플리케이션 컨텍스트 : 빈팩토리를 확장한 IoC컨테이너

설정 메타정보 : 어플리케이션 컨텍스트 또는 빈팩토리가 IoC를 적용하기 위해 사용하는 메타정보..

 

DI의 유형

1. Setter Injection

2. Constructor Injection

3. Method Injection

 

 

PSA(Portable Service Abstraction)

트랜잭션 추상화, OXM 추상화, 데이터 액세스의 Exception 변환기능 등 기술적인 복잡함은 추상화를 통해 Low Level의 기술 구현 부분과 기술을 사용하는 인터페이스로 분리한다.

 

 

우선 스프링이 언제 나왔는지 부터 살펴볼까?

 

github.com/spring-projects/spring-framework

 

spring-projects/spring-framework

Spring Framework. Contribute to spring-projects/spring-framework development by creating an account on GitHub.

github.com

J2EE쪽에.. EJB(Enterprise Java Beans)라는 기술이 있다.

: WAS상에서 동작하고 복잡한 트랜잭션 처리, 인증... 이런 기능들을 제공.

: 거의 대부분 APP들이 EJB였다..

: 근데 이건 WAS상에서 동작하기 떄문에 JAR로 묶어야댐..

: 웹인경우 또 WAR로 묶어..

: 이 두개를 묶어서(EAR) WAS에서 Deploy해야지만.. 되었다..

: 배포가 굉장히 복잡하고 귀찮았다..하다가 버그라도 있으면 .. 다시 또 고치고, JAR WAR 만들고. EAR만들고, 배포하고.. 

복잡했다.

 

:그래서 Rod Johnson이라는 사람이.. EJB없이 개발해보자.. 해서 2004년에 책을 냄.

:그 후 2005년에 로드 존슨, juergen Hoeller 등이 스프링개발하고 스프링책냄

 

 

 

스프링.io사이트 가보면... 스프링에서 파생되어나온 것들을 볼 수 있다.

spring.io/

 

Spring makes Java simple.

Level up your Java code and explore what Spring can do for you.

spring.io

Spring Framework는 모든 종류의 배포 플랫폼에서 최신 Java 기반 엔터프라이즈 애플리케이션을위한 포괄적 인 프로그래밍 및 구성 모델을 제공합니다.

Spring의 핵심 요소는 애플리케이션 수준의 인프라 지원입니다. Spring은 엔터프라이즈 애플리케이션의 "배관"에 중점을 두어 팀이 특정 배포 환경에 대한 불필요한 연결없이 애플리케이션 수준의 비즈니스 로직에 집중할 수 있도록합니다.

 

스프링 프레임워크 페이지 설명...

그니까 인프라는 우리가 깔아줄테니.. 너네는 로직에만 집중해라...

그래서 주도권을 얘네가 가져갑니다..

 

 

 

우린 그리고 Spring Boot 쓸거니까.. 부트 좀 뭔지 알아보자..

 

특징

스프링 기반 어플리케이션 개발할 때 쉽게 만들도록 도와준다.

빈번하게 사용하는 기능들은 그냥 기본으로 제공하며, 사용자가 변경 가능

code generation이 없고, XML도 사용하지 않는다.

java 8 이상부터 사용가능하다.

 

 

 

 

이제 스프링 프레임웤 기반의 프로젝트 만들어 볼것이다.

순서..

1. Dynamic Web Project 생성

-> Maven Project로 변환 

-> Spring-context, junit, spring-test 의존성 추가

-> Spring Bean Configuration XML 파일 생성

-> 클래스 작성하고..

 

 

1. 프로젝트 생성

web.xml 생성 해야댄다.. 체크..

 

 

 

메이븐으로 프로젝트 변경..

 

pom.xml에 의존성 추가..

 

메이븐 레포지토리 접속

mvnrepository.com/

 

Maven Repository: Search/Browse/Explore

JKube Kit :: Common Last Release on Jan 28, 2021

mvnrepository.com

spring context

mvnrepository.com/artifact/org.springframework/spring-context

 

Maven Repository: org.springframework » spring-context

 

mvnrepository.com

 

추가되었다..

 

 

src밑에 config라는 폴더하나만들자

spring beanconfig file 생성..

beans와 context 선택하고.. 맨 위에거 체크..

 

 

 

 

config 파일이 생겼다.

 

이제 인터페이스 만들것이다.

 

package myspring.di.xml;

public class StringPrinter implements Printer {

	@Override
	public void print(String message) {
		// TODO Auto-generated method stub

	}

}

 

 

StringPirnter클래스 하나 만들고, 방금전 만든 프린터 인터페이스를 추가..

package myspring.di.xml;

public class StringPrinter implements Printer {
	StringBuilder builder = new StringBuilder();

	@Override
	public void print(String message) {
		this.builder.append(message);
	}

	@Override
	public String toString() {
		return "StringPrinter [builder=" + builder + "]";
	}
	
	
}

 

 

 

ConsolePirnter클래스 하나 만들고, 방금전 만든 프린터 인터페이스를 추가..

 

 

package myspring.di.xml;

public class ConsolePrinter implements Printer {

	@Override
	public void print(String message) {
		System.out.println(message);
	}

}

 

 

 

 

 

이제 String Printer와 Console Printer 두개가 준비가 되었다.

다음으로는..

Hello라는 클래스 하나 만들어준다.

 

package myspring.di.xml;

public class Hello {
	private String name;
	private Printer printer;
	
	public Hello() {
		System.out.println("Hello Default constructor called");
	}

	public void setName(String name) {
		System.out.println("Hello setName() called" + name);
		this.name = name;
	}
	public void setPrinter(Printer printer) {
		System.out.println("Hello setPrinter() called" + printer.getClass().getName());
		this.printer = printer;
	}
	
	public String sayHello() {
		return "Hello" + this.name;
	}
	
	public void print() {
		this.printer.print(sayHello());
	}
	
}

 

그리고 이제 아까 만들었던 springbeans.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	
	
	<!-- StringPrinter 클래스를 Bean으로 등록 -->
	<bean id="strPrinter" class="myspring.di.xml.StringPrinter" />
	
	<!-- ConsolePrinter 클래스를 Bean으로 등록 -->
	<bean id="conPrinter" class="myspring.di.xml.ConsolePrinter" />
	
	<!-- Hello Bean 설정 -->
	<!-- 
		scope종류
		1. singleton (default) : 객체 생성 하나만하겠다.
		2. prototype : 객체 생성 항상 한다.
		3. request, session : 웹에서 사용하는 스코프, session이 request 보다 범위가 넓음. 
	 -->
	<bean id="hello" class="myspring.di.xml.Hello" scope="singleton">
		<!-- Setter Injection 설정 -->
		<property name="name" value="스프링이다." />
		<property name="printer" ref="strPrinter" />
	</bean>

</beans>

 

 

이렇게 생성해보았다.

그러니까.. 중요한 개념은 bean이라는 태그 안에 printer클래스를 등록해준다.....

그리고 나서 hello 클래스도 등록해주고.... setname, setprinter같은 setter들을 property 태그로 만들어주는것이다..

여기서.. <property name="printer" ref="strPrinter" /> 는 속성 중에 ref가 있는 것을 볼 수 있다.

ref에 strprinter를 넣어줌으로써.. 위에 bean태그로 만들어놓은 stringprinter객체를 생성하는것이다...

 

setter Injection 개념...

 

 

 

junit과 springtest도 받아준다..

spring test 는 context랑 버전을 맞춰준다.

 

이후 테스트를 해본다..

이렇게 객체가 생성되어서... getbean매서드 쓰면 가져올 수 있다는 것을 알 수 있다..

또한 포인트로는 getbean의 매개변수로 아까 xml에서 작성했던 bean의 id를 넣어주어야 한다는 것이다..

package myspring.di.xml.test;

import static org.junit.Assert.*;

import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericXmlApplicationContext;

import myspring.di.xml.Hello;
import myspring.di.xml.Printer;

public class HelloBeanTest {
	
	@Test @Ignore
	public void setterInjection() {
		// xml파일을 알려준다.
		// 여기까지만 해도 객체가 생겨난다.
		BeanFactory factory = new GenericXmlApplicationContext("config/springbeans.xml");
		// bean을 생성했으니까 줘바 ..
		// xml파일의 ID를 사용한다..
		// bean은 타입이 object이므로.. Hello로 캐스팅해야댐
		Hello hello = (Hello)factory.getBean("hello");
		Hello hello2 = (Hello)factory.getBean("hello", Hello.class);
		
		System.out.println(hello == hello2);
		assertSame(hello2, hello);
		assertEquals("Hello스프링이다.", hello.sayHello());
		
		hello.print();
		
		Printer printer = factory.getBean("strPrinter", Printer.class);
		System.out.println(printer.getClass().getName());
		System.out.println(printer.toString());
	}
}

 

그리고 생성할 때 마다 객체가 새로 생겨나는것이아닌... 하나의 객체가 계속 재사용된다고한다..

빈으로 생성한 객체는 기본이 singleton이다. 이건 객체 재사용 하기위해 생성할때마다 재사용.'

prototype으로 하면 생성할때마다 객체가 새로 생성된다고한다..

테스트에서 주소를 찍어보면은 ... singleton으로 할 때는 주소가 같으나

prototype으로 하면 다른 것을 확인할 수 있다.

 

 

 

무튼 여기까지 실습 해보면... 스프링에 대해 조금은 이해할 수 있을 것 같다.

 

반응형