[Spring] Spring Framework 기초

programmeaow·2022년 7월 6일
0

Spring

목록 보기
1/1

🍀 Spring Framework

- Java 플랫폼을 위한 오픈 소스 경량 애플리케이션 프레임워크

Spring은 객체를 생성하고 관리해주는 컨테이너를 내부적으로 포함하고 있다.

코드로 객체를 직접 생성하는 Java와 달리, 코드와 분리된 .xml 파일에서 객체를 생성하고 관리한다.

Spring 설치하기

Eclipse를 이용하여 Spring을 사용할 예정이라, 호환성 문제로 최신 버전이 아닌 3.9.14버전을 .zip 파일로 다운받아 압축 해제하여 사용하였다.
해당 깃허브에서 파일을 다운받아 사용했다 : https://github.com/spring-projects/toolsuite-distribution/wiki/Spring-Tool-Suite-3

파일을 압축 해제 하면 나오는 sts-3.9.14.RELEASE 폴더 내부의 STS.exe를 실행하여 사용하면 된다.

Spring을 실행하면 아무것도 생성하지 않은 상태여도 server라는 폴더가 존재하는 것을 확인할 수 있다.

Spring은 기본적으로 Tomcat server가 내장되어 있어서 별도의 설치 없이도 Server 구동이 가능하다! 물론 싫다면 다른 버전을 설치하여 서버 구동 또한 가능하다.

- Spring Project 환경설정

먼저 Java Project 선택 -> create module 체크해제 -> Finish 로 Java Project를 생성해준다.

Spring Project를 사용하려면 자바 프로젝트 생성 후 변환 작업을 거쳐야 한다.
1 . maven project 변환 : 우클릭 -> Configure -> Convert to Maven Project
2 . Spring 변환 : 우클릭 -> Spring -> Add Spring Project Nature
3. pom.xml 설정에서 아래의 코드 추가

<dependencies>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>4.3.30.RELEASE</version>
  	</dependency>
  </dependencies>

설정 완료시 Spring Project를 이용할 수 있다.



🌿 Spring에서의 객체 생성

Spring은 객체를 생성하고 관리해주는 컨테이너를 내부적으로 포함하고 있다고 했는데, 이런 Spring Container가 관리하는 객체들을 bean이라고 한다.

먼저 객체 생성 구조를 알아보기 전, 객체 생성을 위한 설정 파일을 만들어보자.

1 . 프로젝트 우클릭 -> New -> Others -> Spring 폴더에서 Spring Bean Configuration File 선택
2 . Next -> Beans 선택 -> 프로젝트에서 src 클릭하여 경로 지정

이름은 임의로 설정 가능하며 나는 manager.xml 라는 이름으로 생성했다.



📁 model 패키지에 객체의 정보를 담을 student 클래스를, running 패키지에 객체 생성을 확인할 Test Class를 생성했다.

public class Student {
	private String name;
	private int age;
	private int grade;
	
	public Student() {
		System.out.println("Student()");
	}
	
	public Student(String name, int age, int grade) {
		this.name = name;
		this.age = age;
		this.grade = grade;
		System.out.println("Student(String name, int age, int grade)");
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
		System.out.println("setName(String name)");
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
		System.out.println("setAge(int age)");
	}
	public int getGrade() {
		return grade;
	}
	public void setGrade(int grade) {
		this.grade = grade;
		System.out.println("setGrade(int grade)");
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Student [name=");
		builder.append(name);
		builder.append(", age=");
		builder.append(age);
		builder.append(", grade=");
		builder.append(grade);
		builder.append("]");
		return builder.toString();
	}

어노테이션은 사용하지 않고 기본 메서드를 작성했다.
source 메뉴에서 기본 생성자 / 멤버변수 초기화 생성자 / Getter / Setter / toString 메서드를 자동으로 생성할 수 있다!

객체 생성과 값 대입시 호출을 확인하기 위해 간단한 출력문들을 함께 작성해주었다.

📁 Test 클래스에는 실행을 위한 Main method가 포함되어 있다.

public class Test {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
	}
}

Spring 컨테이너를 통해 객체 생성 권한을 부여한 뒤 Test 클래스를 실행하여 생성 여부를 확인해보자.

manager.xml 파일에서 ctrl+space를 누르면 <bean></bean> 태그 생성이 가능하다.
<bean/> : 열고 닫는 태그가 하나인 형식으로도 변경할 수 있다.

<bean id="s" class="model.Student"/> <!--객체 생성 권한 부여-->

출력 : Student()

Main 메서드 실행시 manager.xml 파일이 부여받은 권한을 통해 Student 객체가 생성되면서 해당 로그가 출력된 것을 확인할 수 있다.

이번에는 Test 클래스에 Student 객체인 s 생성 후, 해당 객체를 출력해보자.

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
	Student s = context.getBean("s", Student.class);
	System.out.println(s);
}

//Student()
//Student [name=null, age=0, grade=0]

Student 객체가 생성되고 기본값인 null, 0, 0이 출력되었다.
객체를 생성만 하고 데이터를 주지 않았기 때문에 기본값이 출력된 것이다.

Scope 속성 지정하기

Student 객체인 s1를 추가 생성 후 다시 출력해보자.

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
	Student s = context.getBean("s", Student.class);
	System.out.println(s);
    
	Student s1 = context.getBean("s", Student.class);
	System.out.println(s1);
}

//Student()
//Student [name=null, age=0, grade=0]
//Student [name=null, age=0, grade=0]

Student 객체는 하나만 생성되었다. 어째서일까?

객체 생성 과정은 다음과 같다 :

Main 메서드 실행 -> parameter로 준 이름의 설정 파일 실행 -> 로딩시 Student 기본생성자 호출 -> Student 객체 생성

이때 실행되는 코드는 이것이다 : <bean id="s" class="model.Student" scope="prototype"/>

xml 파일에서는 scope 속성을 지정할 수 있는데, 속성 지정이 생략된 경우 scope="singleton" 으로 자동 적용된다!
singleton이 적용되어 객체를 하나만 생성하고 기존에 생성된 객체를 불러왔기 때문에 객체가 의도한대로 두개 생성되지 않은 것이다.

✅ prototype

.getBean 호출 시마다 객체를 생성하게 하려면 scope 속성을 prototype으로 지정해줘야 한다.
prototype은 객체를 여러개 생성할 수 있지만, .getBean을 사용하지 않으면 객체가 생성되지 않으니 주의해야 한다.

<bean id="s" class="model.Student" scope="prototype"/>

manager.xml 파일에서 scope 속성을 prototype 으로 지정해주었다.
다시 Test 클래스를 실행해보자.

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
	Student s = context.getBean("s", Student.class);
	System.out.println(s);
    
	Student s1 = context.getBean("s", Student.class);
	System.out.println(s1);
}

//Student()
//Student [name=null, age=0, grade=0]
//Student()
//Student [name=null, age=0, grade=0]

변경 후에는 .getBean을 두번 호출하여 Student 객체가 두개 생성되며 기본 생성자도 두번 호출된 것을 확인할 수 있다.



<constructor-arg>

데이터를 주면서 변수를 생성하려면 <constructor-arg> 태그를 이용하여 작성하면 된다.
[ 이름 : James, 나이 : 15, 학년 : 3 ]의 정보로 Student 객체를 생성해보자.

작성 문법은 다음과 같다.

<constructor-arg name="변수명" value="값"/>

정보를 모두 입력하게 되면 다음과 같은 코드가 된다.

<bean id="s" class="model.Student" scope="prototype">
	<constructor-arg name="name" value="James"/>
	<constructor-arg name="age" value="15"/>
	<constructor-arg name="grade" value="3"/>
</bean>

agegrade 는 Int 타입의 변수이지만 여기서 ""는 String 등의 문자 표현 방식이 아니라, 값 표현 형식이기 때문에 ""안에 입력해야 한다.

Test 클래스를 다시 실행해보자.

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
	
    Student s = context.getBean("s", Student.class);
	System.out.println(s);
}
//Student(String name, int age, int grade)
//Student [name=James, age=15, grade=3]

멤버변수 초기화 메서드가 실행되며 [ 이름 : James, 나이 : 15, 학년 : 3 ]의 데이터를 가진 변수 s를 생성한 것이 확인되었다.

Student와 비슷한 구조의 Teacher 클래스를 생성한 뒤, [ 이름 : Tim, 나이 : 34, 반 번호 : 1 ]의 정보를 가진 Teacher 객체를 생성 후 함께 출력해보자.

<!-- 설정 파일 -->
<bean id="s" class="model.Student" scope="prototype">
	<constructor-arg name="name" value="James"/>
	<constructor-arg name="age" value="15"/>
	<constructor-arg name="grade" value="3"/>
</bean>
	
<bean id="t" class="model.Teacher" scope="prototype">
	<constructor-arg name="name" value="Tim"/>
	<constructor-arg name="age" value="34"/>
	<constructor-arg name="classNum" value="1"/>
</bean>

//Test 클래스
public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
    
	Student s = context.getBean("s", Student.class);
	System.out.println(s);
		
	Teacher t = context.getBean("t", Teacher.class);
	System.out.println(t);
}

//출력 결과 
//Student(String name, int age, int grade)
//Student [name=James, age=15, grade=3]
//Teacher(String name, String age, int classNum)
//Teacher [name=James, age=15, classNum=1]


이번에는 Main 메서드의 context를 제외하고 모두 지운 뒤 xml 설정 파일의 <constructor-arg> , scope 설정도 함께 전부 삭제하고 다시 실행해보자.

<!-- 설정 파일 -->
<bean id="s" class="model.Student"/>
<bean id="s" class="model.Teacher"/>

//Test 클래스
public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
}

먼저 생성되는 객체는 Student()Teacher() 중 무엇일까?
출력 결과는 다음과 같다.

Student()
Teacher()

그럼 이번에는 설정 파일의 순서를 바꾼 뒤 다시 결과를 확인해보자.

<!-- 설정 파일 -->
<bean id="s" class="model.Teacher"/>
<bean id="s" class="model.Student"/>

//Test 클래스
public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("manager.xml");
}

//출력 결과
//Teacher()
//Student()

이것으로 설정 파일의 위치 순서대로 변수를 생성한다는 사실을 확인할 수 있다.


profile
개발이란 뭘까

0개의 댓글