자바 플랫폼을 위한 오픈소스 어플리케이션 프레임워크. 동적인 웹사이트 개발을 위한 여러 가지 서비스를 제공.
제어의 역전. 프레임워크에 제어의 권한을 넘김으로써 클라이언트 코드가 신경 써야 할 것을 줄이는 전략. 객체의 생명 주기를 관리하고 의존성 주입을 통해 각 계층 간의 의존성을 낮춰줌.
// 일반적인 의존성에 대한 제어권: 내가 사용할 의존성은 내가 만듦
class OwnerController{
private OwnerRepository repository = new OwnerRepository();
}
// IoC: 내가 사용할 의존성의 타입(또는 인터페이스)만 맞으면 어떤거든 상관 없다
// 스프링에서 OwnerRepository 타입의 빈을 찾아서 의존성 주입해줌
class OnwerController{
private OwnerRepository repo;
public OwnerController(OwnerRepository repo){
this.repo = repo;
}
}
어떤 클래스가 최초 한번만 메모리를 할당하고 그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴. 최초 생성 이후에 호출된 생성자는 최초에 생성한 객체를 반환한다. 메모리 낭비를 방지하기 위해 씀. Thread-safe 하기 위해 stateless 여야함.
스프링에 등록된 자바 객체. 스프링 컨테이너에 등록해 관리되는 객체
빈으로 등록하는 법
Component Scanning
Annotation 프로세서 중에 스프링 IoC 컨테이너를 만들고 빈을 등록할때 사용하는 여러가지 인터페이스들이 있는데, 이 인터페이스들을 life cycle callback이라고 부름. 그 중에는 Component annotation이 붙어있는 모든 클래스를 찾아서 이 클래스의 인스턴스를 만들어서 bean으로 등록하는 이런 복잡한 일을 하는 Annotation processor가 등록되어 있음.
ComponentScan Annotation이 붙은 위치에서부터 그 하위 패키지 모든 클래스에서 Component가 붙은 클래스들을 모두 스캔해서 빈으로 등록한다.
@Component
repository는 특별하게 jpa가 제공해주는 기능에 의해서 빈으로 등록됨. 특정한 인터페이스를 상속받은 경우에, 이 인터페이스를 상속받고 있는 클래스를 찾아서 이 인터페이스의 구현체를 만들어서 빈으로 등록하는 복잡한 과정이 일어남??
직접 일일히 XML 이나 자바 설정 파일에 등록
자바 설정 파일 예시 - 리턴하는 객체를 직접 빈으로 등록
@Configuration
public class SampleConfig{
@Bean
public SampleController sampleController(){
return new SampleController();
}
}
빈 꺼내쓰는 법
@Autowired / @Inject 사용해서 주입
ApplicationContext에서 getBean()으로 직접 꺼낼수도 있음
public void testDI(){
SampleController bean = applicationContext.getBean(SampleController.class);
}
ApplicationContext > bean container(BeanFactory)
주입을 이용하여 객체를 관리하는 컨테이너. 빈의 생성과 관계 사용, 생명 주기 등을 관장함. (빈을 만들고 빈들 사이의 의존성을 엮어주고 컨테이너가 가지고 있는 빈을 제공해주는 역할을 함)컨테이너를 통해 시스템 전반에서 언제든 사용 가능하다. 요즘은 xml 파일로 관리 안하고 configuration 클래스를 만듬
class안에 다른 class 선언하고 의존성 주입해줌. 객체 종류로는 controller, service, repository, datasource 등이 있음
@Autowired / @Inject 를 통해 의존성을 주입할 수 있음
생성자(권장) - Spring 4.3부터는 생성자에는 @Autowired 생략해도 인자로 받는 객체가 빈 등록되어 있으면 알아서 주입해줌
class OnwerController {
private OwnerRepository owners;
@Autowired
public OwnerController(OwnerRepository clinicService) {
this.owners = clinicService;
}
}
필드
class OnwerController {
@Autowired
private OwnerRepository owners;
}
Setter
class OnwerController {
private OwnerRepository owners;
@Autowired
public void setOwners(OwnerRepository owners){
this.owners = owners;
}
}
여러 곳에서 공통적으로 쓰이는 기능들을 분리하여 Aspect로 모듈화 하고, 핵심적인 비즈니스 로직에서 재사용 하는 프로그래밍 모델. annotation 이용해서 시점을 파악.
AOP 구현 방법
컴파일 시에 A.class가 되기 전 중간에 필요한 기능을 끼워주는(?) 컴파일러 사용(AspectJ에서 제공하는 컴파일러가 있음)
바이트코드 조작 - A.class 를 클래스 로더가 읽어와 메모리에 올릴때 조작(클래스 로더에 옵션을 붙여 바이트 코드를 조작)
프록시 패턴(스프링 AOP가 사용하는 방법으로 디자인 패턴을 사용해서 AOP와 같은 효과를 냄)
스프링에서는 애노테이션을 이용해서 프록시 패턴 기반으로 AOP 적용할 수 있도록 기능을 제공함. (스프링 내부적으로 프록시 만들고 주입해주는 등의 처리를 자동으로 해줌)
AOP 예제(스프링이 제공하는 애노테이션을 이용한 프록시 패턴 기반의 AOP)
@LogExecutionTime 애노테이션
@Target(ElementType.METHOD) //메서드에 쓴다는 뜻
@Retention(RetentionPolicy.RUNTIME) //런타임까지 유지한다는 뜻
public @interface LogExecutionTime {
}
실제 Aspect(@LogExecutionTime 애노테이션을 읽어서 실제 기능을 동작하게 하는 Aspect)
@Component
@Aspect
public class LogAspect {
Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object proceed = joinPoint.proceed();
stopWatch.stop();
logger.info(stopWatch.prettyPrint());
return proceed;
//joinPoint를 실행하고 그 결과를 그대로 리턴하되, 그 앞뒤로 시간을 측정하는 기능을 추가함
}
}
추상화 계층을 사용하여 어떤 기술을 내부에 숨기고 개발자에게 편의성을 제공해주는 것이 서비스 추상화(Service Abstraction) 라고 한다. 이 Service Abstraction으로 제공되는 기술을 다른 기술 스택으로 간편하게 바꿀 수 있는 확장성을 갖고 있는 것이 PSA(Portable Service Abstraction)이다. 스프링에서는 Spring Web MVC, Spring Transaction, Spring Cache 등의 다양한 PSA를 제공한다.
Model View Controller. 사용자가 Controller에 요청 보내면, Controller는 Model을 통해서 데이터를 가져오고, 그 정보를 바탕으로 View를 제어해서 사용자에게 전달하는 패턴. 컨트롤러는 비즈니스 로직과 모델의 상호동작 조정 역할을 한다.
DispatcherServlet: Spring MVC의 핵심 요소인데, Front Controller 역할을 하며 요청이 들어왔을때 어떤 컨트롤러가 요청을 처리해야 하는지 앞단에서 mapping.
servlet: 웹 프로그래밍에서 클라이언트의 요청을 처리하고 그 결과를 다시 클라이언트에게 정송하는 Servlet 클래스의 구현 규칙을 지킨 자바 프로그래밍 기술. 즉, 자바에서 웹을 만들기 위해 필요한 기술. 각각의 controller를 servlet이라고 보면 됨. 스프링에서는 servlet이 다 추상화되어 controller를 만들어 자동으로 처리됨.
소스코드에 메타데이터를 표현하는 것. reflection을 이용해서 부가적인 기능이 있음.
구체적인 클래스 타입을 정적인 타이밍에는 알지 못해도, 그 클래스의 메소드, 타입, 변수들을 접근할 수 있도록 해주는 자바 API. 코드를 작성할 시점에는 어떤 타입의 클래스를 사용할지 모르는 경우, 런타임에 동적 바인딩을 위해서 제공되는 기능. Spring에서는 DI에 Reflection이 사용됨.(@Autowired). 런타임 시에 개발자가 등록한 빈을 애플리케이션에서 가져와 사용할 수 있음.
@Bean: Spring Container에 Bean을 등록하는 메타데이터. 메소드에만 적용. 그 메소드에서 반환하는 객체가 bean으로 등록됨. 개발자가 직접 제어가 불가능한 외부 라이브러리 등을 Bean으로 만들려고 할 때 사용됨. 프로퍼티를 메소드를 통해서 설정한 후 bean으로 등록하는 경우. (프로퍼티가 설정 돼있냐 마냐)
@Component: Spring Container에 Bean을 등록하는 메타데이터. 클래스에만 적용. 개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 어노테이션. static한 경우.
@ComponentScan: 특정 패키지 안에 @Component와 @Service, @Repository, @Controller, @Configuration이 붙은 클래스 Bean들을 찾아서 Context에 bean등록을 해주는 Annotation
@Autowired: 각 상황에 맞게 IoC컨테이너 안에 존재하는 Bean을 자동으로 주입하게 하는 annotation
@Controller : component의 구체화된 역할. API랑 view 둘다 사용하는 경우. Spring Container에 Bean을 등록하는 메타데이터. 내부는 기본적으로 Component인데, 특정하게 Controller로 등록하는 annotation
@RestController
@RequestMapping: 요청에 대해서 적절한 controller와 매핑하기 위한 annotation. 변수 : url + http 메소드도 적음. 클래스에 붙으면 그 안에 있는 모든 메소드에 요청의 공통된 값이 prefix로 붙음
@Service : @Service, @Repository, @Configuration은 모두 bean 등록을 위한 annotation. 가독성 등 용도 구분하려고 만듬. 그 중에서 Service는 비즈니스 로직을 맡은 클래스를 bean 등록하기 위함 (비즈니스 로직: 업무에 필요한 데이터 처리를 위한 로직. 보이는 것의 뒤에서 일어나는 각종 처리)
@Repository: db와 관련된 클래스에 붙임. 여기서 일어나는 exception(오류)가 발생하면 db와 관련된 오류라고 번역해서 주는 역할을 함.
@Configuration : @Configuration으로 정의된 클래스는 @Bean으로 정의된 메소드들을 포함