현재 클래스 100곳에서 CurrentDiscountInfo
클래스의 객체를 쓰던중이었지만, 요구사항이 바뀌면서 RateDiscountInfo
라는 새로운 클래스를 선언하여 기존의 CurrentDiscountInfo
대신 사용해야 한다면, 의존성을 고려하지 않았았으면 CurrentDiscountInfo
를 사용하던 모든 100곳의 클래스에서 RateDiscountInfo
로 변경해주어야 할 것입니다.
Class 클래스{
// DiscountInfo discount = new CurrentDiscountInfo();
// 클래스 100곳 모두 수정
DiscountInfo discount = new RateDiscountInfo();
}
클래스 내부에서 의존하는 객체를 선언하는 것이 아닌, 외부에서 객체를 선언
하여 해당 클래스로 의존 객체를 주입한다면 100
곳 모든 클래스가 아니라 주입시켜주는 부분 1
곳만 수정하면 될 것입니다.
Class 클래스{
DiscountInfo discount;
//의존성 외부 주입
public 생성자(DsicountInfo discount){
this.discount = discount;
}
}
Class Config{ //의존성을 주입해주는 객체
public DiscountInfo discountInfo(){
// return new CurrentDiscountInfo();
//1곳만 수정 -> 100곳 클래스 수정x
return new RateDiscountInfo();
}
}
의존도가 높으면 결합성이 높아지고 캡슐화가 낮아집니다. 객체지향은 낮은 결합성과 높은 캡슐화로 객체간 주는 영향을 줄여야 합니다. 따라서 의존 객체를 외부에서 주입해 줌으로써 의존도를 낮추는 것은 매우 유지보수, 테스트, 에러 수정에서 중요합니다.
Collection Framework
와 비슷하게 ApplicationContext
인터페이스를 구현한 구현체들이 만든 빈 메타 정보를 받는 곳을 스프링 컨테이너
라고 부릅니다.
스프링 컨테이너
는 IoC
개념을 이용하여 Bean객체
로 만들고, 수정하고, 삭제하고, 의존 주입하고, 등등 여러가지 일을 개발자가 아닌 스스로 객체의 생명주기
를 관리합니다.
예전에는 xml
을 통하여 모두 설정 하였었지만, Spring Boot을 사용하면서 거의 사용하지 않고 애너테이션
을 사용합니다.
스프링 컨테이너의 특징은 아래와 같습니다.
Configuration Metadata
를 사용합니다.스프링 컨테이너에게 빈 메타 정보를 전달해주는 객체 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(컨테이너.class);
스프링 컨테이너도 컬렉션 프레임워크와 마찬가지로 인터페이스를 상속 받는 인터페이스가 존재하고 인터페이스를 구현한 구현체가 존재합니다.
최상위
인터페이스 입니다.getBean()
메서드를 통해 빈을 인스턴스화 시킵니다.@Bean
애너테이션이 붙은 메서드를 통해 빈을 등록합니다.BeanFactory
의 기능을 상속받는 인터페이스입니다.BeanFactory
+ @ 부가기능 제공합니다.ApplicationContext
는 인터페이스고 AnnotataionConfigApplicationContext
는 ApplicationContext
를 구현한 구현체중 하나입니다.
스프링 컨테이너가 빈의 생성부터 소멸까지(다르게 설정 가능) 생명주기를 관리합니다.
Bean
은 스프링 컨테이너에 인스턴스화 된 객체
를 의미합니다.
@Configuration
클래스에 @Bean
메서드로 적힌 메서드를 호출해서 설정 메타디이터
에 따라 스프링 컨테이너의 객체로 등록합니다.
//@Configuration의 @Bean메서드들 호출하여 객체를 만듭니다.
ApplicationContext ac = new AnnotationConfigApplicationContext(컨픽.class);
빈객체 b = ac.getBean("메서드명",빈클래스.class); //스프링 컨테이너의 빈객체를 반환합니다.
스프링은 다양한 설정 형식을 BeanDefinition
이라는 추상화 덕북에 지원할 수 있습니다.
Bean은
BeanDefinition(빈 설정 메타정보)
속성에 따라 생성되고 활용하는 방법이 달라지게 됩니다.
빈 1개당 1개의 메타 정보가 생성되며 스프링 컨테이너는 설정 형식이 XML, Java코드인지 모르고 BeanDefninition만 알면 됩니다.
스코프(Scope)
란 어느 범위까지 사용가능할지, 또 언제까지 사용 가능할지를 정의해둔 속성입니다. Bean Definition에 정의된 설정 메타 정보에 따라 Bean객체 각각의 스코프가 정의됩니다.
Bean의 은 여러 범위 중 하나에 배치되도록 정의할 수 있고, 사용자 정의 범위를 생성할 수 도 있습니다.
Scope | Description |
---|---|
singleton | (기본)각 Spring 컨테이너에 대한 단일 객체 인스턴스만 생성합니다. |
prototype | 생성과 의존관계 주입까지만 관여하고 그 이상은 관리하지 않습니다. |
request | 웹 요청이 들어오고 나갈 때 까지 유지는 스코프입니다. |
session | 웹 세션이 생성되고 종료될 때 까지 유지되는 스코프입니다. |
application | 웹 서블릿 컨텍스트(어플리케이션) 범위로 유지 되는 스코프입니다. |
websocket | WebSocket의 라이플 사이클까지 확장합니다. Spring ApplicationContext의 컨텍스트에서만 유효합니다. |
클래스의 인스턴스가 1개 이고 추가 호출시 같은 인스턴스가 반환됩니다.
스프링 컨테이너의 시작과 함께 생성되어 스프링 컨테이너가 종료될때까지 유지되며 공유 인스턴스 하나만 관리하게 됩니다.(싱글톤 빈에 대한 모든 요청은 같은 빈 인스턴스를 반환합니다.)
싱글톤 방식은 여러 클라이언트가 하나의 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 무상태
로 설계해야 합니다.
@Configuration
public class 컨텍스트{
@Bean
public 빈클래스 빈메서드(){
return new 빈클래스();
}
}
@Configuration
: 컨텍스트 클래스임을 명시합니다. 컨텍스트 클래스 내부에 있는 빈 메서드를 실행하여 스프링 컨테이너에서 관리하도록 객체를 생성합니다.@Bean
: 빈 메서드임을 알립니다. 해당 메서드 실행후 생성된 객체들은 스프링 컨테이너에서 관리됩니다.ApplicationContext ac = new AnnotationConfigApplicationContext(컨텍스트.class);
입력시
1. 스프링 컨테이너를 인스턴스화 합니다.
2. @Configuration 클래스 자체가 Bean 정의로 등록되고 클래스 내에서 선언된 @Bean 메서드도 Bean정의로 등록됩니다.
3. @Component 클래스, JSR-330클래스 가 @Autowired, @Inject와 같이 DI메타데이터가 사용되는 것으로 가정합니다.
public interface 인터페이스{
@Bean
빈클래스 빈메서드(){
return new 빈클래스();
}
}
@Configuration
public class 클래스 implements 인터페이스{
}
빈메서드가 존재하는 인터페이스를 구현하여 Configuration 클래스를 정의할 수 도 있습니다.
@Configuration
public class 컨텍스트{
@Bean
public BeanOne beanOne(){
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo(){
return new BeanTwo();
}
}
빈이 서로 의존성을 가질 때, 의존성을 표현하는 것은 다른 Bean 메서드를 호출하는 것 입니다.
@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean(name="ThisIsName")
public DataSource dataSource(){
return new DataSource();
}
}
public static void main(String[] args){
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.clas);
TransferService transferService = ctx.getBean(TransferService.class);
AccountRepository accountRepository = ctx.getBean(AccountRepository.class);
DataSource dataSource = ctx.getBean("ThisIsName");
}
@Import
애너테이션을 사용하여 다른 컨텍스트들의 빈 객체들을 가져올 수 있습니다.
@Import(컨택스트.class)
는 1개의 컨택스트를 참조할 수 있고, @Import({컨텍스트1.class, 컨텍스트2.class, ...})
형식으로 여러개의 컨텍스트들을 동시에 참조할 수 있습니다.
@Import 애너테이션을 사용하여 여러개의 @Configuration 컨텍스트들을 기억하고 생성할 필요없이 하나의 컨텍스트만 처리하면 됩니다.
@Bean 애너테이션에 name
속성을 지정할 수 있습니다. getBean()
등 빈 메서드를 구분할때 메서드명을 입력할 수도 있는데 이 때 name
속성을 지정하여 메서드명을 다른 이름으로 지정이 가능합니다.
(name속성 == 빈메서드명 일때 에러발생 할 수 있으니 다른 이름 지정)
Spring은 유지보수와 확장을 중요시하는 프레임워크입니다. 따라서 DI개념은 Spring에서 많은 중요한 부분을 차지합니다. 오늘은 그중에서도 중요한 컨테이너, 컨텍스트, 빈에 대하여 공부하였습니다. 정말 정말 중요한 부분인것 같습니다.
https://github.com/ds02168/CodeStates_Spring/tree/main/cmarket