🍀 Spring Framework
- Java 플랫폼을 위한 오픈 소스 경량 애플리케이션 프레임워크
Spring
은 객체를 생성하고 관리해주는 컨테이너를 내부적으로 포함하고 있다.
코드로 객체를 직접 생성하는 Java
와 달리, 코드와 분리된 .xml
파일에서 객체를 생성하고 관리한다.
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 구동이 가능하다! 물론 싫다면 다른 버전을 설치하여 서버 구동 또한 가능하다.
먼저 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 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이 출력되었다.
객체를 생성만 하고 데이터를 주지 않았기 때문에 기본값이 출력된 것이다.
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이 적용되어 객체를 하나만 생성하고 기존에 생성된 객체를 불러왔기 때문에 객체가 의도한대로 두개 생성되지 않은 것이다.
.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>
age
와 grade
는 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()
이것으로 설정 파일의 위치 순서대로 변수를 생성한다는 사실을 확인할 수 있다.