예전 프로젝트는 STS4를 이용하여 프로젝트를 생성했었지만,
이번엔 initializr로 프로젝트를 생성하고 eclipse를 사용할 예정이다.
1. 프로젝트 만들기
maven으로 선택해 준 뒤, springboot 버전과 이름들을 지정해 주고, CENERATE를 클릭하여 다운로드 해주면 된다.
다운로드 후, zip 압축을 출고 eclipse에서 폴더를 열어준다.
File > import > Existing Maven Projects
압축 푼 폴더를 지정해준다.
Finish를 클릭한다.
성공적으로 불러온 것을 확인할 수 있다.
AppGamingBasicJava 클래스를 하나 생성해준다.
package com.jm.learnspringframework;
public class AppGamingBasicJava {
public static void main(String[] args) {
var marioGame = new MarioGame();
var gameRunner = new GameRunner(marioGame);
gameRunner.run();
}
}
marioGame과 gameRunner의 객체를 만들어 준 뒤, gameRunner의 run 메소드를 호출한다.
MarioGame과 GameRunner의 클래스를 생성해준다.
패키지는 AppGamingFrameworkApplication클래스가 있는 패키지에 .game을 추가한 패키지로 지정해준다.
package com.jm.learnspringframework.game;
public class GameRunner {
MarioGame game;
public GameRunner(MarioGame game) {
this.game = game;
}
}
GameRunner 생성자에서 MarioGame 인자를 받기 위해 위 코드와 같이 GameRunner 클래스를 수정해준다.
game인스턴스를 생성해 준 뒤, 생성자를 만들어 MarioGame을 받을 수 있도록 하였다.
package com.jm.learnspringframework.game;
public class GameRunner {
MarioGame game;
public GameRunner(MarioGame game) {
this.game = game;
}
public void run() {
System.out.println("Running game : " + game);
}
}
그리고 run 메소드를 호출했기 때문에 run메소드도 만들어 준다.
AppGamingBasicJava 클래스에서 코드를 실행시키면
Running game : com.jm.learnspringframework.game.MarioGame@28a418fc
이렇게 출력되는 것을 확인할 수 있다.
package com.jm.learnspringframework.game;
public class MarioGame {
public void up() {
System.out.println("jump");
}
public void down() {
System.out.println("Go into a hole");
}
public void left() {
System.out.println("Go back");
}
public void right() {
System.out.println("Accelerate");
}
}
위, 아래, 왼쪽, 오른쪽 4가지 동작을 수행할 수 있도록 4개의 메소드를 만들어 주었다.
package com.jm.learnspringframework.game;
public class GameRunner {
MarioGame game;
public GameRunner(MarioGame game) {
this.game = game;
}
public void run() {
System.out.println("Running game : " + game);
game.up();
game.down();
game.left();
game.right();
}
}
GameRunner에서 4개의 메소드를 호출하였고,
AppGamingBasicJava 클래스에서 해당 메소드가 잘 실행되는지 확인하였다.
Running game : com.jm.learnspringframework.game.MarioGame@28a418fc
jump
Go into a hole
Go back
Accelerate
위의 코드대로 하면 여러 게임들을 쉽게 바꿀 수 없기 때문에 해당 그림처럼 인터페이스를 추가하여 수정해주어야 한다.
(Tightly Coupled Java Code -> Loose Coupling(Interface))
게임 클래스들이 있는 패키지에 GamingConsole 인터페이스를 생성해준다.
그리고 SuperContraGame클래스도 생성해준다.
GameRunner.java
package com.jm.learnspringframework.game;
public class GameRunner {
private GamingConsole game;
public GameRunner(GamingConsole game) {
this.game = game;
}
public void run() {
System.out.println("Running game : " + game);
game.up();
game.down();
game.left();
game.right();
}
}
GamingConsole.java
package com.jm.learnspringframework.game;
public interface GamingConsole {
void up();
void down();
void left();
void right();
}
MarioGame.java
package com.jm.learnspringframework.game;
public class MarioGame implements GamingConsole{
public void up() {
System.out.println("jump");
}
public void down() {
System.out.println("Go into a hole");
}
public void left() {
System.out.println("Go back");
}
public void right() {
System.out.println("Accelerate");
}
}
SuperContraGame.java
package com.jm.learnspringframework.game;
public class SuperContraGame implements GamingConsole{
public void up() {
System.out.println("up");
}
public void down() {
System.out.println("sit down");
}
public void left() {
System.out.println("Go back");
}
public void right() {
System.out.println("shout a bullet");
}
}
위의 코드들 처럼 수정하게 되면,
package com.jm.learnspringframework;
import com.jm.learnspringframework.game.GameRunner;
import com.jm.learnspringframework.game.MarioGame;
import com.jm.learnspringframework.game.SuperContraGame;
public class AppGamingBasicJava {
public static void main(String[] args) {
var game = new MarioGame();
//var game = new SuperContraGame();
var gameRunner = new GameRunner(game);
gameRunner.run();
}
}
//실행결과
Running game : com.jm.learnspringframework.game.MarioGame@5305068a
jump
Go into a hole
Go back
Accelerate
package com.jm.learnspringframework;
import com.jm.learnspringframework.game.GameRunner;
import com.jm.learnspringframework.game.MarioGame;
import com.jm.learnspringframework.game.SuperContraGame;
public class AppGamingBasicJava {
public static void main(String[] args) {
//var game = new MarioGame();
var game = new SuperContraGame();
var gameRunner = new GameRunner(game);
gameRunner.run();
}
}
//실행결과
Running game : com.jm.learnspringframework.game.SuperContraGame@5305068a
up
sit down
Go back
shout a bullet
AppGamingBaseJava에서 주석처리를 통해 game을 MarioGame으로 바꾸거나, SuperContraGame으로 바꾸어도 정상적으로 작동된다.
이번에는 PacMan을 추가해준다.
PacmanGame 클래스를 추가해준 뒤,
package com.jm.learnspringframework.game;
public class PacmanGame implements GamingConsole{
public void up() {
System.out.println("up");
}
public void down() {
System.out.println("down");
}
public void left() {
System.out.println("left");
}
public void right() {
System.out.println("right");
}
}
다른 게임들과 같은 코드를 넣어준다.
package com.jm.learnspringframework;
import com.jm.learnspringframework.game.GameRunner;
import com.jm.learnspringframework.game.MarioGame;
import com.jm.learnspringframework.game.SuperContraGame;
import com.jm.learnspringframework.game.PacmanGame;
public class AppGamingBasicJava {
public static void main(String[] args) {
//var game = new MarioGame();
//var game = new SuperContraGame();
var game = new PacmanGame();
var gameRunner = new GameRunner(game);
gameRunner.run();
}
}
//실행결과
Running game : com.jm.learnspringframework.game.PacmanGame@5305068a
up
down
left
right
AppGamingBasicJava에서 이제 Pacman을 실행시키기 위해 다른 게임들은 주석처리해주고 pacman 객체를 만들어준다.
그러면 정상적으로 작동되는 것을 확인할 수 있다.
(import 까먹지 말기)
이번에는 Bean으로 spring이 관리할 수 있도록 해볼 것이다.
먼저, AppGamingBasicJava 클래스의 이름을 사진과 같이 변경해준다.
그리고 처음부터 있었던 LearnSpringFrameworkApplication.java 클래스를 삭제해준다.
App01GamingBasicJava 클래스를 복사하여 App02HelloWorldSpring 클래스도 생성해준다.
AnnotationConfig를 고를 땐, ApplicationContext를 골라준다.
HelloWorldConfiguration.java
package com.jm.learnspringframework;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//JDK16에서 새로생긴 기능(record)
//getter, setter와 같은 것들을 안만들어도 됨 (자동으로 생성됨)
record Person(String name, int age) {};
record Address(String Contry, String City) {};
@Configuration
public class HelloWorldConfiguration {
@Bean
public String name() {
return "Ranga";
}
@Bean
public int age() {
return 21;
}
@Bean
public Person person() {
return new Person("Jimin", 20);
}
@Bean(name = "address2")
public Address address() {
return new Address("Korea", "Incheon");
}
}
App02HelloWorldSpring.java
package com.jm.learnspringframework;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App02HelloWorldSpring {
public static void main(String[] args) {
// 1: Spring Context 생성
var context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
// 2: Spring이 관리하는 bean 구성 -
// HelloWorldConfiguration - @Configuration
// name - @Bean
// 3: Bean 호출
System.out.println(context.getBean("name")); //생성한 Bean 이름이 name이다.
System.out.println(context.getBean("age"));
System.out.println(context.getBean("person"));
System.out.println(context.getBean("address2"));
System.out.println(context.getBean(Address.class));
}
}
//실행결과
Ranga
21
Person[name=Jimin, age=20]
Address[Contry=Korea, City=Incheon]
Address[Contry=Korea, City=Incheon]
이번에는 호출을 통해 person2 객체를 만들어 보았다.
package com.jm.learnspringframework;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//JDK16에서 새로생긴 기능(record)
//getter, setter와 같은 것들을 안만들어도 됨 (자동으로 생성됨)
record Person(String name, int age, Address address) {};
record Address(String Contry, String City) {};
@Configuration
public class HelloWorldConfiguration {
@Bean
public String name() {
return "Ranga";
}
@Bean
public int age() {
return 21;
}
@Bean
public Person person() {
return new Person("Jimin", 20, new Address("Korea", "seoul"));
}
@Bean
public Person person2() {
return new Person(name(), age(), address());
}
@Bean(name = "address2")
public Address address() {
return new Address("Korea", "Incheon");
}
}
//실행 결과
Ranga
21
Person[name=Jimin, age=20, address=Address[Contry=Korea, City=seoul]]
Address[Contry=Korea, City=Incheon]
Address[Contry=Korea, City=Incheon]
Person[name=Ranga, age=21, address=Address[Contry=Korea, City=Incheon]]
관리되고 있는 기존 Bean을 이용하여 새로운 Bean을 만들 수 있는 것이다.
이미 존재하는 Bean을 호출하는 것이 아닌 매개변수를 이용하는 방법도 있다.
package com.jm.learnspringframework;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//JDK16에서 새로생긴 기능(record)
//getter, setter와 같은 것들을 안만들어도 됨 (자동으로 생성됨)
record Person(String name, int age, Address address) {};
record Address(String Contry, String City) {};
@Configuration
public class HelloWorldConfiguration {
@Bean
public String name() {
return "Ranga";
}
@Bean
public int age() {
return 21;
}
@Bean
public Person person() {
return new Person("Jimin", 20, new Address("Korea", "seoul"));
}
@Bean
public Person person2MethodCall() {
return new Person(name(), age(), address());
}
@Bean
public Person person3Parameters(String name, int age, Address address2) {//name, age, address2
return new Person(name, age, address2);
}
@Bean(name = "address2")
public Address address() {
return new Address("Korea", "Incheon");
}
}
//실행결과
Ranga
21
Person[name=Jimin, age=20, address=Address[Contry=Korea, City=seoul]]
Address[Contry=Korea, City=Incheon]
Address[Contry=Korea, City=Incheon]
Person[name=Ranga, age=21, address=Address[Contry=Korea, City=Incheon]]
Person[name=Ranga, age=21, address=Address[Contry=Korea, City=Incheon]]
JVM 내부에는 구성한 모든 Bean을 관리하는 스프링 컨텍스트가 있다.
스프링 컨테이너 : spring Bean과 그 lifecycle을 관리하는 컨테이너이다.
2가지 종류가 있음
- Bean Factory : 기본 spring container
- Application Context : 엔터프라이즈 특정 기능을 가진 고급 spring container (위의 코드에서 사용함)
- web application 제작, 국제화 기능, spring AOP 지향 프로그래밍을 위함
bean의 3가지 종류
- Pojo : Plain Old Java Object로 오래된 평범한 java 객체이다. (null:0)
- spring Bean : IOC 컨테이너에서 관리하는 Bean은 모두 Spring Bean이다.
- Java Bean : 클래스가 패키지화 되어야 한다. 등 여러 규약이 있다.
getBeanDefinitionNames를 이용해서 관리되고 있는 Bean들을 출력할 수 있다.
package com.jm.learnspringframework;
import java.util.Arrays;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App02HelloWorldSpring {
public static void main(String[] args) {
// 1: Spring Context 생성
var context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
// 2: Spring이 관리하는 bean 구성 -
// HelloWorldConfiguration - @Configuration
// name - @Bean
// 3: Bean 호출
System.out.println(context.getBean("name")); //생성한 Bean 이름이 name이다.
System.out.println(context.getBean("age"));
System.out.println(context.getBean("person"));
System.out.println(context.getBean("address2"));
System.out.println(context.getBean(Address.class));
System.out.println(context.getBean("person2MethodCall"));
System.out.println(context.getBean("person3Parameters"));
System.out.println("-------------------------------");
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
}
}
//실행 결과
Ranga
21
Person[name=Jimin, age=20, address=Address[Contry=Korea, City=seoul]]
Address[Contry=Korea, City=Incheon]
Address[Contry=Korea, City=Incheon]
Person[name=Ranga, age=21, address=Address[Contry=Korea, City=Incheon]]
Person[name=Ranga, age=21, address=Address[Contry=Korea, City=Incheon]]
-------------------------------
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
helloWorldConfiguration
name
age
person
person2MethodCall
person3Parameters
address2
같은 Bean이 여러개 일때는 예외가 생기게 된다.
여러 개의 Bean 중 하나를 우선순위에 두는 것이 필요하다.
@Bean 어노테이션 밑에 @Primary를 추가해주면 된다.
또, @Bean 어노테이션 밑에 @Qualifier 어노테이션을 추가할 수도 있는데,
같은 타입의 클래스를 구별할 수 있도록 해주는 것이다.
이제 지금까지 했던 HelloWorldConfiguration.java와 App02HelloWorldSpring.java 파일은 새로운 .helloworld 패키지로 이동시켜준다.
현재 context를 보면 이러한 warning이 뜨는 것을 볼 수 있다.
package com.jm.learnspringframework.helloworld;
import java.util.Arrays;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App02HelloWorldSpring {
public static void main(String[] args) {
// 1: Spring Context 생성
try(var context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class)){
// 2: Spring이 관리하는 bean 구성 -
// HelloWorldConfiguration - @Configuration
// name - @Bean
// 3: Bean 호출
System.out.println(context.getBean("name")); //생성한 Bean 이름이 name이다.
System.out.println(context.getBean("age"));
System.out.println(context.getBean("person"));
System.out.println(context.getBean("address2"));
System.out.println(context.getBean(Address.class));
System.out.println(context.getBean("person2MethodCall"));
System.out.println(context.getBean("person3Parameters"));
System.out.println("-------------------------------");
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
}
}
}
이렇게 try문으로 고쳐주면 warning이 없어진다.
이제 게임을 만들던 곳에도 Bean을 생성해 줄 것이다.
App01GamingBasicJava.java 파일을 복붙 해주고 이름은 App02GamingSpringBeans로 해준다.
그리고 같은 패키지에 GamingConfiguration 클래스도 하나 생성해준다.
GamingConfiguration.java
package com.jm.learnspringframework;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.jm.learnspringframework.game.GameRunner;
import com.jm.learnspringframework.game.GamingConsole;
import com.jm.learnspringframework.game.PacmanGame;
@Configuration
public class GamingConfiguration {
@Bean
public GamingConsole game() {
var game = new PacmanGame(); //PacmanGame만 생성해줌.
return game;
}
@Bean
public GameRunner gameRunner(GamingConsole game) {
var gameRunner = new GameRunner(game); //Pacman 게임을 가져와서 GameRunner를 생성해줌
return gameRunner;
}
}
App03GammingSpringBeans.java
package com.jm.learnspringframework;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.jm.learnspringframework.game.GameRunner;
import com.jm.learnspringframework.game.GamingConsole;
public class App03GamingSpringBeans {
public static void main(String[] args) {
try(var context = new AnnotationConfigApplicationContext(GamingConfiguration.class)){
context.getBean(GamingConsole.class).up(); //생성된 Pacman의 up메소드 호출
context.getBean(GameRunner.class).run(); //pacman을 넣어준 gamerunner의 run 메소드를 호출
}
}
}
// 실행결과
up
Running game : com.jm.learnspringframework.game.PacmanGame@10959ece
up
down
left
right
21:25:19.499 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext -- Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@66d33a, started on Thu Jun 15 21:25:19 KST 2023
(다음 게시글은 코드를 더 쉽게하고 더 많은 어노테이션을 공부할 예정..)
'IT > 개발공부' 카테고리의 다른 글
Java 오버로딩, 오버라이딩 정리 (0) | 2023.06.23 |
---|---|
C++ 함수 (함수 정의, 호출, 인수 전달, inline 함수) (0) | 2023.06.20 |
C++ 언어 기초 (2) (흐름제어, 구조체, 클래스, 배열, 포인터, 메모리 할당, 참조) (0) | 2023.06.15 |
C++ 언어 기초(1) (키워드, 식별자, 자료형, 상수, 변수, 연산자) (0) | 2023.06.14 |
C++ 언어의 개요 (처음 C++ 배우기!) (0) | 2023.06.13 |