1.
웹 애플리케이션을 사용 하지 않고, 간단하게 console 예제 라는 것을 참고 하자.
2.
따라서,
TEST01Application.java 파일의,
@SpringBootApplication 어노테이션과
SpringApplication.run(Test01Application.class, args) 은 주석 처리 하여 예제를 진행 한다.
3.
프로젝트를 잘 생성 하면, 기본 구조는 아래와 같다.
4.
강제성을 부여할 인터페이스를 생성하고 미완성 메서드를 작성 하기.
Phone.java
package test;
public interface Phone {
void call(String name);
// 인터페이스에 달리는 기본 키워드는 아래와 같다.
// 하지만 당연하게 달려있어야 하기 때문에 생략이 가능 하다.
// public : 인터페이스를 구현할 클래스들보다 무조건적으로 접근제어자의 범위가 넓어야 해서 public 이다.
// abstract : 메서드 바디를 가질 수 없는 미완성 메서드가 된다. (== 추상 메서드)
} // Phone interface
Phone 인터페이스와, call 추상 메서드를 작성 했다.
5.
Phone 인터페이스를 구현한 PhoneA 클래스와 PhoneB 클래스를 생성 하기.
PhoneA.java
package test;
public class PhoneA implements Phone {
@Override
public void call(String name) { // 오버라이딩
System.out.println("PhoneA : " + name + "이 (가) 전화 거는중..");
}
} // PhoneA
PhoneB.java
package test;
public class PhoneB implements Phone {
@Override
public void call(String name) { // 오버라이딩
System.out.println("PhoneB : " + name + "이 (가) 전화 거는중..");
}
} // PhoneB
Phone 인터페이스를 구현한 각각의 클래스들은 추상메서드를 반드시 오버라이딩 해야 한다.
6.
스마트폰을 사용 하는 것을 표현하기 위한 설계도를 작성 한다.
설계도 == 클래스
Member 클래스 작성 하기.
DI를 setter 방식과 생성자 방식으로 둘다 실습 하기 위해서,
Member 클래스에,
생성자, setter & getter, toString() 오버라이딩, .. 등등을 작성 한다.
Member. java
package test;
public class Member {
private String name;
private Phone phone;
public Member() {
System.out.println("Member 기본 생성자 호출.");
}
// 생성자 오버로딩
public Member(String name, Phone phone) {
this.name = name;
this.phone = phone;
System.out.println("Member 생성자 호출.");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Member [name=" + name + ", phone=" + phone + "]";
}
public void print() {
this.phone.call(name); // this 키워드는 생략 가능 하다.
}
} // Member
7.
스프링부트는 외부의 설정파일이 아닌,
.xml 파일 설정 대신에 @ 어노테이션 위주로 설정 하는게 특징 이라고 했었다.
따라서 자바에서 Configuration 클래스를 생성 한다.
package test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 설정 클래스
// Configuration : 프로그램의 설정을 저장해두고 환경을 구성하는 데에 사용 하는 파일.
@Configuration // 설정과 관련된 파일이라는것을 명시하는 어노테이션.
public class Config {
@Bean // 스프링이 IoC 컨테이너로 관리하는 객체라는것을 명시하는 어노테이션.
public PhoneA phoneA() {
return new PhoneA();
}
@Bean
public PhoneB phoneB() {
return new PhoneB();
}
@Bean
public Member Member1() { // 생성자 주입
return new Member("Hwanii", new PhoneA());
}
@Bean(name = "apple")
public Member Member2() { // setter 주입
Member Member = new Member();
Member.setName("Yoonjeong");
Member.setPhone(new PhoneA());
return Member;
}
// 같은 타입의 객체를 생성 할 때는, 이름 설정을 해주자. (별도로 하지 않으면 메서드명 (Member2) 이 등록 된다)
} // Config
위의 Configuration 클래스는 줄여서 Config 라고 작성 했고,
프로그램의 설정을 저장해두고 환경을 구성하는 데 사용 한다.
@Configuration 어노테이션으로 설정과 관련된 파일이라는것을 명시 한다.
@Bean 어노테이션을 사용 해서, 스프링 컨테이너가 IoC로 관리하는 객체라는것을 명시 한다.
@Bean 어노테이션을 사용 할 때, 별도로 name 설정을 해주지 않으면,
메서드명이 객체의 이름으로 자동 설정 된다.
즉,
@Bean 어노테이션을 통해 PhoneA와 PhoneB 객체는 스프링 컨테이너가 관리하는 객체가 되며,
PhoneA 를 사용하는 주체인 Member 에게,
생성자 주입과 setter 주입 방식으로 의존 주입을 하도록 작성 했다.
8.
스프링 컨테이너를 구동시키기 위해서,
TEST01Application.java 클래스 에서 실행할 코드를 작성 하기.
package com.hwan.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import test.Config;
import test.Member;
//@SpringBootApplication // 웹 어플리케이션을 사용 할 때 명시하는 어노테이션 이다.
public class Test01Application {
public static void main(String[] args) {
// SpringApplication.run(Test01Application.class, args);
// 1. 스프링 IoC 컨테이너 구동 하기.
// 1-2. 컨테이너를 구동시킬때에 설정 파일이 필요 하다.
// (스프링에서는 .xml / 부트에서는 .java)
ApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
// 컨테이너가 팩토리 패턴을 기반으로 동작 하고 있다.
Member Member1 = (Member) ac.getBean("Member1"); // 다운 캐스팅 (형변환)
Member1.print();
Member Member2 = ac.getBean("apple", Member.class);
Member2.print();
// 2. 싱글톤 유지되는지 확인 하기 !
if(Member1 == Member2) {
System.out.println("둘은 동일한 객체 입니다.");
}
else {
System.out.println("둘은 다른 객체 입니다.");
}
// 부트 방식을 전부 활용 하지 않음.
// 개발자가 직접 new를 작성한 상황.
// 개발자가 Member 객체를 2개 등록 -> (둘은 같은 타입의 객체이므로, 싱글톤 유지가 되지 않는다)
} // main()
} // Test01Application
[ console ]
Member 생성자 호출.
Member 기본 생성자 호출.
PhoneA : Hwanii이 (가) 전화 거는중..
PhoneA : Yoonjeong이 (가) 전화 거는중..
둘은 다른 객체 입니다.