93일차 Spring DI

쿠우·2022년 8월 11일
0

의존성 주입 (Dependency Identity)

*DI (의존성 주입)
1. Spring BeansContainer 안에서만 수행
2. 때문에 , 의존성 주입을 받고 싶은 모든 객체는 Spring Beans Container에 Bean으로 등록되어 있어야함.

  • Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean) 이라고 부릅니다
  • 빈즈 컨테이너 주입을 해줘야함 Spring 컨테이너 바깥에서 객체를 요청 할 수 없다.
  • OOP를 조금 더 OOP 답게 완성시킬 수 있는 수단

Spring Beans Container

(1) 의존성 주입 시그널을 받고
(2) 시그널대로, 의존성 객체를 생성해서, 의존하는 개체의 필드에 직접 주입(injection)해준다.

위와 같이 , 의존성 객체들 간의 DI(의존성 주입)을 수행해주는
Beans Container의 구현객체의 타입이 정확히는 "ApplicationContext"이다.

OOP 기반으로 클래스 설계시
현실세계의 객체의 모델링하고
클래스로 만들시, 클래스 필드로 나올 수 있는 3가지 종류
(1) 해당 객체의 고유속성
(2) 해당 객체의 실시간 상태
(3) 해당 객체의 부품 => 집합관계(=부품관계)

Spring은 3번에 해당 할 때 new 연산자 대신 주입을 해달라는 신호를 보낸다.

-네임스페이스는 태그들의 모음의 공간

같은 태그라도 네임태그가 다르면 다른태그 (패키지랑 클래스라 생각해라)


-빈을 등록하는 2가지 방법 (Beans 그래프에서 확인가능 )

- 빈즈에 component -scan 태그를 사용하면

	<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에 빈을 통합한다.


-Spring test를 위해 메이븐에 추가해줘야하는 부분

		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-test</artifactId>
		    <version>${org.springframework-version}</version>
		    <scope>test</scope>
		</dependency>

- DI를 확인하기 위한 테스트와 어노테이션에 대한 예제

알아본 점

  • @Component -> 빈으로 연결하기 위한 어노테이션/ 빈 컨테이너의 하나의 조각으로 만든다.
  • @Autowired -> 자동 주입!
  • @inject -> 주입!
  • 사용 할때 @ExtendWith(SpringExtension.class) 로 spring테스트 사용
  • @ContextConfiguration 을 통해서 root-context 설정파일을 등록해준다.
  • spring 프레임워크가 작동이 되어야 테스트 할 수 있기 때문에 위 어노테이션을 통해 root파일을 설정해줌
@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

- DI 테스트 beansContainer에 대한 예제

-자바빈즈 규약에 의해 주입된 객체는 일정한 주소값에서 사용된다는 것을 볼 수 있다.

-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



Spring 의존성 주입의 2가지 방법

  1. 생성자를 통해 주입
  2. setter를 통해 주입
    (매개변수로 주면 주입이 안된다.)

    사진속 위에 setter로 명시해주는 방법이 보편적이다.


- 오라클 DB와 Spring 프로젝트 연결이 가능한지 설정한다.

- hikariCP maven에서 추가 해준다.

hikariCP란 무엇인가 (DBCD와 myBatis 등 대체가능할 수 있는 connection pool이 있다.)
-> DataSource를 구현한 구현 라이브러리다
->영속성계층에서 데이터베이스와 응용서버의 연결고리다.

  • DataSource = 하나의 connection pool 을 제공하는 하나의 규격이다. (자바 문서에 interface 설명 정리되어있음)
  • 툴과 관련된 기능에대한 설정은 hikariConfig 태그에 있다

root-context에 추가해준 hokariCP

- 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>

빈등록 후 결과

profile
일단 흐자

0개의 댓글