본문 바로가기
스터디정리방

[기록] 220126

by gogumi 2022. 2. 3.

1. 스프링이란 무엇인가

: 자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크.

 

경량화

-스프링 자체가 가볍거나 작은 규모의 코드로 이루어진 것은 아니다.

-오히려 스프링은 20여개의 모듈로 세분화되고 복잡하고 방대한 코드를 가진 프레임워크이다.

-경량화가 특징인 이유는 기존 자바 엔터프라이즈 기술의 불필요한 복잡함에 반대되는 개념에서 시작되었다.

-주류 기술이었던 EJB는 고가의 무거운 자바 서버(WAS)가 필요했고, 다루기 힘든 설정파일 구조, 패키징, 불편한 배포 등이 단점이었다.

-반면, 스프링은 톰캣과 같은 단순한 서버환경에서도 동작하며, 단순한 개발환경으로도 엔터프라이즈 애플리케이션 개발하는데 충분하다.

-또 EJB 등의 기존 프레임워크에서 만들어진 코드에 비해 코드량이 적고 단순하기도 하다.

-즉, 기존에 비해 빠르고 간편하게 애플리케이션을 개발할 수 있어 생산성이 뛰어난 프레임워크다.

 

스프링 기능

-경량 컨테이너로서 자바 객체를 직접 관리
-> 각각의 객체 생성, 소멸과 같은 라이프 사이클을 관리하며 스프링으로부터 필요한 객체를 얻어올 수 있다.

-POJO(Plain Old Java Object) 방식의 프레임워크 ->일반적인 J2EE 프레임워크에 비해 구현을 위해 특정한 인터페이스를 구현하거나 상속을 받을 필요가 없어 기존에 존재하는 라이브러리 등을 지원하기에 용이하고 객체가 가볍다.

-제어 반전(또는 제어의 역전)(IoC: Inversion of Control)을 지원
->컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어서 필요에 따라 스프링에서 사용자의 코드를 호출한다.

-의존성 주입(DI: Dependency Injection)을 지원
->각각의 계층이나 서비스들 간에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.

-관점 지향 프로그래밍(AOP: Aspect-Oriented Programming)을 지원
->트랙잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리할 수 있다.

-확장성이 높음
->스프링 프레임워크에 통합하기 위해 간단하게 기존 라이브러리를 감싸는 정도로 스프링에서 사용이 가능하다.
->수많은 라이브러리가 이미 스프링에서 지원되고 있고 스프링에서 사용되는 라이브러리를 별도로 분리하기도 용이하다.

-다른 프레임워크들의 통합

-오픈소스
-> 스프링은 아파치 라이선스 2.0을 따르므로 무료이다.

2. SpringBootApplication Annotation 분석

-SpringdatademoApplication.java

@SpringBootApplication
public class SpringdatademoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringdatademoApplication.class, args);
    }
}

-SpringBootApplication.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    Class<?>[] exclude() default {};

    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    String[] excludeName() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    String[] scanBasePackages() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    Class<?>[] scanBasePackageClasses() default {};

    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "nameGenerator"
    )
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

 

*중요 어노테이션 -> @ComponentScan, @EnableAutoConfiguration
( 왜냐하면 Bean이 @ComponentScan과 @EnableAutoConfiguration에 의해 두 단계로 나눠서 읽히기 떄문 )

@ComponentScan

@Configuration, @Repository, @Controller, @Service, @RestController
위 어노테이션을 포함하는 모든 클래스를 찾아서 Bean으로 등록해준다.

@EnableAutoConfiguration

Spring의 META-INF 파일을 읽어들인다.
META-INF 아래 spring.factories 파일이 존재하는데 org.springframework.boot.autoconfigure.EnableAutoConfiguration 를 키값으로 하는 모든 설정을 가져온다.
실제로 전부 다 가져오는게 아니고 @ConditionalOn~~ 조건에 따라 다르다.

 

즉, ComponentScan은 안에 해당되는 어노테이션에 대한 설정을 Bean으로 등록하여 사용 가능하게 해주고 EnableAutoConfiguration은 환경 설정에 필요한 자동 설정을 Bean으로 등록해준다.

따라서 EnableAutoConfiguration에 있는 설정을 사용하지 않을 것이라면 사용하지 않고 @Configuration, @ComponentScan 만으로도 구동이 가능하다.

 

3. POJO (Plain Old Java Object)

스프링 프레임워크는 IoC 컨테이너 안에서 POJO를 구성하고 관리하는 것이 가장 핵심이고, POJO를 매우 잘 다루는 프레임워크다. POJO 프로그래밍이 가능하도록 기술적인 기반을 제공하는 프레임워크를 POJO 프레임워크라고 하는데, 스프링과 하이버네이트가 대표적인 POJO 프레임워크라고 할 수 있다.

POJO (Plain Old Java Object)

말 그대로 해석하면 오래된 방식의 간단한 자바 오브젝트

JLS(Java Language Specification)에 의해 강제된 것 이외의 제한에 의존하지 않는 자바 오브젝트,

특정 환경과 규약에 종속되지 않고 재사용될 수 있는 방식으로 설계된 오브젝트이며, 객체지향적 원칙을 지향하는 것을 POJO라고 할 수 있다.

1. 특정 규약에 종속되지 않음

2. 특정 환경에 종속되지 않음

3. 단일 책임 원칙(SRP)을 지키는 클래스

 

POJO를 지향해야 하는 이유

스프링 프레임워크 이전에는 엔터프라이즈 기술을 직접 의존하는 객체를 설계했다. 그래서 결합도가 높아지고 응집성이 낮아져 유지보수가 어려워졌다. , 객체 지향을 추구하는 자바가 객체지향 설계의 장점들을 잃어버리게 되었고, 그래서 POJO라는 개념이 등장했다.
POJO
를 지향하게 되면 객체지향 설계의 장점을 얻을 수 있다.

 

그럼에도 특정 기술을 사용해야 하는 경우

특정 기술에 종속적이면 POJO가 아니기 때문에 스프링에는 표준 인터페이스가 준비되어 있다.

예를 들어 자바 객체와 데이터베이스를 연결하기 위해 JPA라는 표준 인터페이스를 정해 두었고, 이와 관련된 여러 프레임워크들은 이 JPA라는 표준 인터페이스 아래 구현되어 실행되는 것이다.

이렇게 사용하고자 하는 기술과 환경의 변화와 관계없이 일관된 방식의 기술 접근 환경을 제공하는 추상화 구조인 PSA를 활용한다.

4. Spring에 적용된 디자인 패턴 파해쳐보기

스프링을 학습하면서 디자인 패턴을 익혔지만 막상 누군가가 xxx 패턴은 스프링에 어디에 적용되어 있을까요!? 라는 질문을 한다면 자신있게 대답하기 위해 정리한 내용입니다.


🔍 프록시 패턴

프록시 패턴은 어떤 객체에 대한 접근을 제어하기 위한 목적으로 쓰이며, 실제 객체 메소드를 호출하면 중간에서 호출을 가로채는 패턴을 말합니다.

Spring AOP(Aspect Oriented Programming)

스프링에서 프록시 패턴이 적용된 부분입니다. AOP 는 관점 지향 프로그래밍으로 핵심 기능과 부가 기능을 분리시켜 하나의 관점으로 만들어 이를 재사용하는 방식입니다.


🔍 싱글턴 패턴

애플리케이션이 실행할 때 최초 한번만 메모리를 할당하고 그 메모리에 인스턴스를 만들어 사용하는 디자인 패턴입니다. 커넥션 풀, 스레드 풀, 디바이스 설정 객체 등과 같은 경우 인스턴스를 여러 개 만들게 되면 불필요한 자원을 사용하게 되고 이런 연결은 비용이 많이 들기 때문에 인스턴스 하나만 만들고 그것을 계속해서 재사용합니다.

즉, 실제로 생성되는 객체는 하나이고, 최초 생성 이후에 호출된 생성자는 생성한 객체를 반환합니다.

스프링에서는 애플리케이션이 실행할 때 스프링 컨테이너가 관리하는 빈을 생성하고 한 번 생성된 빈은 최초 한 번만 메모리를 할당하고 스프링 컨테이너 안에서 등록된 이 빈을 호출할 때마다 같은 인스턴스를 반환합니다.


🔍 템플릿 메소드 패턴

템플릿 메소드 패턴은 이름 그대로 템플릿을 사용하는 패턴입니다. 템플릿은 기준이 되는 거대한 틀로 변하지 않는 부분을 템플릿이라는 틀에 모아둡니다. 그리고 일부 변하는 부분을 별도로 호출하여 해결합니다.

DispatcherServlet

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {

	...생략

	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
	
			... 생략

			try {
				doService(request, response); // doService 호출
			}
			catch (ServletException | IOException ex) {
				failureCause = ex;
				throw ex;
			}
			... 생략
	}

	...
	// doService는 추상 메소드 --> 하위 클래스에게 구현을 위임 (DispatcherServlet 에게 위임)
	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
				throws Exception;
}

스프링에서는 DispatcherServlet에서 템플릿 메소드 패턴이 사용되고 있습니다.

DispatcherServlet의 doService() 메소드는 http 요청에 대해 처리하는 메소드입니다. DispatcherServlet은 FrameworkServlet의 상속을 받은 클래스입니다. FrameworkServlet의 processRequest() 메소드 안에선 doService()를 템플릿 메소드 패턴을 이용해 호출하게 되는데 이 doService()는 추상 메소드로 정의되어 있어 하위 클래스인 DisparcherServlet에서 오버라이딩 된 doService()를 호출하게 됩니다.

즉, FrameworkServlet이 커다란 틀인 템플릿이 되는 것이고, 변경되는 부분을 추상 메소드로 정의함으로써 하위 클래스인 DisparcherServlet에서 구현하여 사용하는 방식을 적용하고 있습니다.

JDBCTemplate

먼저 JDBC(Java DataBase Connectivity : Java에서 데이터 베이스에 접속할 수 있도록 해주는 Java API)를 통해 DB 연결을 할 때의 순서는 다음과 같습니다.

  1. 드라이버 로딩
  2. 데이터 베이스를 연결
  3. 쿼리 실행
  4. 커넥션 해제
public class DBConnection {	// DB 연결 클래스 
	public static Connection getConnection() throws ClassNotFoundException {
		**// 드라이버 로딩** 
		Class.forName("com.mysql.cj.jdbc.Driver");	

		Connection conn = null;
		try {
			//자신의 DB 정보에 맞는 user와 pw 설정 
			String user = "user"; 	
			String pw = "pw";
			String url = "jdbc:mysql://localhost:3306/project?serverTimezone=Asia/Seoul&characterEncoding=utf8";
			**// DB 연결** 
			conn = DriverManager.getConnection(url, user, pw);
		} catch (SQLException sqle) {
			System.out.println("DB error : " + sqle.toString());
		} catch (Exception e) {
			System.out.println("Unkonwn error");
		}
		return conn;
	}
}

🔍 팩토리 메소드 패턴(Factory Method Pattern)

팩토리 메소드 패턴이란 객체 생성 처리를 서브 클래스로 분리하여 처리하도록 캡슐화 패턴이다.즉, 객체의 생성 코드를 별도의 클래스/메서드로 분리함으로써 객체 생성의 변화에 대비하여 유용하게 사용할 수 있습니다.

팩토리 패턴의 장점

  • 비슷한 성격의 객체를 인터페이스를 통해 하나로 관리할 수 있다.
  • 협업시 공통코드를 건드리는 일이 없이 업무를 진행할 수 있다.
  • 추수 비슷한 유형의 객체가 생성되어도 implement를 통해 쉽게 추가할 수 있다.

팩토리 메소드 패턴 사용 방법

  1. 요구사항을 담을 interface 정의
  2. interface를 상속받아 구현하는 Class 정의
  3. 파라미터에 따라 구현한 Class 객체를 반환해주는 Factory Class 정의
  4. Factory Class를 통해 객체를 받아 사용

🔍 전략 패턴 (Strategy Pattern)

템플릿 메소드 패턴과 유사하지만 상속이 아닌 인터페이스로 정의함으로써 상속의 단점을 보완한 패턴입니다. 전략을 생성해 전략을 실행할 Context(문맥)에 주입합니다.

템플릿 콜백 패턴은 전략 패턴의 전략에 해당하는 부분을 익명 내부 클래스 또는 람다로 구현하여 인자로 넘겨주는 패턴을 말합니다. 스프링에서만 불리는 패턴으로 스프링에서 제공하는 template 은 대부분 템플릿 콜백 패턴을 사용


그 외의 패턴

프론트 컨트롤러(Front Controller)

모든 리소스(Resource)의 요청을 하나의 대표 컨트롤러(Controller)로 처리하는 패턴으로 스프링은 DispatcherServlet이 처음 HTTP 모든 요청을 받고, HandlerMapper를 통해 요청을 처리할 Controller를 반환받아 다시 DispatcherServlet이 Controller에 요청을 보낸 후 작업을 처리한 후, DispatcherServlet이 다시 그 결과를 ViewResolver에 넘겨 보여줄 화면(Html, jsp)을 반환받아 해당 View를 보여주게 된다.

즉, 스프링은 DispatcherServlet이라는 프론트 컨트롤러로 제일 앞에서 서버로 들어오는 모든 요청을 처리합니다. 모든 들어오는 요청은 하나의 서블릿(DispatcherServlet)을 거쳐 해당 서블릿 내부에서 요청 라우팅을 하여 분배하는 형태입니다.

MVC 패턴(Model View Controller Pattern)

Model, View, Controller를 분리한 디자인 패턴으로 Controller를 통해 요청을 받고, 업무 로직(Service), 데이터 처리(DAO)는 다른 클래스로 처리하고, 다시 결과 데이터를 Model에 담아 Controller에서 사용자에게 보여줄 화면을 반환하여 해당 jsp로 View를 보여주는 형식을 사용합니다.

이런 업무로직을 Controller나 View 페이지에서 처리하지 않고 Service 클래스를 만들어 처리하는 것은 아래 View Helper Pattern 과도 연관이 있다.

뷰 헬퍼(View Helper)

View에서 제어 로직, 데이터 액세스, 화면 구성 등을 모두 넣는 것이 아닌, View는 단순히 클라이언트에게 정보를 보여주는 역할, Controller는 View와 Model을 연결해주는 역할, helper는 View에서 사용할 데이터 모델을 적용하는 것을 포함하여 데이터를 가공하는 역할을 한다.

Spring에서는 보통 View(jsp), Controller(controller), Service(helper), DAO(helper)로 업무 로직과 데이터 액세스 로직을 나누어 Service, DAO 클래스를 헬퍼로 지정하는 방식을 사용한다.

5. POJO

"POJO" 는 주로 Java 모델이나 기능,  프레임워크를 따르지 않는 Java 오브젝트를 말한다.

아래와 같이 가장 기본적인 형태의 java 객체를 POJO라 한다.

public class MyPojo {
    private String name; 
    private int age; 
    
    public String getName() { 
        return name; 
    } 
    public String getAge() {
        return age;
    } 
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age; 
    } 
}

POJO는 Java 언어 규약에 의해 강제된 것 이외의 제한에 구속되지 않는 Java 오브젝트여야 한다.

따라서 POJO는 아래와 같은 것을 해서는 안 된다.

  • 1. 지정된 클래스를 extends 하는 것
  • 2. 정의된 인터페이스를 implement 하는 것
  • 3. 정의된 Annotation을 포함 하는 것

6. POJO 프로그래밍의 가치

단순히 POJO 프레임워크를 사용한다고, POJO 개발을 자연스럽게 하는 것은 아니다.

 

POJO 기반의 코드인지를 확인하는 두 가지 기준

 

1. 객체지향적으로 설계 되었는가?

반복적인 템플릿 코드와 테스트하기 힘든 구조, 확장 및 재활용의 어려움이 남아있다면 EJB의 문제점을 여전히 안고 있는 것이다.

 

2. 테스트가 용이한가?

잘 만들어진 POJO 어플리케이션은 자동화된 테스트 코드 작성이 편리하다.

코드 작성이 편리하면 좀 더 꼼꼼하게 만들게 되고, 코드 검증과 품질 향상에 유리해진다.

또한, 잘 만들어진 테스트 코드베이스가 있다면 리팩토링할 여유가 생겨 POJO 코드를 좀 더 나은 설계구조로 변경할 수 있다.

 

진정한 POJO란 객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말한다.

7. @Autowired vs @Resource vs @Inject

  @Autowired @Resource @Inject
지원 Spring Framework JAVA
(javax.annotation)
JAVA
(javax.annotation)
검색 방식 타입 이름 타입

 

ublic class Animal{}
@Component
public class Dog implements Animal{}

@Component
public class Cat implements Animal{}

 

차이

@Autowired
private Dog cat 
//타입 기준 -- Dog 타입으로 연결

@Resource
private Dog cat
//이름 기준 -- Cat 타입으로 연결

@Inject
private Cat dog
//타입 기준 -- Cat 타입으로 연결

 

@Autowired의 특징

  • Spring Framwork에만 존재하기 때문에 타 프레임워크에서 사용 불가능하다.
  • 타입을 통해 빈을 검색한다.
  • @Autowired는 기본적으로 특정 빈을 찾지 못하면 예외를 던진다.
  • 타입 -> 이름 -> @Qualifier -> 실패 순으로 검색한다.
  • 이 때 @Autowired의 required 속성값을 false로 지정해 빈을 못 찾더라도 그냥 치나치게 해줄 수 있다.
@Autowired( required = false )

 

만약 타입을 기준으로 IoC 컨테이너에 호환 타입이 여럿 존재하거나 그룹형이 아닐 때 @Primary, @Qualifier를 통해 특정한 빈에 우선권을 부여 할 수 있다.

@Autowired
@Qualifier("example")

 

@Resource의 특징

  • 자바 측에서 @Autowired를 참고 해 만든 어노테이션이다.
  • javax.annotation에 속해 있다.
  • 이름을 통한 검색 방식이기 때문에, POJO가 여럿일 때 대상이 모호하지 않고 명확하다.
  • @Autowired + @Qualifier
  • 이름 -> 타입 -> @Qualifier -> 실패 순으로 검색한다.

 

@Inject의 특징

  • 자바 측에서 @Autowired를 참고 해 만든 어노테이션이다.
  • javax.annotation에 속해 있다.
  • 타입을 통한 검색방식
  • 타입이 같은 POJO가 여럿일 때 커스텀 어노테이션(custom annotation)을 작성해야 한다.
  • 타입 -> @Qualifier-> 이름 -> 실패 순으로 검색한다.

References

스프링이란
@SpringBootApplication
스프링 어노테이션 총정리
롬복이란

https://blog.naver.com/PostView.nhn?blogId=hj_kim97&logNo=222295968816

POJO

@Resource, @Autowired, @Inject 차이

@Resource vs @Autowired vs @Inject

'스터디정리방' 카테고리의 다른 글

[기록] 220119  (0) 2022.01.25
[기록] 220112  (0) 2022.01.16
[기록] 220105  (0) 2022.01.09
[기록] 211229  (0) 2022.01.02
[기록] 211222  (0) 2021.12.26

댓글