$ sudo service docker start  
Redirecting to /bin/systemctl start docker.service  
Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.

실행하려니 실패.

$ systemctl status docker.service  
● docker.service - Docker Application Container Engine  
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)  
   Active: failed (Result: exit-code) since 화 2022-04-05 12:17:01 KST; 12s ago  
     Docs: [https://docs.docker.com](https://docs.docker.com)  
  Process: 25074 ExecStart=/usr/bin/dockerd (code=exited, status=1/FAILURE)  
 Main PID: 25074 (code=exited, status=1/FAILURE)

상세 사유 없어서 확인이 안됨.

이럴땐 도커 데몬을 직접 실행해본다.

$ sudo dockerd --debug  
Error starting daemon: Error initializing network controller: Error creating default "bridge" network: failed to allocate gateway (10.252.0.0): Address already in use

나의 경우 bridge ip 설정 떄문에 실패한 것.

'개발 > 기타' 카테고리의 다른 글

[SpringSecurity] Https same origin 에 대한 CORS 설정  (0) 2020.06.09
URI와 URL의 개념, 차이  (2) 2020.05.23
SAML / OAuth2.0 / OpenIDConnect  (1) 2020.05.12
[PHP] Call to undefined function dl()  (0) 2020.02.10
카프카(Kafka)  (0) 2020.01.30

이것 저것 찾아보던 중 제일 깔끔하게 잘 돌아가는 것 발견!

'개발' 카테고리의 다른 글

[Vue.js] 템플릿에서 상수 접근하기  (0) 2020.07.15
Java 리팩토링하면서 느낀 것들  (0) 2020.06.25
개발 시 패키지 구조 설정  (0) 2020.06.24

1. data에 property를 선언한다.

  • 컴포넌트마타 property를 선언해줘야하는 번거로움.
  • 리액티브로 관리된는 오버헤드 (상수는 리액티브하지 않아도 되는데)

2. create 훅에서 property를 선언한다.

  • create 훅은 이미 observation 단게가 끝난 후에 호출되는 것이므로, 여기서 property를 선언하면 리액티브 시스템에서 관리되지 않는다.
  • 이것도 컴포넌트마다 property를 선언해줘야 하는 번거로움이 있다.

    3. 플러그인 만들어 사용하기

  • 아래 링크 참조
  • 컴포넌트마다 property 선언 안해줘도 된다.

https://coderethinked.com/3-different-ways-to-access-constants-in-a-vue-template/

'개발' 카테고리의 다른 글

[Vue.js] masonry layout 플러그인  (0) 2020.07.17
Java 리팩토링하면서 느낀 것들  (0) 2020.06.25
개발 시 패키지 구조 설정  (0) 2020.06.24

enum 클래스를 활용하자.

String 상수로 정의한 경우 정해진 값 외에 값이 들어와도 정적 체크가 안된다.
enum을 활용하면 정적 체크가 가능하다.

에러 로그엔 컨텍스트가 담겨야한다.

에러가 어떤 인풋에서 기타 다른 조건은 어떠했는지등을 남겨야 한다.
띡하고 에러만 남기면 어디서 부터 디버깅을 시작해야 할지 알 수 없다.

INFO 레벨 로그 또한 컨텍스트가 담겨야 한다.

컨텍스트 없는 로그는 반쪽자리다.

로그는 시간이 지나고 봐도 의미를 알 수 있어야 한다.

개발 할때 대충 간략하게 로그 메시지를 작성하게 되면 시간이 지나거나 다른 사람이 보면 이해할 수 없게 된다.
누가봐도 이 로그가 어떤걸 의미하고, 그래서 어떤 영향이 있는지 등을 알 수 있게 작성하자.

catch를 아무데서나 하지 말자

그 에러에 대한 처리 방향을 결정할 수 있는 위치에서 catch 해줘야 한다.
어떤 인터페이스가 throw 한다고 해서 무조건 그 자리에서 catch 해버리는 것은 의미 없다.
또한 에러를 먹어버리거나 임의값을 리턴한다든지 하는 경우 2차 사고를 낳고 디버깅을 어렵게 한다.

if, else if의 연속...

status를 체크하고 싶어
상태전이가 A -> B -> C 로 된다고 할때

if(currentStatus.equals(A) && nextStatus.equals('B')) return true;
if(currentStatus.equals(B) && nextStatus.equals('C')) return true;
return false;

이렇게 작성하면 보기도 어렵고 상태가 추가될때 마다 코드가 늘어난다.
일때 enum 클래스 내부에 상태전이 사전조건에 대한 것을 한 단계 추상화하여

enum Status {
 Status condition;
}

if(currentStatus.equals(currentStatus.condition)) return true;
return false;

Status 클래스에만 추가하면 로직은 더 이상 건드리지 않아도 된다.

'개발' 카테고리의 다른 글

[Vue.js] masonry layout 플러그인  (0) 2020.07.17
[Vue.js] 템플릿에서 상수 접근하기  (0) 2020.07.15
개발 시 패키지 구조 설정  (0) 2020.06.24

보통 레이어에 따라

controller
service
domain
mapper

등으로 패키지 구조를 잡았는데, 프로젝트가 커지다보면 각 피쳐 별로 클래스가 산재되어있어 유지보수가 어려워 어떤 것이 Best Practice인지 찾아보게 되었다.

from : https://stackoverflow.com/questions/3226282/are-there-best-practices-for-java-package-organization

One package per module/feature, possibly with sub-packages. Put closely related things together in the same package. Avoid circular dependencies between packages.

  1. 피쳐/모듈 별로 패키지를 나눈다.
  2. 각 피쳐/모듈 패키지는 서브 패키지를 가질 수 있다.
  3. 각 패키지별 순환 참조가 생기지 않도록 한다.

이렇게 관리하면 연관된 클래스가 가까이 있어 유지보수가 쉬워지지 않을까 생각한다.

레이어별, 피쳐별 각각 장단점이 있겠지만, 프로젝트 구조가 커지면 피쳐별로 관리하고, 그 안에서 레이어를 나누는게 낮지 않을까하는 생각

'개발' 카테고리의 다른 글

[Vue.js] masonry layout 플러그인  (0) 2020.07.17
[Vue.js] 템플릿에서 상수 접근하기  (0) 2020.07.15
Java 리팩토링하면서 느낀 것들  (0) 2020.06.25

기존 스프링 Security에서 same-origin의 경우 별도 CORS설정을 안해줘도 문제가 없었지만

origin이 Https가 되는 경우엔 cors 설정을 해줘야 한다. 

 

이렇게 Origin 헤더가 https인 경우 CORS 설정이 필요하다. 

Origin: https://test.io

 

또한 allow method 디폴트가 GET,HEAD, POST 이므로

PUT과 같은 method를 사용하는 경우

  public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
      @Override
      public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedMethods("*")
            .allowedOrigins("https://test.io")
            .allowedHeaders("*")
            .allowCredentials(true);
      }
    };
  }

registry.allowedMethods("*") 설정이 필요하다. 

 

'개발 > 기타' 카테고리의 다른 글

Docker service 실행 안될 때  (0) 2022.04.05
URI와 URL의 개념, 차이  (2) 2020.05.23
SAML / OAuth2.0 / OpenIDConnect  (1) 2020.05.12
[PHP] Call to undefined function dl()  (0) 2020.02.10
카프카(Kafka)  (0) 2020.01.30

스프링 빈 라이프사이클

라이프사이클

스프링의 빈은 스프링이 빈 생성, 주입, 소멸까지를 책임진다. 빈 생성부터 소멸까지의 라이프사이클을 다뤄보고자 한다.

라이프사이클 콜백

컨테이너가 빈의 라이프사이클을 관리하는데, 라이프사이클의 특정 시점에 커스텀 로직을 넣을 수 있도록 한 것이 라이프사이클 콜백이다.

라이프사이클 살펴보기

1. XML이나 어노테이션을 탐색하여 빈 정의를 스캔

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

SpringApplication.run()에서 어플리케이션컨텍스트를 만들고 빈 정의를 탐색하기 시작한다.

2. 빈 클래스의 인스턴스를 생성 - 생성자 호출

정의된 빈 인스턴스를 생성한다. 이때 생성자를 호출한다.

3. 빈 안에 주입되야할 프로퍼티들을 셋팅한다.

@Component
public class HelloBean implements ApplicationContextAware, InitializingBean {
    @Autowired
    WorldBean worldBean;
}

빈 안에 프로퍼티를 주입해야 하는데 프로퍼티에 해당하는 빈이 아직 생성되지 않은 경우 그 빈부터 생성해준다.
빈 간에 순환참조가 있으면 빈 생성과정에 에러가 발생하게 된다.

3. ~Aware 관련 콜백 호출

예를 들면 다음과 같은 것들이 있다.

ApplicationContextAware.setApplicationContext - 어플리케이션컨텍스트를 받을 수 콜백,
BeanClassLoaderAware.setBeanClassLoader - 클래스로더를 받을 수 콜백

이걸 써서 컨텍스트나 클래스로더를 따로 저장해둬야하는 상황이 어떤게 있을까....

이런 콜백들을 호출하려면 각 인터페이스를 implement해야한다.

package sample;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class MyBean implements ApplicationContextAware, BeanClassLoaderAware {

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        // do something
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // do something
    }
}

4. @PostContruct, InitializingBean.afterPropertiesSet(), init-method

셋은 프로퍼티 및 종속성 주입이 완료된 후 호출되는 점에서 동일하다.

@PostContruct는 JSR-250에서 정의한 어노테이션으로 스프링이 아닌 프레임워크에서도 사용할 수 있는 콜백이고, InitializingBean.afterPropertiesSet(), init-method는 스프링에서 제공하는 콜백이다.

InitializingBean.afterPropertiesSet()의 경우 InitializingBean 인터페이스를 implement하면 된다.

@Component
public class HelloBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        logger.info("afterPropertiesSet() called");
    }
}

init-method의 경우 @Bean(initmethod="..")으로 등록한 메서드가 실행되게 된다.

실행 순서는 @PostContruct -> InitializingBean.afterPropertiesSet() -> init-method 이다.

세 가지 콜백을 각각 언제 사용해야 하는지를 명확히 구분할 수는 없다.

참고로 BeanPostProcessor.postProcessBeforeInitialization() 안에서 @PostContruct 가 호출된다.

5. BeanPostProcessor.postPRocessAfterInitialization()

기본 스프링부트 설정을 사용하는 경우 BeanPostProcessor를 따로 설정하지 않는 한 이 단계에서 하는 일은 없다.

이렇게 되면 빈을 사용할 수 있는 상태가 된다.
빈이 제거 될 때 설정할 수 있는 콜백도 생성과 비슷하다.

'개발 > Spring' 카테고리의 다른 글

[Java, Spring] Filter와 Interceptor의 차이  (0) 2020.05.22
[SpringMVC] CORS 처리  (2) 2020.03.31

자바 언어에 타입 파라미터라는 개념을 도입한 것이 제네릭스(Generics)이다.
인터페이스나 메서드에서 처리할 타입을 사용하는 쪽에서 지정할 수 있다.

가장 쉬운 예로 List 인터페이스는 제네릭스 기반으로 작성되었다.

List  
booelan add(E e);  
E get(int index);

List<Integer> list; 혹은 List<String> list; 등 사용하는 쪽에서 지정하는 것이다.

제네릭스가 없다면 여러 타입을 담으려면 결국 모든 클래스의 조상인 Object로 지정해야 했을 것이다.

List  
boolean add(Object object);  
Object get(int index);

이렇게 하면 발생하는 문제는 다음과 같다.

  1. 형변환
    매번 사용할 때마다 형변환을 해줘야 한다.

    Integer 타입을 예로 들면,

    Integer value = 4;
    add((Object) value);
    (Integer) ret = get(1);
  2. 타입 체크가 안됨
    Integer 리스트를 만들었는데 모르고 Long을 넣어도 알 수가 없다.

    Long value = 4L;
    add((Object) value);

이러한 이유로 제네릭스를 이용하는 것이 좋다.

참고자료

토비의 스프링 3.1, 이일민

+ Recent posts