티스토리 뷰

스프링을 사용하면서도 정작 단어를 듣기만 하고 잘 모르는 경우가 있어서 정리중

 

스프링 빈이란?

 

::스프링 IoC 컨테이너가 관리하는 자바 객체를 빈이라 함

 

제어의 역전

=> 기존에는 각 객체들이 흐름을 결정하고 생성 조작을 하였지만 이 과정이 관리위임주체가 스프링이 됨.

사용자가 직접 생성하지 않고 , 객체의 생명주기를 위임한다. 이것을 제어의 역전

 

기존에는 new xxx 를 썼지만 spring에서는 Bean을 생성하는 것을 볼수 있는데 이것이 스프링에 의해서 생성, 관리되는 것이다. 

 

 

불변성(immutable)

 

string과 같은것이 불변성의 예시이다. 어?

 

String str = "a"

str = "asd"로 하면 변하지 않는가 라고 생각할수 있지만 실제론

 

asd라는 새로운 객체를 만들고 이를 참조하게 하는것.

 

물론 final 같은게 붙어도 불변성이 된다.

 

장점

 - 신뢰성이 높음. 변하지 않으니까

 - 방어 복사가 필요없음. 

 - 멀티스레드 환경에서 동기화 처리 없이 객체공유

단점

 - 객체의 값마다 새로운 객체를 만들어야 하기 때문에 메모리에 대한 성능저하 이슈가 있을수 있다.

 - 당연하지만 변경불가능, 그래서 setter가 안먹힌다(쓸수도없고)

 

참고로 StringBuilder는 mutable이라서 기존의 할당한 값을 수정하는 메소드이다.

 

이걸 글로 설명하면 이해하기 어려운데 예를들어...

boolean flag = true;
String x = "";
int idx = 0;
while(flag){
	x += idx+"";
    idx++;
    if(idx == 10000) break;
}

이렇게 되면 불변성이 문제가 된다. x += idx +""의 x는 String이기 때문에 매번 새로운 객체를 만들어야 한다.

즉 단점중 하나인 "메모리에 대한 성능저하 이슈"가 발생할수 있다. 그래서 보통 예시들이 StringBuilder를 쓰는건가

 

물론 몇번 안된다면 별 문제 없이 가바지 콜렉터가 알아서 하지만 이게 대량이면? 

 

싱글튼(SingleTon)

 

클래스의 인스턴스가 1개만 생성되는 것을 보장하는 디자인패턴 

최초 한번 메모리를 할당하고 인스턴스를 만들어서 사용하는 디자인패턴

메모리 할당이라는 점에서 이 개념은 static에서 들어봤을 것이다.

 

 - 쓰는이유

메모리낭비방지, 그리고 전역인스턴스라 다른 데이터를 공유하기 쉽다.

보통 DB 커넥션을 만들때 쓴다. 이걸 여러개 만들 이유가 없으니까...

 

 - 단점

 

빈 스코프

 

일단 스코프라는 뜻은 : 존재할수 있는 범위 라는 뜻이다.

즉 Bean이 존재할수 있는 범위인데, 스프링 빈은 싱글톤 스코프이다.

 

싱글톤은 스프링 컨테이너의 시작부터 종료까지 유지되는 가장 넓은 스코프...이라고 한다.

@Component를 붙혀서 사용한다. (Autowired 같은거 보면 사용하는걸 볼수있다.)

 

프로토타입이라는 개념이 여기서 튀어나온다.

빈의 생성과 의존관계 주입까지만 관여하고 그 이후는 관여없는 매우 짧은 스코프이다. 

@Scope("prototype") 으로 선언을 하는데 일반적으로 본적이(..)

 

수동으로한다면

 

@Scope("prototype")

@Bean

 

형태이다.

 

메모리 값을 보면 프로토타입을 부를때마다 메모리값이 다르지만

싱글톤을 부르면 메모리 값이 항상 일정하다. 

 

이렇게 설명하면 좀 이해하기 어려우니까 테스트를 해보면 

 

package com.lunastratos.mudspoon.Util.Example

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component


@Component
class SingleTonSample {

    @Autowired
    private val proto: Proto? = null

    fun getProto(): Proto? {
        return proto
    }

}
package com.lunastratos.mudspoon.Util.Example

import org.springframework.context.annotation.Scope
import org.springframework.stereotype.Component

@Component
@Scope("prototype")
class ProtoTypeSample() {

}

 

@SpringBootTest
class MudspoonApplicationTests @Autowired constructor(
	val singleTonSample : SingleTonSample,
	val protoTypeSample : ProtoTypeSample,
	val ctx : ApplicationContext

) {


	@Test
	fun singletonTest() {
		println(ctx.getBean(singleTonSample.javaClass))
		println(ctx.getBean(singleTonSample.javaClass))
		println(ctx.getBean(singleTonSample.javaClass))

		println(ctx.getBean(protoTypeSample.javaClass))
		println(ctx.getBean(protoTypeSample.javaClass))
		println(ctx.getBean(protoTypeSample.javaClass))

	}

이런 형태로 테스트를 했다.

 

위의 싱글톤은 같은 메모리 인스턴스이지만, 아래 프로토 타입은 부를때마다 다른 인스턴스이다.

프로토타입에서 싱글톤을 부르는 건 괜찮다. 프로토타입은 한번 생성되고 나서 죽으면 되니까...

문제가 되는건 싱글톤에서 프로토타입을 부르는 경우이다. 싱글톤 내에서 프로토타입이 주입되어 버려서 유지가된다.

 

예를들어 싱글톤에 count가 있고 프로토타입으로 count++;를 시키면 공유가 되어버려 데이터 오염이 생긴다.

앞에서도 말했듯이 싱글톤은 스프링 생성부터 죽음까지 계속 유지되니까. 

 

해결책은 프록시로 감싸는 것인데, 이렇게 되면 인스턴스를 매번 새로 생성할수 있게 중간 방어책을 해준다. 

 

나머지 스코프들도 보면 스코프가 대충 무슨 의미인지 이해가 되었다. 

 

웹 관련 스코프

  • request: 웹 요청이 들어오고 나갈때 까지 유지되는 스코프이다.
  • session: 웹 세션이 생성되고 종료될 때 까지 유지되는 스코프이다.
  • application: 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프이다.

 

즉 생명주기속에 움직이는 것이다.

 

 

자바 JVM 구조

 

잘 설명한 글이 있다.

 

https://ecsimsw.tistory.com/entry/%EC%9E%90%EB%B0%94-%EA%B9%8A%EC%9D%B4-%EC%95%8C%EA%B8%B0-JVM-%EA%B5%AC%EC%A1%B0?category=887812 

 

자바 깊이 알기 / JVM 구조

자바 깊이 알기 JVM의 구조, Static이란, HashTable, Garbage Collection.. 항상 정리하고자 생각만하고 실행이 안되던 나름대로의 시리즈였다. 사실 정리하면서 굉장히 간단하게 요약된 글부터, 어셈블리

ecsimsw.tistory.com

 

다양한 의존성 주입

 

1. 생성자 주입

 

@Service
public class UserServiceImpl implements UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public UserServiceImpl(UserRepository userRepository, MemberService memberService) {
        this.userRepository = userRepository;
        this.memberService = memberService;
    }
    
}

 

생성할때 주입, 이걸 사용해야 한다고 한다.

테스트 코드 생각하면...

 

2. 수정자 주입

@Service
public class UserServiceImpl implements UserService {

    private UserRepository userRepository;
    private MemberService memberService;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setMemberService(MemberService memberService) {
        this.memberService = memberService;
    }
}

 

setXXX를 사용하는 방법

 

3. 필드주입

 

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private MemberService memberService;

}

이거 많이 사용했는데 쓰면안되는거였구나 반성해야겠다

 

1번을 사용해야 하는 EU

 

 - 객체의 불변성 : 바뀔 이유가 없는데 위험하게 수정을 열어둘 이유가 없다. OOP 원칙을 어기는 것도 있고

 - 테스트 코드작성  : 3번의 경우 유닛 테스트가 불가능하다. 의존 관계가 주입되지 않아서 null 에러가 나니까..

 - 순환참조 에러 방지

 - final 써서 불변성확보 및 롬복과 결합(가능하다고 하는데 코틀린써서 영...)

 

 

@Bean, @Configuration, @Component 

 

@Bean은 메소드에 사용한다. (public...같은거)

@Bean 단독으로 사용가능, 하지만 싱글톤 보장이 안되어서 값이 바뀔수있음.

싱글톤 보장을 하려면 CLASS에 @Configuration을 쓰고 쓰자

 

@Bean을 사용하는 경우는 보통 2가지인데(실제로 개발할때 보니 그경우)

 

  • 개발자가 직접 제어가 불가능한 라이브러리를 활용할 때
  • 초기에 설정을 하기 위해 활용할 때

PasswordEncoder를 만들때 썼다. 직접 제어 불가능한 라이브러리를 사용할때  + 초기 설정에 해당했다. 

 

실제 @Bean 사용 부분, 싱글톤 보장을 위해서 @Configuration도 썼다.

 

 

 

직접 개발한 CLASS를 Bean으로 등록하고자 하는 경우 @Component 를 써야한다.

 

파일업로드, Component를 썼다.

 

왜 썼는지 모르다가 알고 쓰니까 재미있다. 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함