Dependency Injection

의존성 주입의 방법은 총 3가지가 있다.

Constructor Injection

  • Spring 4.3에서부터는 단일 생성자의 경우 Autowired Annotation 불필요함
@Service
public class Atin {
  private final Story story;

  @Autowired
  public Atin(Story story) {
    this.story = story;
  }
}

Field Injection

...

@Service
public class Atin {
  @Autowired
  private final Story story;
}

Setter Injection

...

@Service
public class Atin {
  private Story story;

  @Autowired
  public void setStory(Story story) {
    this.story = story;
  }
}

어떤 방법이 가장 좋을까?

여러 가지 방법이 있고, 어떤 형태로 하던 개발에는 문제는 없다.
그러나 프로젝트 개발, 그리고 회사의 팀에서 개발을 할 때는 공통된 코드 스타일 작성이 필요하다.

가장 추천하는 방법은 생성자 주입이다.
스프링 소스를 살펴보면 생성자 주입을 이용한 방법을 사용하고 있다.

생성자 주입이 좋은 내가 생각하는 이유는 다음과 같다.

  • 테스트 클래스 작성시 리플렉션을 이용하지 않고 주입할 수 있다.
  • POJO에 가깝다.
  • 특별한 경우가 아니라면, 의존관계에 있는 객체들은 반드시 의존관계 주입이 되어야 하며 그렇다면 생성자 주입이 그림상 맞다.

[1]의 블로그에 보면 해당 이유를 다음과 같이 설명하고 있다.

  • 단일 책임의 원칙
  • 테스트 용이성
  • Immutabiblity
  • 순환 의존성
  • 의존성 명시

그렇다면 생성자 주입이 가장 좋은 방법으로 생각해 볼 수 있다.
그런데 생성자를 만드는 방법이 꽤 불편하기도 한데 이럴 때 고려를 해 볼 수 있는 점이 lombok이다.

주입이 필요한 객체들을 final로 한 이후에 lombok의 @RequiredArgsConstructor를 사용하면 final로 지정된 객체들이 자동적으로 생성자 때 필요하게 되면서 편리하게 생성자 주입을 사용할 수 있다.

@Service
@RequiredArgsConstructor
public class TestController {
    private final StoryService storyService;
    private final TestService testService;

    ...
}

그러면 lombok을 통한 방법의 생성자 주입이 최선일까?
처음에는 이 방식이 편리해서 사용했고 편리했다.
그러나 이 방식에는 몇 가지 문제가 존재한다.

  • 주입하려는 bean이 1개가 아닌 경우에는 @Qualifier를 사용해야 하는데 lombok 이용시 불가능하다.
  • @Value와 같은 properties 등의 주입이 필요할 경우 불가능하다. 그렇다고 @Value경우는 필드 주입을 쓰게 되면 코드 통일성이 없어진다.
  • final로 지정된 클래스 변수들의 순서가 변경이 되면 생성자도 변경이 되며 TC등에서 문제가 발생할 수 있다.
  • 생성자에 특정 로직 작성이 필요한 등의 이슈가 발생하면 결국 직접 생성을 해줘야 한다.

그래서 결론은, 생성자 주입은 lombok을 사용하지 않고 직접 작성하는 것이 좋다.
다음은 spring sagan 소스이다. 참고용으로 넣어본다.
Spring 4.3 이후 버전이라서 Autowired도 필요가 없다.

@RestController
@RequestMapping(path = "/guides", produces = MediaTypes.HAL_JSON_VALUE)
public class GuidesController {

    private final GuideRenderer guideRenderer;

    private final GithubClient githubClient;

    private final RendererProperties properties;

    private final GuideResourceAssembler guideAssembler = new GuideResourceAssembler();

    public GuidesController(GuideRenderer guideRenderer, GithubClient github,
            RendererProperties properties) {
        this.guideRenderer = guideRenderer;
        this.githubClient = github;
        this.properties = properties;
    }

    ...
}

https://github.com/spring-io/sagan/blob/master/sagan-renderer/src/main/java/sagan/renderer/guides/GuidesController.java

Reference

[1] https://landsnail.tistory.com/entry/Spring-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95
[2] https://github.com/sieunkr/spring-tips/tree/master/spring-di
[3] https://javaslave.tistory.com/19

Leave a Comment

Spring Boot.

스프링 부트(Spring Boot)

  • 공식 홈 - https://spring.io/projects/spring-boot
  • 스프링 기반으로 상용제품 수준의 단독 실행형 애플리케이션을 복잡한 과정없이 개발할 수 있도록 하는 것

History


기능

  • 단독실행가능한 스프링어플리케이션 생성
  • 기본 설정된 스타터 컴포넌트
  • 내장형 WAS(톰캣, 제티, 언더토우)
  • AutoConfiguration 으로 기본 설정이 제공
  • 상용화에 필요한 통계, 상태 점검 및 외부설정을 제공
  • XML 코드를 생성하거나 요구하지 않음


특징

  • Spring CoC(Convention-over-Configuration) Version (Wikipedia)
  • 최적의 Dependency(라이브러리, 버전) 관리
  • 관례에 따른 기본 Bean 설정(@Configuration)을 미리 제공
  • 상용화를 위한 기능(Actuator 등)
  • Micro Service(Application With Single Responsbility) 구현에 최적화
  • 보안, 모니터링 구현을 프레임워크 레벨에서 지원


Leave a Comment


기본 JDK 지원 버전 업데이트

  • Spring Framework 5.0 최소 요구 사항 : Java 8
  • 전체 Spring 프레임 워크 5.0 코드베이스는 Java 8에서 실행


Core Framework Revision

  • Java 8 reflection 기반으로 Spring Framework 5.0의 메소드 매개 변수에 효율적으로 액세스 가능
  • 코어 스프링 인터페이스는 이제 Java 8 기본 메소드를 기반으로 선택적 선언을 제공
  • @ Nullable 및 @ NotNull 주석은 nullable 인수 및 반환 값을 명시적으로 표시
    • 런타임에 NullPointerExceptions 대신 컴파일 타임에 Null 값을 처리  가능


Core Container Updates

  • 선택적 주입 포인트에 대한 지표로 @Nullable 어노테이션 지원
  • GenericApplicationContext/AnnotationConfigApplicationContext 함수형 스타일 형태
  • 인터페이스 메소드에서 트랜잭션, 캐싱, 비동기 어노테이션 감지
  • 버전 정보 없는 XML 설정 네임스페이스
  • classpath 스캐닝 대신에 후보 구성 요소 색인 지원


Reactive Programming Model

  • Reactive Stack Web Framework이 핵심
  • 완전히 반응적이고 논 블로킹
  • 소수의 스레드로 확장 할 수있는 이벤트 루프 스타일 처리에 적합
  • Reactive Streams : 
    • Netflix, Pivotal, Typesafe, Red Hat, Oracle, Twitter 및 Spray.io의 엔지니어가 개발 한 API 사양
    • 리액티브 프로그래밍 구현을 위한 공통 API 제공
    • Hibernate,  JPA와 유사. (JPA가 API이고, Hibernate가 구현)
  • Reactive Streams API는 공식적으로 Java 9의 일부
  • Java 8에서는 Reactive Streams API 사양에 대한 종속성을 포함
  • Spring Framework 5.0은 Reactive Streams API 사양을 구현 한 Project Reactor 기반


Spring-webflux - 서버 측 두 가지 프로그래밍 모델을 가짐

  • @Controller와 Spring MVC의 다른 Annotation으로 된 Annotation 기반
  • Java 8 lambda를 사용한 함수형 스타일 라우팅 및 처리


Spring Webflux를 사용하면 RestTemplate의 대안으로 반응적이고 non-blocking적인 WebClient를 만들 수 있음



Kotlin을 사용한 함수형 프로그래밍

  • JetBrains Kotlin 언어 지원
  • Kotlin은 JVM 상단에서 실행되지만 이에 국한되지 않음


테스팅 개선

  • Junit 5 Jupiter 완벽 지원
  • Jupiter 서브 프로젝트는 프로그래밍 및 확장 모델을 제공 할뿐만 아니라 Spring에서 Jupiter 기반 테스트를 실행하는 테스트 엔진을 제공
  • Spring Framework 5는 Spring TestContext Framework에서 병렬 테스트 실행을 지원
  • 리액티브 프로그래밍 모델의 경우 스프링 테스트에는 이제 Spring WebFlux에 대한 테스트 지원을 통합하기위한 WebTestClient가 포함


지원 중단 패키지

  • beans.factory.access
  • jdbc.support.nativejdbc
  • mock.staticmock
  • web.view. tiles2M
  • orm.hibernate3
  • orm.hibernate4


라이브러리 지원 중단

  • Portlet
  • Velocity
  • JasperReports
  • XMLBeans
  • JDO
  • Guava


라이브러리 지원

  • Jackson 2.6+
  • EhCache 2.10+ / 3.0 GA
  • Hibernate 5.0+
  • JDBC 4.0+
  • XmlUnit 2.x+
  • OkHttp 3.x+
  • Netty 4.1+


Summarry

  • 중요한 패러다임 전환 - 리액티브 프로그래밍
  • 스프링 데이터 팀은 이미 MongoDB 및 Redis에 대한 리액티브 프로그래밍을 대응함
  • JDBC 지원 불가(JDBC 스펙 자체가 차단중, 전통적인 JDBC 데이터베이스로 리액티브 프로그램을 보는 것은 현재로서는 불가)
  • Spring Framework 5는 Reactive Streams 표준 API의 구현체인 Reactor를 사용중


Reference

[1] What's new in Spring framework 5(https://springframework.guru/what-is-new-with-spring-framework-5/)

[2] Web on Reactive Stack (https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#spring-webflux)

[3] What's New in the Spring Framework (https://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-the-Spring-Framework)

Comments

  1. 나그네 2018.07.06 11:36 Permalink Modify/Delete Reply

    정리 감사드립니다.

Leave a Comment


File 주소 기반



ClassPath 기반


Leave a Comment

Spring에서 RestController를 사용하면 URL 끝에 ".json"을 붙여주면 json 타입으로 리턴을 해준다.

하지만 기본값은 xml이여서 xml로 리턴이 되어진다. 이 기본값을 변경하려면 다음과 같이 해야 한다.


1. Controller에서 설정하기 - produces

Controller.java




2. XML에서 기본값을 변경하기 - ContentNegotiationManager

[1]의 문서를 보면 defaultContentType만 설정해주면 되는것 같은데, 나는 도저히 기본값이 적용이 되지 않았다.

그래서 원하는 확장자를 별도로 선언해서 사용하니까 잘 적용이 되었다.


servlet-context.xml


3. jackson-dataformat-xml.jar 제거하기

작업하다보니 나도 모르게 jackson-dataformat-xml을 pom.xml에 추가를 해놓았었다.

이것만 제거해도 xml로 나가지 않는다.


Reference

[1] Content Negotiation using Spring MVC (https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc)

[2] Chapter16. 스프링 MVC로 REST API 사용하기 (https://rebeccacho.gitbooks.io/spring-study-group/content/chapter16.html)



Leave a Comment

다국 언어 선택할 때 많이 사용하는 스프링 메시지이다.

세션을 많이 사용하겠지만 쿠키 형태로 정보를 저장할 때의 설정이다.

필요한 정보만 간단히 모아보았다.

언어 변경은 LocaleChangeInterceptor을 통해서 할 수 있게 설정했다.


applicationContext.xml


servlet-context.xml


message.jsp


Leave a Comment

Spring에서 webjars 적용하는 방법

Maven Repository나 다른 곳에서 webjars를 검색한다.

pom.xml에 추가한다.


pom.xml



servlet-context에 주소를 매핑한다.


servlet-context.xml


Java configuration을 사용할 경우에는 아래와 같이 설정한다.


WebConfig.java



JSP에서 호출한다.

Example1)

http://localhost/webjars/jquery/3.1.1-1/jquery.min.js

http://localhost/webjars/jqgrid/4.7.0/css/ui.jqgrid.css


Example2)




Reference

[1] [블로그개발_06] webjars를 이용한 bootstrap, jquery 적용해보기 (Spring Boot) (http://millky.com/@origoni/post/1147?language=ko_kr)

[2] 허니몬의 자바 | webjars란 무엇인가? (http://java.ihoney.pe.kr/428)


Leave a Comment

Spring Security를 커스터마이징하기 위해서는 그리고 이해하기 위해서는 아래 필터 체인을 이해하는 것이 좋다.

아래 그림은 인터넷에 돌아다니는 Spring Security 호출 그림을 내가 다시 깔끔하게 그려본 것이다.




Table 3.1. Standard Filter Aliases and Ordering
(https://docs.spring.io/spring-security/site/docs/3.1.x/reference/ns-config.html)


AliasFilter ClassNamespace Element or Attribute
CHANNEL_FILTERChannelProcessingFilterhttp/
intercept-url
@requires-channel
SECURITY_CONTEXT_FILTERSecurityContextPersistenceFilterhttp
CONCURRENT_SESSION_FILTERConcurrentSessionFiltersession-management/
concurrency-control
LOGOUT_FILTERLogoutFilterhttp/logout
X509_FILTERX509AuthenticationFilterhttp/x509
PRE_AUTH_FILTERAstractPreAuthenticatedProcessingFilter SubclassesN/A
CAS_FILTERCasAuthenticationFilterN/A
FORM_LOGIN_FILTERUsernamePasswordAuthenticationFilterhttp/form-login
BASIC_AUTH_FILTERBasicAuthenticationFilterhttp/http-basic
SERVLET_API_SUPPORT_FILTERSecurityContextHolderAwareRequestFilterhttp/
@servlet-api-provision
JAAS_API_SUPPORT_FILTERJaasApiIntegrationFilterhttp/
@jaas-api-provision
REMEMBER_ME_FILTERRememberMeAuthenticationFilterhttp/remember-me
ANONYMOUS_FILTERAnonymousAuthenticationFilterhttp/anonymous
SESSION_MANAGEMENT_FILTERSessionManagementFiltersession-management
EXCEPTION_TRANSLATION_FILTERExceptionTranslationFilterhttp
FILTER_SECURITY_INTERCEPTORFilterSecurityInterceptorhttp
SWITCH_USER_FILTERSwitchUserFilterN/A



API Document

- Spring Security 3.1.7 API Docs

Spring Javadocs 3.1.7

Spring Javadocs Current


- Spring Security Filter Chain

Spring Javadocs 3.1.x

Spring Javadocs Current


Filter Class

- SecurityContextPersistenceFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- LogoutFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


UsernamePasswordAuthenticationFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


DefaultLoginPageGeneratingFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


BasicAuthenticationFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- RememberMeAuthenticationFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- SecurityContextHolderAwareRequestFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- AnonymousAuthenticationFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- SessionManagementFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- ExceptionTranslationFilter

Spring Javadocs 3.1.7

Spring Javadocs Current


- FilterSecurityInterceptor

Spring Javadocs 3.1.7

Spring Javadocs Current



Authentication class

- SecurityContextHolder

Spring Javadocs 3.1.7

Spring Javadocs Current



Authentication interface

- SecurityContextRepository

Spring Javadocs 3.1.7

Spring Javadocs 3.1.7


- SecurityContext

Spring Javadocs 3.1.7

Spring Javadocs Current


- LogoutSuccessHandler

Spring Javadocs 3.1.7

Spring Javadocs Current


- Authentication

Spring Javadocs 3.1.7

Spring Javadocs Current


- AuthenticationManager

Spring Javadocs 3.1.7

Spring Javadocs Current


- AuthenticationProvider

Spring Javadocs 3.1.7

Spring Javadocs Current


- UserDetails

Spring Javadocs 3.1.7

Spring Javadocs Current


- AuthenticationSuccessHandler

Spring Javadocs .3.1.7

Spring Javadocs .Current


- UserDetailService

Spring Javadocs 3.1.7

Spring Javadocs Current


- GrantedAuthority

Spring Javadocs 3.1.7

Spring Javadocs Current


- AuthenticationFailureHandler

Spring Javadocs 3.1.7

Spring Javadocs Current


- SessionAuthenticationStrategy

Spring javadocs 3.1.7

Spring javadocs Current


- SessionRegistry

Spring javadocs 3.1.7

Spring javadocs Current


- RequestCache

Spring Javadocs 3.1.7

Spring Javadocs Current




Authorization interface

- AuthenticationEntryPoint

Spring Javadocs 3.1.7

Spring Javadocs Current


- AccessDeniedHandler

Spring javadocs 3.1.7

Spring javadocs Current


- AccessDecisionManager

Spring Javadocs 3.1.7

Spring Javadocs Current


- AccessDecisionVoter

Spring Javadocs 3.1.7

Spring Javadocs Current


- SecurityMetadataSource

Spring Javadocs 3.1.7

Spring Javadocs Current




Authorization class

- AffirmativeBased

implemented : AccessDecisionManager

Spring Javadocs 3.1.7

Spring Javadocs Current


- RoleVoter

implemented : AccessDecisionVoter

Spring Javadocs 3.1.7

Spring Javadocs Current


- AuthenticationVoter

- DefaultMethodSecurityExpressionHandler 

implemented : MethodSecurityExpressionHandler, SecurityExpressionHandler

Spring Javadocs 3.1.7

Spring Javadocs Current


- AbstractAuthenticationToken 

implemented : Authentication

Spring Javadocs 3.1.7

Spring Javadocs Current

github java source


- AnonymousAuthenticationToken 

implemented : Authentication

Spring Javadocs 3.1.7

Spring Javadocs Current

github java source


- UsernamePasswordAuthenticationToken 

implemented : Authentication

Spring Javadocs 3.1.7

Spring Javadocs Current

github java source




Comments

  1. 2018.11.20 21:25 Permalink Modify/Delete Reply

    비밀댓글입니다

Leave a Comment

SpringSecurity를 설정하다보니 Method레벨(global-method-security)에서의 AccessDeniedException은 그 전에 설정해놓은 <access-denied-handler>에 걸리지 않는 것을 알게 되었다.


왜 그런가 찾다보니 스택오버플로우[1]에서 답을 찾았는데

내 상황이 답을 준것처럼 처리하기에는 정확히 맞지 않는 상황이었다.


- StackOverFlow 번역 -

access-denied-handler는 AccessDeniedException가 발생할 때 ExceptionTranslationFilter에 의해 사용됩니다.

그러나 org.springframework.web.servlet.DispatcherServlet은 먼저 예외 처리를 시도했다.

특히 defaultErrorView로 정의 된 org.springframework.web.servlet.handler.SimpleMappingExceptionResolver가 있는데, 결과적으로 SimpleMappingExceptionResolver는 적절한 뷰로 리디렉션하여 예외를 소비하므로 결과적으로 ExceptionTranslationFilter에 버블링 될 예외가 없습니다.


수정은 간단했다. 모든 AccessDeniedException을 무시하도록 SimpleMappingExceptionResolver를 구성하십시오.


applicationContext.xml


이제는 AccessDeniedException이 발생할 때마다 SimpleMappingExceptionResolver를 무시하고 ExceptionTranslationFilter를 통해 예외 처리를 하게 됩니다.



- 내 해결 방식 -

내 프로젝트에서는 위와 같이 설정하기 난해한 부분이 있어서 중복이여서 아쉽지만 web.xml에 이동 페이지를 설정하게 해주었다.


web.xml



Reference

[1] Spring Security ignoring access-denied-handler with Method Level Security (http://stackoverflow.com/questions/21171882/spring-security-ignoring-access-denied-handler-with-method-level-security)



Leave a Comment

간단하지만 생각보다 어려운 설정 문제로 인해서 한참 고생을 했다.

Spring Security에서 기존에 있는 공통 Expression 외에 별도의 Expression을 만드려고 했는데 이게 제대로 문서도 없고 관련 예제가 있는 곳도 없다.

결국 구글링으로 만들긴 만들었다만 이 간단한 커스텀 개발을 위해서 쓴 시간이 아깝긴 하다. 막상 만들고 보니 고민거리가 있어서 실제로 쓸지도 모르겠다.


이 부분을 위해서 삽질하는 분들에게 도움이 되길 바란다.

우선 custom expression에는 2가지 종류가 있다.

메서드단에 설정하는 MethodSecurityExpression과 웹쪽에 설정하는 WebSecurityExpression이 있다. 이것을 몰라서 Method만 갖고 한참 삽질을 했다.

MethodSecurityExpression은 관련 클래스나 용어로 찾다보면 자료가 많이 있다. WebSecurityExpression이 별로 없다.





Version

  • 3.1.7을 기준으로 함
  • 3.0.7을 사용하다가 DefaultWebSecurityExpressionHandler을 상속받아서 사용할 때 원하는 메서드가 없어서 3.1.7로 올려서 사용하게 되었음
  • 3.1.7의 경우 Spring 3.0.7 Version에 대해 의존하고 있어서 다행히 문제되지 않음 ([4] 참조)



MethodSecurityExpression

  • 관련 클래스
    • DefaultMethodSecurityExpressionHandler
    • SecurityExpressionRoot
    • MethodSecurityExpressionOperations
  • 메소드쪽에 제한 설정
  • @PreAuthorize와 함께 사용



WebSecurityExpression

  • 관련 클래스
    • WebSecurityExpressionRoot
    • DefaultWebSecurityExpressionHandler
  • 웹쪽(xml or java config)에 설정
  • http intercept-url access에 설정



spring-security.xml (3.0.7의 경우)

SpringSecurity 3.0 에서는 XML 태그를 통해 웹 전반에 관한 expressionHandler 설정이 불가능

(SEC-1452 버그 참조. 3.1부터 가능.)

access-decision-manager-ref를 지정함으로써만 가능 (권남 블로그 참조)




spring-security.xml (3.1.7의 경우)



CustomWebSecurityExpressionHandler.java



CustomSecurityExpressionRoot.java




기타 참고 소스 1 - CustomMethodSecurityExpression


CustomMethodSecurityExpressionHandler.java


CustomMethodSecurityExpressionRoot.java


기타 참고 소스 2 - CustomAuthenticationToken


CustomAuthenticationToken.java


SampleCode - JaasGrandtedAuthority(3.1.7 사용 가능), SimpleGrantedAuthority(상위 버전)를 사용하거나 GrantedAuthority를 직접 구현해서 사용



Reference

[1]  16. Expression-Based Access Control (http://docs.spring.io/autorepo/docs/spring-security/3.1.x/reference/el-access.html)
[2] 권남 Spring Security (http://kwonnam.pe.kr/wiki/springframework/security)

[3] Github 참고 소스 (https://gist.github.com/bmchild/1642655)

[4] Maven Repository - spring security 3.1.7 (http://mvnrepository.com/artifact/org.springframework.security/spring-security-core/3.1.7.RELEASE)





Leave a Comment


to Top