◎ 참고 서적 | Mastering Spring 5
[차이]
Java : 클래스가 다른 클래스에 의존하는 형태, 클래스를 사용하기 위해 인스턴스를 생성할 때 클래스 간에 밀접한 결합이
형성된다.
Spring : 인스턴스 생성 대신 Ioc 컨테이너라는 객체를 생성하고 의존 관계를 연결한다.
[장점]
Spring : Ioc 컨테이너로 연결하기 때문에 클래스 간 결합을 느슨하게 만들고 단위 테스트를 용이하게 만들어준다.
[ 최신 스프링 버전 5.1 에 대해 알아야 할 정보]
스프링 프레임워크 5.1 // JDK 12, JDK 11 // Java 8 이상
[2장 학습에 앞서 필요한 소프트웨어]
- 이클립스
- 자바 8+
- 메이븐 3.x
- 인터넷연결
- BusinessService (인터페이스)
package com.mastering.spring.business;
import com.mastering.spring.beans.User;
public interface BusinessService {
long calculateSum(User user);
}
- BusinessServiceImpl (클래스 implements 인터페이스 할)
package com.mastering.spring.business;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mastering.spring.beans.Data;
import com.mastering.spring.beans.User;
import com.mastering.spring.data.DataService;
@Service
public class BusinessServiceImpl implements BusinessService {
// @Autowired --> 해당 인터페이스
// DataService dataService = new DataServiceImpl()의 인스턴스 생성과 같지만 클래스 결합 정도가 다름
@Autowired
private DataService dataService;
public long calculateSum(User user) {
long sum = 0;
for (Data data : dataService.retrieveData(user)) {
sum += data.getValue();
}
return sum;
}
public void setDataService(DataService dataService) {
this.dataService = dataService;
}
}
- DataService (인터페이스)
package com.mastering.spring.data;
import java.util.List;
import com.mastering.spring.beans.Data;
import com.mastering.spring.beans.User;
public interface DataService {
List<Data> retrieveData(User user);
}
- DataServiceImpl.java (클래스 implements 인터페이스 할)
package com.mastering.spring.data;
import java.util.Arrays;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.mastering.spring.beans.Data;
import com.mastering.spring.beans.User;
//@Repository ==> 데이터베이스에서 데이터를 가져올 때 사용하는 어노테이션
@Repository
public class DataServiceImpl implements DataService {
public List<Data> retrieveData(User user) {
// ArrayList 생성과 동시에 값 선언 하는 법 Data(n)는 setter를 이용한 값 지정
return Arrays.asList(new Data(10), new Data(20));
}
}
[어노테이션]
- @Component : 스프링 IoC 컨테이너에 어떤 빈을 생성해야 하는지 알려줘야 하는 어노테이션
@Component
public Class DataServiceImpl implements DataService ( 여기서 빈은 DataService ) - @Service : 비즈니스 서비스 구성요소에 사용됨 -> DAO 구성요소에서 사용된다.
@Service
public Class BusinessServiceImpl implements BusinessService - @Repository : 데이터베이스에서 데이터를 가져 오는 것과 관련이 있음 --> DataServiceImpl에 사용
@Repository
public cCass DataServiceImpl implements DataService
와이어링
@Service
public class BusinessServiceImpl{
@Autowired
private DataService dataService;
[스프링으로 IoC 컨테이너 생성하는 방법]
1. 빈 팩토리
2. 애플리케이션 컨텍스트
- pom.xml : 메이븐으로 프로젝틀를 빌드하는 과정 (JAR)
<dependency>
<groupId>org.springframework</groupId> ==>> jar 파일을 불러올 패키지
<artifactId>spring-core</artifactId> ==>> jar(라이브러리)명
</dependency>
<?xml version="1.0" encoding="US-ASCII"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mastering.spring</groupId>
<artifactId>Chapter02-Dependency-Injection</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>${project.artifactId}</name>
<properties>
<spring.version>5.1.3.RELEASE</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- Unit Test Dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.0-rc1</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
※중요※
@Autowired를 사용하여 결합도를 낮추려면
스프링 IoC 컨테이너는 빈의 위치를 알고있어야 한다 ==> 컴포넌트 스캔하여 찾을 수 있게 context를 만들어야 한다.
① SpringContext : 컴포넌트 스캔 역할
@Configuration
class SpringContext {
}
② LanchJavaContext : 스캔 지시가 떨어지면 그 후 빈의 클래스명을 지목시킬 부분
public class LaunchJavaContext {
private static final User DUMMY_USER = new User("dummy");
public static Logger logger = Logger.getLogger(LaunchJavaContext.class);
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(
SpringContext.class);
BusinessService service = context.getBean(BusinessService.class);
logger.debug(service.calculateSum(DUMMY_USER));
}
}
즉, ① + ② = 컴포넌트 스캔한 패키지 지정해주면 + 해당 빈 클래스들 찾아와!! ▼▼▼
└─▶ LanchJavaContext 의 완전체
package com.mastering.spring.context;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.mastering.spring.beans.User;
import com.mastering.spring.business.BusinessService;
@Configuration
@ComponentScan(basePackages = { "com.mastering.spring" })
class SpringContext {
}
public class LaunchJavaContext {
private static final User DUMMY_USER = new User("dummy");
// LaunchJavaContext 가 실행되면 로그로 기록 남겨라
public static Logger logger = Logger.getLogger(LaunchJavaContext.class);
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(
SpringContext.class);
BusinessService service = context.getBean(BusinessService.class);
logger.debug(service.calculateSum(DUMMY_USER));
}
}
실행 결과
● 컨테이너 관리 빈
의존 관계를 만드는 클래스 대신, 빈을 생성하고 관리하는 기능을 컨테이너에 위임하면 이로운 점
- 느슨하게 결합되 테스트할 수 있다. ==> 결함 감소
- 컨테이너가 빈을 관리하므로 로깅, 캐싱, 트랜잭션 관리 및 예외 처리와 같은 크로스 컷팅을 AOP를 사용해 빈 중심으로
구성할 수 있다. ==> 유지 보수가 용이
[어노테이션 (@Annotation) 사용 시 특징]
1, 빈을 더 짧고 간단하게 정의할 수 있음
2. 어노테이션을 사용하게 되면 더이상 POJO가 아님.
3. 어노테이션을 사용하면 오토와이어링 문제를 해결하기 어려울 수 있다.
애플리케이션 컨텍스트에 XML 구성 사용
- BusinessApplicationContext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.mastering.spring"/>
</beans>
xmlns:context-"경로" ==> 경로가 스캔할 패키지
이 xml을 사용함으로써
LaunchJavaContext.java 와 다르게
“@Configuration
@ComponentScan(basePackages = { "com.mastering.spring" })
class SpringContext {
}”
파트가 LaunchXmlContext.java 에서는 사라짐
- LaunchXmlContext.java
package com.mastering.spring.context;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.mastering.spring.beans.User;
import com.mastering.spring.business.BusinessService;
public class LaunchXmlContext {
private static final User DUMMY_USER = new User("dummy");
public static Logger logger = Logger.getLogger(LaunchJavaContext.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"BusinessApplicationContext.xml");
BusinessService service = context.getBean(BusinessService.class);
logger.debug(service.calculateSum(DUMMY_USER));
}
}
[@Autowired 어노테이션 종류 from Chapter02]
package com.mastering.spring.context;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Configuration
@ComponentScan(basePackages = { "com.mastering.spring" })
class PrimaryAnnotationSpringContext {
}
interface SortingAlgorithm {
}
@Component
@Qualifier("mergesort")
class MergeSort implements SortingAlgorithm {
// Class code here
}
@Component
@Primary
class QuickSort implements SortingAlgorithm {
// Class code here
}
@Component
class SomeService {
@Autowired
@Qualifier("mergesort")
// SortinAlgorithm은 두군데에서 implements 되지만 @Qualifier("meresort") 라고 지정된 곳의
// 의존관계로 규정된다.
SortingAlgorithm algorithm;
}
public class PrimaryAnnotationJavaContext {
public static Logger logger = Logger
.getLogger(PrimaryAnnotationJavaContext.class);
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(
PrimaryAnnotationSpringContext.class);
SortingAlgorithm algorithm = context.getBean(SortingAlgorithm.class);
logger.debug(algorithm);
SomeService service = context.getBean(SomeService.class);
logger.debug(service.algorithm);
}
}
- @Autowired :
의존 관계에 사용하면 애플리케이션 컨텍스트는 일치하는 의존관계를 검색
오토와이어링된 모든 의존 관계 필요
일치 1항목 존재 -> 와이어링 성공
일치 2항목 존재 -> 와이어링 실패
일치 0항목 존재 -> 와이어링 실패
- 여러 항목 중 하나만 사용하려면 @Primary 어노테이션 사용
- 오토와이어링 강화하려면 @Qualifier 사용
[의존관계 주입 옵션]
- setter 주입
- 생성자 주입
[스프링 빈 스코프 사용자 정의]
스프링 빈은 여러 스코프로 만들 수 있으며 기본 스코프는 '싱글톤'
:: 싱글톤 부터는 다음 시간에 이어서 진행::
'spring framework' 카테고리의 다른 글
스프링 프레임워크 #6 - 모델, 세션, 예외처리 (0) | 2023.09.18 |
---|---|
스프링 프레임워크 #5 Spring MVC 핵심 개념 (RequestMapping, 뷰 리졸버, 핸들러, 인터셉터) (0) | 2023.09.17 |
★스프링 프레임워크 #4 - Chapter03 : Spring MVC 실습, 유효성 검사, 예외 처리, 정규식 등 (0) | 2023.09.14 |
스프링 프레임워크 #3 - Chapter03 : Spring MVC (0) | 2023.09.13 |
스프링 프레임워크 #2 - Chapter02 : 스코프 (0) | 2023.09.12 |