*DI (의존성 주입)
1. Spring BeansContainer 안에서만 수행
2. 때문에 , 의존성 주입을 받고 싶은 모든 객체는 Spring Beans Container에 Bean으로 등록되어 있어야함.
- Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean) 이라고 부릅니다
- 빈즈 컨테이너 주입을 해줘야함 Spring 컨테이너 바깥에서 객체를 요청 할 수 없다.
- OOP를 조금 더 OOP 답게 완성시킬 수 있는 수단
(1) 의존성 주입 시그널을 받고
(2) 시그널대로, 의존성 객체를 생성해서, 의존하는 개체의 필드에 직접 주입(injection)해준다.
위와 같이 , 의존성 객체들 간의 DI(의존성 주입)을 수행해주는
Beans Container의 구현객체의 타입이 정확히는 "ApplicationContext"이다.
OOP 기반으로 클래스 설계시
현실세계의 객체의 모델링하고
클래스로 만들시, 클래스 필드로 나올 수 있는 3가지 종류
(1) 해당 객체의 고유속성
(2) 해당 객체의 실시간 상태
(3) 해당 객체의 부품 => 집합관계(=부품관계)
Spring은 3번에 해당 할 때 new 연산자 대신 주입을 해달라는 신호를 보낸다.
같은 태그라도 네임태그가 다르면 다른태그 (패키지랑 클래스라 생각해라)
<context:component-scan base-package="org.zerock.myapp.domain"/>
<context:component-scan base-package="org.zerock.myapp.car" />
<bean id="chef" class = "org.zerock.myapp.domain.Chef"/>
<bean id="hotel" class = "org.zerock.myapp.domain.Hotel"/>
<bean id="restaurant" class = "org.zerock.myapp.domain.Restaurant"/>
<bean id="avanteCar" class = "org.zerock.myapp.car.AvanteCar"/>
<bean id="engine" class = "org.zerock.myapp.car.Engine"/>
<bean id="handle" class = "org.zerock.myapp.car.Handle"/>
<bean id="tire" class = "org.zerock.myapp.car.Tire"/>
context파일에서 bean을 등록할 때 참고점
-servlet-context 와 root-context에 분할해서 등록했을지라도 설정파일이 실행될때 하나로 통합한다.
-왜 두개로 나눴냐면 관리 차원에서 웹과 관련이 없으면 root에 관련이있으면 servlet에 빈을 통합한다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
<scope>test</scope>
</dependency>
알아본 점
@Log4j2
@NoArgsConstructor
// JUnit 4버전대에서는
//@RunWith(SpringRunner.class) 또는
//@RunWith(SpringJUnit4ClassRunner.class) 사용해준다.
// 테스트 메소드 수행시, 스프링 프레임워크까지 함께 구동되도록 해주는 어노테이션 설정이다.
// For JUnit jupyter v5.x
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations= {
//필요한 스프링 설정파일을 등록해준다. 이때 file:이 사용되는 데, 이 file:의 의미는 프로젝트 폴더와 같다.
"file:src/main/webapp/WEB-INF/spring/root-context.xml"
})
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DITests {
// 이 JUnit 테스트 클래스도, JUnit test framework에 의해서, 구동시
// 기본생성자를 이용하여 객체를 생성하고,
//이 객체는 자동으로 Spring Beans Container의 Bean으로 등록된다.
@Autowired
private Hotel hotel;
@Autowired // 빈즈 컨테이너에 의존성 주입 시그널 전송 -> 주입된다.
private Restaurant restaurant;
@BeforeAll
void beforeAll() {
// Null인지 확인하는 3가지 방법
assertNotNull(this.restaurant);
// Objects.requireNonNull(this.restaurant);
// assert this.restaurant != null ;
log.info("\t+ 1. this. restaurant:{}",this.restaurant);
// ----
// Null인지 확인하는 3가지 방법
assertNotNull(this.hotel);
// Objects.requireNonNull(this.hotel);
// assert this.hotel != null ;
log.info("\t+ 2. this. hotel:{}",this.hotel);
}// beforeAll
@Test
void dummyTest() {;;}
}// end class
- domain 클래스
// 필드의 값이 없으면 생성자만 처리해줘도 자바빈즈의 규약을 지키고 있는 것이다.
@ToString
@NoArgsConstructor // 모든 생성자는 명시적으로 보이게 하라.
// 속성의 값은 컴포넌트의 이름을 정한다.
@Component("hotel") // 관례에 따라, 논리적인 이름은 타입명의 첫문자를 소문자로 해서 작성한다.
public class Hotel {
@Inject // 의존성 주입해주는 어노테이션
@Autowired // 자동으로 의존성 주입을 연결해주는 어노테이션 생성자, 필드, setter 메소드 또는 config 메소드위에 사용가능
//이렇게 사용하는 것이 정석이다 . 필드에 대해 세터메서드가 만들어지고 세터에게 배열로 지정한 모든 어노테이션을 붙여서 처리하라
@Setter(onMethod_= {@Autowired}) // 이 필드에 대한 setter 메소드를 통한 의존성 주입 발생
private Chef cher;
}// end class
-자바빈즈 규약에 의해 주입된 객체는 일정한 주소값에서 사용된다는 것을 볼 수 있다.
-beansContainer의 객체를 받고 출력해본다. > GenericApplicationContext@~~~
-beansContainer의 객체의 메서드를 확인 ↓결과
@Log4j2
@NoArgsConstructor
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations= {
//필요한 스프링 설정파일을 등록해준다. 이때 file:이 사용되는 데, 이 file:의 의미는 프로젝트 폴더와 같다.
"file:src/main/webapp/WEB-INF/spring/root-context.xml"
})
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DITestsForAvanteCar {
@Autowired
private AvanteCar car;
@Autowired
private AvanteCar car2;
// Spring Beans Container 를 주입해달라!
@Autowired
private ApplicationContext beansContainer;
@BeforeAll
void beforeAll() {
Objects.requireNonNull(this.car);
Objects.requireNonNull(this.car2);
Objects.requireNonNull(this.beansContainer);
log.info("\t+ . this. car:{}",this.car);
log.info("\t+ . this. car2:{}",this.car2);
log.info("\t+ . this. beansContainer:{}",this.beansContainer);
}// beforeAll
@Test
void dummyTest() {
int beanCount = beansContainer.getBeanDefinitionCount(); // 빈즈 컨테이너에서 등록된 클래스 개수
String[] beanNames = beansContainer.getBeanDefinitionNames(); // 등록되어 있는 클래스 목록
log.info("빈즈내에서 클래스 개수 : {}",beanCount);
log.info("빈즈내에서 클래스 목록 : {}",Arrays.toString(beanNames));
}// dummyTest
}// end class
- domain 클래스
@ToString
@NoArgsConstructor
@Component // 빈즈컨테이너 안으로 넣는 어노테이션
public class AvanteCar {
//1. 고유한 속성
private String model = "AVANTE 2022";
private String color = "WHITE";
private Double price = 300000000.0;
//2. 실시간 변하는 상태
private int speed = 0;
//3. 구성부품(= 집합관계)
@Autowired private Engine engine;
@Autowired private Handle handel;
@Autowired private Tire tire;
}//end class
사진속 위에 setter로 명시해주는 방법이 보편적이다.
hikariCP란 무엇인가 (DBCD와 myBatis 등 대체가능할 수 있는 connection pool이 있다.)
-> DataSource를 구현한 구현 라이브러리다
->영속성계층에서 데이터베이스와 응용서버의 연결고리다.
- DataSource = 하나의 connection pool 을 제공하는 하나의 규격이다. (자바 문서에 interface 설명 정리되어있음)
- 툴과 관련된 기능에대한 설정은 hikariConfig 태그에 있다
- hikariConfig
-말그대로 connection pool 구성파일 config에 대한 설정
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<description>HikariCP Configuration</description>
<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:@db202281319_high?TNS_ADMIN=C:/opt/OracleCloudWallet/ATP"/>
<property name="username" value="HR"/>
<property name="password" value="Oracle1234342678"/>
<property name="maximumPoolSize" value="10"/>
<property name="minimumIdle" value="2"/>
<property name="idleTimeout" value="10000"/>
<property name="connectionTimeout" value="1000"/>
<property name="connectionTestQuery" value="SELECT 1 FROM dual"/>
<property name="dataSourceJNDI" value="jdbc/HikariCP"/> <!-- lookup 즉 참고하기위해 등록하는 속성 -->
<property name="poolName" value="*** HikariDataSource ***"/> <!-- log찍어낼 때 위해 만든 개인적으로 속성 -->
</bean>
- hikariDataSource
-config, 구성한 객체를 주입한다.
<!-- 자원객체가 파괴될때 알아서 close함 -->
<bean id="hikariDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<description>HikariCP DataSource</description>
<!-- hikariConfig 이라는 객체를 이 안에다가 집어넣어라라는 의존성 주입 -->
<constructor-arg ref="hikariConfig"/>
</bean>
빈등록 후 결과