spring core분석

mtak·2023년 7월 27일

spring analyzing

목록 보기
1/1
post-thumbnail

spring modules

spring-aop      spring-context-indexer  spring-instrument  spring-orm    spring-web
spring-aspects  spring-context-support  spring-jcl         spring-oxm    spring-webflux
spring-beans    spring-core             spring-jdbc        spring-r2dbc  spring-webmvc
spring-context  spring-expression       spring-jms         spring-test   spring-websocket
                                        spring-messaging   spring-tx  

20개가 넘는 spring의 모듈이 있다. 이를 크게 6 가지로 분류하면 다음과 같다.

  1. core

    • 빈의 생명 주기와 설정 & 처리 방법을 관리하는 스프링 컨테이너
  2. testing

    • 테스트 할 때 test context fw, mock obj 등을 제공
  3. data access

    • jdbc, orm, transaction 등 서비스 추상화를 통해 쉽게 데이터에 접근하는 방법 제공
  4. web & remoting

    • spring mvc & spring webflux

    • remoting 기술인 RMI, Hessian, Burlap, JAX-WS, HTTP 호출자, REST API 제공

  5. instrumentation

    • JVM에 weaving agent 를 제공
  6. aop (aspect oriented programming)

    • 객체 간의 결합을 낮추는 관점 지향 프로그래밍을 지원

Dependency of Spring modules

ASM

엄밀히 말해 스프링 모듈이 아니지만, 클래스 바이트코드 조작 및 분석 프레임워크인 ASM을 재 패키징한 모듈이다.
ASM 프레임워크는 스프링 뿐 아니라 여러 프레임워크에서 및 라이브러리에서 사용되는데, 이때 스프링 프레임워크와 ASM을 사용하는 다른 프레임워크와의 충돌을 방지하기 위해 org.springframework.asm 패키지로 재패키징해 독립적인 모듈로 제공한다.

Core

거의 대부분의 다른 스프링 모듈에서 필요로 하는 공통 기능을 갖는 핵심 모듈이다.
스프링에서 사용하는 주요 어노테이션, 컨버터, 상수, 유틸리티 클래스 등을 제공한다.

필수 라이브러리 - 없음
선택적 의존 - ASM

Beans

Beans는 스프링 DI 기능의 핵심인 빈 팩토리와 DI 기능을 제공하는 모듈이다.
빈 메타 정보, 빈 리더, 빈 팩토리의 구현과 프로퍼티 에디터가 포함되어 있다.
애플릿이나 모바일같은 제한된 환경에서 스프링의 DI 기능만 적용하고 싶으면 Beans 모듈까지만 적용하면 된다.

필수 라이브러리 - ASM, Core

AOP

AOP는 스프링의 프록시 AOP 기능을 제공하는 모듈이다.
프록시 기반 AOP를 만들 때 필요한 advice, pointcut, 프록시 팩토리빈, 자동 프록시 생성기 등을 제공한다.

필수 라이브러리 - Beans

Expression

Expression은 스프링 표현식 언어(SpEL) 기능을 지원한다.

필수 라이브러리 - Core

Cotext

Cotext는 어플리케이션 컨텍스트 기능을 제공한다.
어플리케이션 컨텍스트를 만드는 데 필요한 대부분의 기능과 빈 스캐너, 자바코드 설정 기능, EJB 지원, 포메터, 로드타임 위빙, 표현식, JMX JNDI, 리모팅, 스케줄링, 스크립트 언어 지원, 검증기 등의 컨테이너로서의 주요한 기능을 담고 있다.
단순한 빈팩토리가 아닌 엔터프라이즈 어플리케이션 프레임워크로 사용하기 위해 반드시 필요하다.

필수 라이브러리 - AOP, Expression
선택적 의존 - 로드 타임 위빙을 사용하는 경우 Instrument 모듈 필요

Context.Support

Context.Support의 경우 어플리케이션 컨텍스트에서 필요로 하는 부가기능을 지원한다.
EhCache, 메일 추상화 서비스, CommonJ와 Quartz 스케줄링, FreeMarker, JasperReports, Velocity 팩토리 기능을 제공한다.
해당 기능을 사용하지 않는다면 Context.Support은 필요 없다.
단 스프링 MVC가 Context.Support에 의존하므로 스프링 MVC를 사용한다면 필수로 추가해야 한다.

필수 라이브러리 - Context
선택적 의존 - Quartz의 JobStore 기능을 활용하는 경우 JDBC, Transaction 모듈 필요

트랜잭션(Transaction)

트랜잭션은 스프링의 데이터 액세스 추상화의 공통 기능을 담고 있다.
DataAcssessException 예외 계층구조와 트랜잭션 추상화 기능, 트랜잭션 동기화 저장소 그리고 JCA 기능을 포함한다.

필수 라이브러리 - Context

JDBC

JDBC는 JDBC 템플릿을 포함한 JDBC 지원 기능을 제공한다.
JdbcTemplate 등의 JDBC 지원 오브젝트 외에도 스프링이 직접 제공하는 DataSource 구현 클래스들이 제공됩니다.

필수 라이브러리 - 트랜잭션

ORM

ORM은 하이버네이트, JPA, JDO, iBatis와 같은 ORM에 대한 스프링의 지원 기능을 포함한다.
ORM은 내부적으로 JDBC를 사용한다.

필수 라이브러리 - JDBC
선택적 의존 - OpenSessionInViewFilter 같은 일부 기능은 Web 모듈에 선택적으로 의존

Web

Web은 스프링 웹 기술의 공통적인 기능을 정의한 모듈이다.
spring MVC 외에도 스프링이 지원하는 스트럿츠, JSF 등을 적용할 때 필요하다.
또한 Caucho, HttpInvoker, JAX-RPC, JAX-WS 등의 리모팅 기능도 포함한다.
기본적으로 바인딩, 컨텍스트 로더, 필터, 멀티파트, 메세지 컨버터 기능도 제공한다.

필수 라이브러리 - Context
선택적 의존 - XML을 사용하는 메세지 컨버터 기능에는 OXM 모듈이 필요

웹 서블릿(Web.Servlet)

웹 서블릿은 spring MVC 기능을 제공하는 모듈이다.
전통적인 MVC와 최신 @MVC 기능이 모두 포함되어 있다.

필수 라이브러리 - Web, Context.Support
선택적 의존 - XML을 사용하는 뷰나 메세지컨버터 등을 사용할 때에는 OXM 모듈이 필요

웹 포틀릿(Web.Portlet)

웹 포틀릿은 Portlet 개발에 사용하는 스프링 모듈이다.

필수 라이브러리 - Web.Servlet

웹 스트럿츠(Web.Struts)

웹 스트럿츠는 스트럿츠 1.x를 지원하는 모듈이다.

필수 라이브러리 - Web

JMS

JMS는 스프링의 JMS 지원 기능을 사용할 때 필요한 모듈이다.

필수 라이브러리 - Transaction

Aspects

Aspects는 스프링이 제공하는 AspectJ AOP를 사용할 때 필요한 모듈이다.
AspectJ는 스프링의 @Configurable을 이용한 도메인 오브젝트 DI 기능, JPA 예외 변환기, AspectJ 트랜잭션을 만들 때도 사용된 기술이다.

선택적 의존 - JPA 지원 기능 사용시 ORM, 트랜잭션 기능 지원시 Transaction 필요

Instrument

Instrument는 스프링의 로드타임위버(LTW) 기능을 적용할 때 필요하다.
JVM의 -javaagent 옵션을 사용해 자바에이전트로도 사용된다.

Instrument.Tomcat

Instrument.Tomcat은 어플리케이션이 아닌 톰캣 서버의 클래스 로더로 사용하는 모듈이다.

Test

Test는 스프링의 테스트 지원 기능을 가진 모듈이다.
테스트 컨텍스트 프레임워크나 목 오브젝트 등을 이용해 테스트 할 때 사용된다.
테스트용 모듈이기 때문에 운영 중에는 사용되지 않아야 된다.

스프링의 주요 기술

  • IoC container
  • events
  • resources
  • i18n
  • validation
  • data binding
  • type conversion
  • SpEL
  • AOP

1)IoC container

Spring IoC Container and Beans

IoC(inversion of control)란

코드의 흐름을 제어하는 주체가 바뀌는 것

🤔코드의 흐름을 제어한다?

  • component의 생성과 관계 설정, 사용, 생명 주기 관리
  • 메소드를 수행하는 것
  • etc

💡IoC를 적용한다?

  • 흐름 제어를 제 3자가 수행한다!
@Service
public class CouponService {
	public void updateCoupon(){...};
    public void addCoupon(){...};
}

Service 로직을 작성할 때 생명주기 메소드가 호출되었을 때의 동작만 정의하지, 언제 생명주기 메소드를 호출할지는 신경쓰지 않는다.
즉, Service의 실행 제어권은 spring framework에서 쥐고 있다.

✔ DI는 DIP를 구현하는 기법 중 하나이다.
✔IOC를 적용한 결과 중 하나가 DI이다.

DIP

Dependency Inversion principle의 줄임말.
SOLID 원칙 중 하나로, 핵심은 추상화에 의존하라는 것이다.

a. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g. interfaces).
b. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

예를 들어 다음과 같은 상황일 때,

추상화가 아닌 구체 클래스에 의존한 경우

public class DaoFactory {
	private ConnectionMaker connectionMaker;
    public DaoFactory(NaverConnectionMaker connectionMaker) {
         this.connectionMaker = connectionMaker;
        ...
    }
}

ConnectionMaker가 NaverConnectionMaker에서 DaumConnectionMaker로 바뀌어야 할 때 DaoFactory class까지 변경이 발생해버린다!
즉, 변경에 유연하지 못한 구조이다.

추상화에 의존한 경우

public class DaoFactory {
	private ConnectionMaker connectionMaker;
    public DaoFactory(ConnectionMaker connectionMaker) {
         this.connectionMaker = connectionMaker;
        ...
    }
}

DaoFactory는 ConnectionMaker interface에 의존하기 때문에 구현체인 NaverConnectionMaker이 변경하여도 DaoFactory는 영향을 받지 않는다.
즉, 변경에 유연한 구조가 된다.

DI

dependency injection의 줄임말
필요로 하는 오브젝트를 스스로 생성하는 것이 아닌, 외부로부터 주입받는 기법을 말한다.
DI를 적용하는 2가지 기법이 있다.

  1. Constructor injection
    생성자를 통해 주입하는 방식
public class DaoFactory {
	private ConnectionMaker connectionMaker;
    public DaoFactory(ConnectionMaker connectionMaker) {
         this.connectionMaker = connectionMaker;
        ...
    }
}
  1. Setter injection
    setter를 통해 주입하는 방식
public class DaoFactory {
	private ConnectionMaker connectionMaker;
    public void setConnectionMaker(ConnectionMaker connectionMaker) {
         this.connectionMaker = connectionMaker;
        ...
    }
}
  1. method injection
    일반 메소드를 통해 주입하는 방식
public class DaoFactory {
	private ConnectionMaker connectionMaker;
    public void putConnectionMaker(ConnectionMaker connectionMaker) {
         this.connectionMaker = connectionMaker;
        ...
    }
}

spring IoC container란?

bean의 생성과 관계 설정 같은 제어를 담당하는 IoC 오브젝트를 의미한다.

BeanFactory

BeanFactory는 빈을 생성하고 관계를 설정하는 IoC의 핵심 기능에 초점을 둔 interface다.

classDiagram
direction BT
class BeanFactory {
<<Interface>>
  + getBean(String, Class~T~) T
  + isPrototype(String) boolean
  + getBean(String, Object[]) Object
  + getBeanProvider(Class~T~) ObjectProvider~T~
  + getBean(String) Object
  + getType(String, boolean) Class~?~?
  + isSingleton(String) boolean
  + isTypeMatch(String, Class~?~) boolean
  + getBeanProvider(ResolvableType) ObjectProvider~T~
  + getType(String) Class~?~?
  + getBean(Class~T~, Object[]) T
  + containsBean(String) boolean
  + getAliases(String) String[]
  + getBean(Class~T~) T
  + isTypeMatch(String, ResolvableType) boolean
  + String FACTORY_BEAN_PREFIX
}

ApplicationContext

ApplicationContext는 BeanFactory에 다음 기능을 추가한 하위 interface다.

  • spring의 AOP기능을 쉽게 통합
  • message resource 핸들링 (국제화에 이용)
  • event 발생
  • Application 계층을 위한 context(ex. WebApplicationContext..)

ApplicationContext의 구현체

  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext
  • AnnotationConfigApplicationContext

Bean이란?

spring IoC container가 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 의미한다.

✔Spring IoC container는 bean정보와 연관 관계 정보가 담긴 metadata를 사용해 bean들을 조립한다.

configuration metadata

  • 어떤 형태일까?
    XML
    Java annotation
  • 어떤 정보를 포함하고 있을까?
    빈을 식별할 id
    빈의 class type
    의존하는 빈(optional)

BeanDefinition
Spring IoC container가 갖고 있는 bean metadata를 포함한 interface다.

Bean을 정의하는 정보

  • 패키지를 포함한 클래스 이름
  • scope, life cycle callbacks같은 container안에서 bean이 어떻게 행동할 것인지에 대한 정보
  • 의존하는 다른 빈의 reference
  • connection pool을 관리할 때 필요한 풀 크기 제한, 풀의 수 등 새로 생성된 객체에 설정할 기타 구성 설정

🤔스프링에 등록된 빈은 어떻게 사용하나?
T getBean(String name, Class<T> requiredType)로 원하는 빈을 spring IoC container에서 꺼내올 수 있다.

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

2)Aspect Oriented Programming with Spring

AOP?

  • 애플리케이션에 산재해서 나타나는 부가 기능을 모듈화

    즉, 여러 type의 instance에 나타나는 기능(ex. transaction)를 모듈로 분리해낼 수 있다.

AOP 용어 정리

  • 타깃
    • 타깃은 부가기능을 부여할 대상이다.
    • 핵심기능을 담은 클래스일 수도 있지만 경우에 따라서는 다른 부가기능을 제공하는 프록시 오브젝트일 수도 있다.
  • advice
  • 타깃에게 제공할 부가기능을 담은 모듈이다.
  • 오브젝트로 정의하기도 하지만 메소드 레벨에서 정의할 수도 있다.
  • 여러 가지 종류가 있다.
    • MethodInterceptor처럼 메소드 호출 과정에 전반적으로 참여하는 것도 있지만,
      예외가 발생했을 때만 동작하는 advice처럼 메소드 호출 과정의 일부에서만 동작하는 advice도 있다.
  • join point
  • advice가 적용될 수 있는 위치를 말한다.
  • 스프링의 프록시 AOP에서 join point는 메소드의 실행 단계뿐이다.
  • 타깃 오브 젝트가 구현한 인터페이스의 모든 메소드는 join point가 된다.
  • pointcut
    • advice를 적용할 join point를 선별하는 작업 또는 그 기능을 정의한 모듈을 말한다.
    • 스프링 AOP의 join point는 메소드의 실행이므로 스프링의 pointcut은 메소드를 선정하는 기능을 갖고 있다.
      그래서 pointcut 표현식은 메소드의 실행이라는 의미인 execution으로 시작하고, 메소드의 시그니처를 비교하는 방법을 주로 이용한다.
      • 메소드는 클래스 안에 존재하는 것이기 때문에 메소드 선정이란 결국 클래스를 선정하고 그 안의 메소드를 선정하는 과정을 거치게 된다.
  • 프록시
    • 클라이언트와 타깃 사이에 투명하게 존재하면서 부가기능을 제공하는 오브 젝트다.
    • DI를 통해 타깃 대신 클라이언트에게 주입되며, 클라이언트의 메소드 호출을 대신 받아서 타깃에 위임해주면서, 그 과정에서 부가기능을 부여한다.
    • 스프링은 프록시를 이용해 AOP를 지원한다.
  • advisor
    • pointcut과 advice를 하나씩 갖고 있는 오브젝트다.
    • advisor는 어떤 부가기능(advice)을 어디에(pointcut) 전달할 것인가를 알고 있는 AOP의 가장 기본이 되는 모듈이다.
    • 스프링은 자동 프록시 생성기가 advisor를 AOP 작업의 정보 로 활용한다.
    • advisor는 스프링 AOP에서만 사용되는 특별한 용어이고, 일반적인 AOP에서는 사용되지 않는다.
  • aspect
  • OOP의 클래스와 마찬가지로 aspect는 AOP의 기본 단위이다.
  • 한 개 또는 그 이상 의 pointcut과 advice의 조합으로 만들어지며 보통 싱글톤 형태의 오브젝트로 존재한다.
    따라서 클래스와 같은 모듈 정의와 오브젝트와 같은 실체(인스턴스)의 구분이 특별히 없다.
    두 가지 모두 aspect라고 불린다.
  • 스프링의 advisor는 아주 단순한 aspect라고 볼 수도 있다
  • introuduction
    • Type과 더불어 추가적인 method, fields를 정의하는 것이다.
    • 스프링은

사용된 주요 디자인 패턴

싱글톤 패턴

싱글톤 패턴은 GoF가 소개한 디자인 패턴 중의 하나다. 디자인 패턴 중에서 가장 자주 활용되는 패턴 이기도 하지만 가장 많은 비판을 받는 패턴이기도 하다. 심지어 디자인 책을 쓴 GoF 멤버조차도 싱글 톤 패턴은 매우 조심해서 사용해야 하거나 피해야 할 패턴이라고 말하기도 한다. 싱글톤 패턴은 어떤 클래스를 애플리케이션 내에서 제한된 인스턴스 개수, 이름처럼 주로 하나만 존 재하도록 강제하는 패턴이다. 이렇게 하나만 만들어지는 클래스의 오브젝트는 애플리케이션 내에서 전역적으로 접근이 가능하다. 단일 오브젝트만 존재해야 하고, 이를 애플리케이션의 여러 곳에서 공 유하는 경우에 주로 사용한다.

전략패턴

자신의 기능 맥락context에서, 필요에 따라 변경이 필요 한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴

여기서 알고리즘이란, 독립적인 책임으로 분리가 가능한 기능을 말한다.

바뀔 수 있는 쪽의 클래스는 인터페이스를 구현하도록 하고, 다른 클래스에서 인터 페이스를 통해서만 접근하도록 만들었다. 이렇게 해서 인터페이스를 정의한 쪽의 구현 방법 이 달라져 클래스가 바뀌더라도, 그 기능을 사용하는 클래스의 코드는 같이 수정할 필요가 없도록 만들면 된다.

템플릿 메소드 패턴

  • 상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법이다.

  • 변하지 않는 기능은 슈퍼클래스에 만들어두고 자주 변경되며 확장할 기능은 서브클래스에서 만들도록 한다.

  • 슈퍼클래스 에서는 미리 추상 메소드 또는 오버라이드 가능한 메소드를 정의해두고 이를 활용해 코드의 기본 알고리즘을 담고 있는 템플릿 메소드를 만든다.

  • 슈퍼클래스에서 디폴트 기능을 정의해두거나 비워뒀다 가 서브클래스에서 선택적으로 오버라이드할 수 있도록 만들어둔 메소드를 훅(hook) 메소드라고 한 다.

  • 서브클래스에서는 추상 메소드를 구현하거나, 훅 메소드를 오버라이드하는 방법을 이용해 기능의 일부를 확장한다.

팩토리 메소드 패턴

팩토리 메소드 패턴도 템플릿 메소드 패턴과 마찬가지로 상속을 통해 기능을 확장하게 하는 패턴이 다. 그래서 구조도 비슷하다.
슈퍼클래스 코드에서는 서브클래스에서 구현할 메소드를 호출해서 필요 한 타입의 오브젝트를 가져와 사용한다.
이 메소드는 주로 인터페이스 타입으로 오브젝트를 리턴하므 로 서브클래스에서 정확히 어떤 클래스의 오브젝트를 만들어 리턴할지는 슈퍼클래스에서는 알지 못 한다. 사실 관심도 없다.
서브클래스는 다양한 방법으로 오브젝트를 생성하는 메소드를 재정의할 수 있다.
이렇게 서브클래스에서 오브젝트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소 드를 팩토리 메소드라고 하고,
이 방식을 통해 오브젝트 생성 방법을 나머지 로직, 즉 슈퍼클래스의 기본 코드에서 독립시키는 방법을 팩토리 메소드 패턴이라고 한다.

자바에서는 종종 오브젝트를 생성하는 기능을 가진 메소드를 일반적으 로 팩토리 메소드라고 부르기도 한다. 이때 말하는 팩토리 메소드와 팩토리 메소드 패턴의 팩토리 메 소드는 의미가 다르므로 혼동하지 않도록 주의해야 한다

템플릿/콜백 패턴

전략 패턴의 기본 구조에 익명 내부 클래스를 활용한 방식의 디자인 패턴이다.

템플릿(template)은 어떤 목적을 위해 미리 만들어둔 모양이 있는 틀을 가리킨다.
프로그래밍에서는 고정된 틀 안에 바꿀 수 있는 부분을 넣어서 사용하는 경우에 템플릿이라고 부른다.
JSP는 HTML이라는 고정된 부분에 EL 과 스크립릿이라는 변하는 부분을 넣은 일종의 템플릿 파일이다.
템플릿 메소드 패턴은 고정된 틀의 로직을 가진 템플릿 메소드를 슈퍼클래스에 두고, 바뀌는 부분을 서브클래스의 메소드에 두는 구조로 이뤄진다

콜백(callback)은 실행되는 것을 목적으로 다른 오브젝트의 메소드에 전달되는 오브젝트를 말한다.
파라미터로 전달되지만 값을 참조하기 위한 것이 아니라 특정 로직을 담은 메소드를 실행시키기 위해 사용한다.
자바에선 메소드 자체를 파라미터로 전달할 방법은 없기 때문에 메소드가 담긴 오브젝트를 전달해야 한다.
그래서 펑셔널 오브젝트(functional object)라고도 한다.

Proxy

마치 자기가 client가 원했던 대상이었던 것처럼 위장해서 client의 요청을 받아주는 것을 proxy라고 한다.
proxy를 통해 최종적으로 요청을 외주 받아 처리하는 것은 target 또는 real subject라고 한다.

proxy는 target과 같은 인터페이스를 구현 + target을 제어할 수 있는 점에서 멋지다.

proxy 사용 목적 2가지!

  • client가 target에 접근하는 방법을 제어하기 위해
  • target에 부가 기능을 얹기 위해

decorator 패턴

타깃에 부가적인 기능을 런타임 시 다이내믹하게 부여해주기 위해 프록시를 사용하는 패턴이다.

🤔dynamiccally 기능 부여?
코드 상에서는(aka compile time) 어떤 방법과 순서로 proxy와 target이 연결되어 사용되는지는 정해져 있지 않다는 의미다. 고로 proxy가 여러 개일 수 있다.

Ex. runtime에 proxy들을 적절한 순서로 조합해서 사용할 수 있다.

이 때 proxy로 동작하는 decorator들은 위임하는 대상에도 interface로 접근하기 때문에 지가 target에 접근하는지 or 또다른 decorator에 접근하는지도 모른다. ➡decorator의 다음 위임 대상은 인터페이스로 선언 + 생성자나 수정자로 위임 대상을 runtime시에 주입받을 수 있게 해야한다.

프록시 패턴

proxy != proxy pattern

proxy : client - 사용 대상 사이에 대리 역할인 obj를 두는 방법을 총칭

proxy pattern : proxy 사용 방법 중 target에 대한 접근 방법을 제어하려고 proxy를 사용한 경우. 즉 타깃의 기능을 확장하거나 추가하지 않는다. 대신 client가 target에 접근하는 방식을 바꿔준다.

target obj가 겁나 복잡하거나 당장 필요한게 아니라면 굳이 섣부르게 만들 필요가 없다.
하지만 client에게 target obj에 대한 reference가 미리 필요할 순 있다. 이 때 실제 obj가 아닌 proxy를 넘기는 거다!
실제 obj야 뭐 proxy method로 target을 사용하려고 하면 그때 만들면 된다.

원격 obj! 그러니까 다른 서버에 존재하는 obj를 써야 한다면 원격 obj에 대한 proxy를 만들어두고 client는 마치 로컬 obj대하듯 내버려 두면,proxy입장에선 client의 요청을 받았을때 그제서야 네트워크로 원격의 obj를 실행하고 결과를 받아서 client에게 돌려주면 된다!

또 특별한 상황에서 target에 대한 접근 권한에 차등을 둘때도 proxy pattern 쓸 수 있다.

Collections의 unmodifidableCollection()은 parameter로 넘어온 놈의 proxy를 만들어서 add()같은 수정 메소드 호출할 경우 예외가 발생하게 해준다.

접근 제어를 위한 proxy pattern + paging 기능을 위한 proxy쓰는 decorator pattern

dynamic proxy pattern

dynamic proxy는 reflection 기능을 이용해 proxy를 만들어준다.
🤔reflection : 구체적인 클래스 타입을 몰라도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 Java API

문제 상황

구현할 인터페이스

interface Hello {
    String sayHello(String name);

    String sayHi(String name);

    String sayThankYou(String name);
}

구현한 target class

class HelloTarget implements Hello {

    @Override
    public String sayHello(String name) {
        return "Hello" + name;
    }

    @Override
    public String sayHi(String name) {
        return "Hi" + name;
    }

    @Override
    public String sayThankYou(String name) {
        return "Thank You" + name;
    }
}

Hello interface를 통해 HelloTarget obj를 사용할 client

    @Test
    public void simpleProxy() {
        Hello hello = new HelloTarget();
        assertThat(hello.sayHello("mtak")).isEqualTo("Hello mtak");
        assertThat(hello.sayHi("mtak")).isEqualTo("Hi mtak");
        assertThat(hello.sayThankYou("mtak")).isEqualTo("Thank You mtak");
    }

자 ~! 이제 Hello interface를 구현한 proxy 😆decorator pattern 적용해서 HelloTarget에 부가 기능(upper case) 넣는다.

class HelloUppercase implements Hello{
    Hello hello;

    public HelloUppercase(Hello hello) {
        this.hello = hello;
    }

    @Override
    public String sayHello(String name) {
        return hello.sayHello(name).toUpperCase();
    }

    @Override
    public String sayHi(String name) {
        return hello.sayHi(name).toUpperCase();
    }

    @Override
    public String sayThankYou(String name) {
        return hello.sayThankYou(name).toUpperCase();
    }
}
    @Test
    public void simpleProxy() {
        Hello hello = new HelloTarget();
        assertThat(hello.sayHello("mtak")).isEqualTo("Hello mtak");
        assertThat(hello.sayHi("mtak")).isEqualTo("Hi mtak");
        assertThat(hello.sayThankYou("mtak")).isEqualTo("Thank You mtak");

        Hello hello1 = new HelloUppercase(new HelloTarget());
        assertThat(hello1.sayHello("mtak")).isEqualTo("HELLO MTAK");
        assertThat(hello1.sayHi("mtak")).isEqualTo("HI MTAK");
        assertThat(hello1.sayThankYou("mtak")).isEqualTo("THANK YOU MTAK");
    }

🤔전형적인 proxy문제를 다 가지고 있다. 귀찮게 인터페이스 모든 메소드 오버라이드 해야되고, 부가 기능(toUppercase())이 모든 메소드에 중복되서 나타난다.

dynamic proxy를 만들어보자!

  1. InvocationHandler를 구현한다.
class UppercaseHandler implements InvocationHandler {
    Hello target;

    public UppercaseHandler(Hello target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String ret = (String) method.invoke(target, args);
        return ret.toUpperCase();
    }
}
  1. InvocationHandler를 사용하고 Hello interface를 구현하는 proxy를 만들어보자. ➡ Proxy class, newProxyInstance()
//dynamic proxy obj        
Hello proxyHello = (Hello) Proxy.newProxyInstance(getClass().getClassLoader(),//동적으로 생성되는 dynamic proxy class에 쓸 class loader
                new Class[]{Hello.class},//구현할 interface
                new UppercaseHandler(new HelloTarget())//부가 기능과 위임 코드를 담은 InvocationHandler
        );

        assertThat(proxyHello.sayHello("mtak")).isEqualTo("HELLO MTAK");
        assertThat(proxyHello.sayHi("mtak")).isEqualTo("HI MTAK");
        assertThat(proxyHello.sayThankYou("mtak")).isEqualTo("THANK YOU MTAK");

core

core API: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/package-summary.html

예외 처리 및 버전 검색을 위한 기본 클래스와 프레임워크의 특정 부분이 아닌 기타 핵심 도우미를 제공

Beans

beans API : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/package-summary.html

Java Bean을 조작하기 위한 인터페이스와 클래스가 포함되어 있다.
BeanWrapper 객체는 bean 속성을 단독으로 또는 대량으로 설정하고 가져오는 데 사용할 수 있습니다.

AOP

aop API : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/aop/package-summary.html

AOP Alliance AOP 상호 운용성 인터페이스를 기반으로 하는 코어 Spring AOP 인터페이스.

  • 기능
    • 도입 지원
    • pointcut 추상화
      • '정적' pointcut(클래스 및 메소드 기반) 및 '동적' pointcut(메소드 인수도 고려)을 지원
    • advice type
      • around, before, after return 및 throws advice를 포함한 모든 범위의 advice type지원
      • 핵심 프레임워크를 수정하지 않고 임의의 사용자 정의 advice 유형을 플러그인할 수 있는 확장성.

Spring AOP는 프로그래밍 방식으로 사용하거나 (가급적이면) Spring IoC 컨테이너와 통합하여 사용할 수 있다.

Context

context API : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/package-summary.html

  • 기능
    • 메시지 소스 및 Observer 디자인 패턴에 대한 지원
    • 애플리케이션 개체가 일관된 API를 사용하여 리소스를 얻을 수 있는 기능

profile
노는게 젤 조아. 친구들 모여라!!

1개의 댓글

comment-user-thumbnail
2023년 7월 27일

잘 봤습니다. 좋은 글 감사합니다.

답글 달기