spring 01 - 프레임워크 시작하기

프레임워크(Framework) 정의

  • 사전적 의미 : 어떤 것을 구성하는 구조 또는 뼈대
  • 소프트웨어적 의미 : 기능을 미리 클래스나 인터페이스 등으로 만들어 제공하는 반제품 적 형태

장점

  • 일정한 기준에 따라 개발이 이루어지므로 개발 생산성과 품질이 어느정도 보장된 애플리케이션을 개발할 수 있다.
  • 개발 후 유지보수 및 기능의 확장성에서도 고품질을 보장

스프링 프레임워크

  • 자바 웹 애플리케이션 개발을 위한 오픈 소스 프레임워크다
  • EJB(Enterprise Java Bean) 보다 가벼운 경량 프레임 워크

컨테이너(Container)

  • '톰캣 = 서블릿 컨테이너' 라고 부르는데, 톰캣을 실행하면 서블릿의 생성, 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지고 서블릿을 관리하기 때문이다
  • 스프링은 애플리케이션에서 사용되는 여러가지 빈(클래스 객체를)을 개발자가 아닌 스프링이 권한을 가지고 직접 관리하게 된다.

특징

  • EJB보다 가볍고, 배우기 쉬우며, 경량 컨테이너의 기능을 수행한다
  • 제어 역행(IoC, Inversion of Control) 기술을 이용해 애플리케이션 간의 느슨한 결합을 제어한다
  • 의존성 주입(DI, Dependency Injection) 기능을 지원한다
  • 관점 지향 (AOP, Aspect-Oriented Programming) 기능을 이용해 자원 관리한다
  • 영속성과 관련된 다양한 서비스를 지원한다
  • 수많은 라이브러리와의 연동 기능을 지원한다

용어 정리

  1. 의존성 주입 : 클래스 객체를 개발자가 코드에서 직접 생성하지 않고, 프레임워크가 생성하여 사용하는 방법
  2. 제어 역행 : 서블릿이나 빈 등을 개발자가 코드에서 직접 생성하지 않고, 프레임 워크가 직접 수행하는 방법
  3. 관점 지향 : 핵심 기능 외 부수 기능들을 분리해 구현함으로써 모듈성을 증가시키는 방법

스프링의 주요 기능


의존성 주입

  • 연관관계를 개발자가 직접 코딩을 통해 컴포넌트(클래스)에 부여하는 것이 아니라 컨테이너가 연관 관계를 직접 규정하는 것
  • 코드에서 직접적인 연관 관계가 발생하지 않으므로 각 클래스들의 변경이 자유로워진다

-> 강한 결합과 약한 결합
서로 관련있는 기능들은 강하게 결합(tightly coupled)하고, 관련이 없는 기능들은 약하게 결합(loosely coupled) 해야 한다


자바 코드로 게시판 구현시

  • DAO 클래스에서 오라클과 연동해 게시판 기능을 구현하고 있는데, 오라클에서 MySql로 DB 변경시 DAO 클래스의 기능을 일일이 변경해야 하고, 더 나아가 DAO 클래스를 사용하는 Service 클래스의 기능도 변경해야 할 수도 있음
    -> 따라서 자바 코드에서 직접 객체를 생성해 사용하는 것은 복잡한 문제를 일으킬 가능성이 농후

의존성 주입을 적용한 게시판

  1. 의존성 주입의 장점
  • 클래스들 간의 의존 관계를 최소화 하여 코드를 단순화 가능
  • 애플리케이션을 더 쉽게 유지 관리 가능
  • 기존의 구현 방법은 개발자가 코드로 객체의 생성과 소멸을 제어했지만, 의존성 주입시 객체의 생성, 소멸, 객체간의 의존관계를 컨테이너가 제어
  1. 제어의 역전(Inversion Of Control)
  • 기존 코드에서는 개발자가 직접 객체를 제어했지만 스프링 프레임 워크에서는 객체의 제어를 스프링이 직접 담당한다
    -IoC의 종류도 여러가지
  • 일반적으로 스프링에서는 DI로 IoC의 기능을 구현하므로 IoC보다는 DI라는 용어를 더 많이 사용한다
  1. 스프링의 의존성 주입 방법
  • 생성자에 의한 주입
  • setter에 의한 주입

setter로 의존성 주입하기

  1. 추상 메소드 작성하기
package com.sping.ex02;

public interface PersonService {
	// 1. 추상 메소드로 작성
	public void sayHello();
}
  1. 구현클래스(setter 작성)
package com.sping.ex02;

// 2. 구현 클래스 작성
public class PersonServiceImpl implements PersonService {
	private String name;
	private int age;
	
	// 3. 값 받을 setter 작성
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	// 4. 오버라이드
	@Override
	public void sayHello() {
		System.out.println("이름 : " + name);
		System.out.println("나이 : " + age);
	}
}
  1. person.xml 짜기(값 설정)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
                             "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
   <!-- class : 연결할 파일 경로 지정 -->
   <bean id="personService02" class="com.sping.ex02.PersonServiceImpl">
   		<!-- 넣을 변수명과 값 작성 -->
   		<property name="name">
   			<value>홍길순</value>
   		</property>
   		<property name="age">
   			<value>20</value>
   		</property>
   	</bean>
</beans>
  1. xml에서 설정한 값을 personService를 통해 받아오기
package com.sping.ex02;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class PersonTest2 {
	public static void main(String[] args) {
		BeanFactory factory = 
				new XmlBeanFactory(new FileSystemResource("person.xml"));
		
		// 값을 설정한 id 값 받아오기
		PersonService person = (PersonService) factory.getBean("personService02");
		// 실행
		person.sayHello();
	}
}


생성자로 의존성 주입하기

  1. 추상 메소드 작성
package com.spring.ex03;

// 생성자에 의한 명시
public interface PersonService {
	// 1. 추상 메소드 명시
	public void sayHello();
}
  1. 구현클래스(생성자) 만들기
package com.spring.ex03;

public class PersonServiceimpl implements PersonService{
	private String name;
	private int age;
	
	// 기본 생성자
	public PersonServiceimpl() {}
	
	// 생성자 만들기
	public PersonServiceimpl(String name) {
		this.name = name;
	}
	public PersonServiceimpl(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	@Override
	public void sayHello() {
		System.out.println("이름 : " + name);
		System.out.println("나이 : " + age);
	}
}
  1. person.xml 짜기(값 설정)
   	<bean id="personService03" class="com.spring.ex03.PersonServiceimpl">
   		<!-- 생성자 구문. 태그 속에 value로 값 보냄 -->
   		<constructor-arg value="이순신" />
      		<!-- 위 아래 어느 모양이라도 상관 없다 -->
   		<constructor-arg value="23"></constructor-arg>
   	</bean>
  1. xml에서 설정한 값을 personService를 통해 받아오기
package com.spring.ex03;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class PersonTest {
	public static void main(String[] args) {
		// xml에 작성한 값 가져오기(bean 자료 생성)
		BeanFactory factory =
			new XmlBeanFactory(new FileSystemResource("person.xml"));
		
		PersonService person = (PersonService) factory.getBean("personService03");
		person.sayHello();
	}
}


만약 xml 에서 <constructor-arg value="이순신" /> 이것만 값을 보내도 나이 없이 이름만 잘 출력된다.

이런 식으로 (근데 속성은 있고 값이 없으니 안 예쁘다)

3번 xml을 이런식으로 작성해주고

   	<bean id="personService03" class="com.spring.ex03.PersonServiceimpl">
   		<!-- 생성자 구문. 태그 속에 value로 값 보냄 -->
   		<constructor-arg value="이순신" />
   		<constructor-arg value="33"></constructor-arg>
   	</bean>
   	<!-- id 값은 고유 넘버. 겹치면 안된다 -->
   	<bean id="personService03.1" class="com.spring.ex03.PersonServiceimpl">
   		<constructor-arg value="이수영" />
   	</bean>

4번을 이런식으로 작성할 수도 있다.

package com.spring.ex03;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class PersonTest {
	public static void main(String[] args) {
		// xml에 작성한 값 가져오기(bean 자료 생성)
		BeanFactory factory =
			new XmlBeanFactory(new FileSystemResource("person.xml"));
		
		PersonService person = (PersonService) factory.getBean("personService03");
		person.sayHello();
		
		System.out.println();
		
		PersonService person1 = (PersonService) factory.getBean("personService03.1");
		person1.sayHello();
	}
}


lazy-init 사용해보기

기본적으로 Spring의 ApplicationContext 구현은 초기화 프로세스에서 모든 싱글톤 빈을 생성 및 설정하게 된다.

어떤 이유로 특정 bean이 늦게 초기화되기를 원한다면 lazy-init 을 사용하여 조정할 수 있다.

lazy-init 은 "true", "false", "default" 세 가지의 옵션을 가진다. default 는 spring 의 기본 동작에 맞게 bean 을 생성하며 기본 동작은 false 이다. true 로 설정할 경우 나중에 Bean 을 생성하게 된다.

  1. lazy.xml에 속성 설정하기
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
                             "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <bean id="firstBean" class="com.spring.ex05.First" lazy-init="false" />
    <bean id="secondBean" class="com.spring.ex05.Second" lazy-init="true" />
    <bean id="thirdBean" class="com.spring.ex05.Third" lazy-init="default" />
</beans>
  1. 사용 할 세개의 클래스 작성하기
"First.java"
package com.spring.ex05;

public class First {
	public First() {
		System.out.println("First 생성자 호출");
	}
}



"Second.java"
package com.spring.ex05;

public class Second {
	public Second() {
		System.out.println("Second 생성자 호출");
	}
}



"Third.java"
package com.spring.ex05;

public class Third {
	public Third() {
		System.out.println("Third 생성자 호출");
	}
}
  1. 실행 클래스 작성하기
package com.spring.ex05;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class LazyTest {
	public static void main(String[] args) {
		ApplicationContext context =
				new FileSystemXmlApplicationContext("lazy.xml");
		System.out.println("SecondBean 얻기");
		context.getBean("secondBean");
	}
}


분명 secondBean을 getBean 해주었음에도 lazy 설정에서 true 즉 나중에 Bean을 생성하겠다 해주었기 때문에 출력결과가 위와 같이 나오는 모습을 확인 할 수 있었다.


좋은 웹페이지 즐겨찾기