spring에서는 String > double > int 순서로 우선순위를 가진다. 그러므로 만약 type속성을 아무것도 지정해주지 않았는데, TestBean 클래스에 String형을 매개변수로 받는 생성자가 정의되어 있다면 value값은 자동으로 String으로 인식된다.
최우선순위가 String이므로 만약 type이 String이면 굳이 써주지 않아도 되지만..
쓰고 싶다면, java는 String이 클래스이기 때문에 그냥 type="string" 이 아닌, type="java.lang.String" 과 같이 써주어야 하겠다.
또한 , 위와 같이 xml에 bean을 정의하는데 생성자를 통해 주입할때 생성자 매개변수의 순서는 크게 상관이 없다.
먼소리냐고?
생성자중에 다음과 같이 int, double, String 순서로 매개변수를 받는 생성자가 존재한다고 치자.
만약 자바에서,
이런식으로 객체를 생성했다면? 당연히 오류가 난다. 저런 매개변수를 갖는 생성자를 찾을 수 없기 때문이다.
lazy-init이 true이므로 getBean을 호출해야 객체가 생성되며, scope가 prototype이므로 getBean을 호출 할 때마다 다른 객체가 생성된다.
// xml이 로딩됨. lazy-init속성이 true이기 때문에 이때 객체가 생성되지 않는다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/study/spring/config/beans.xml");
// getBean을 사용하여 bean을 블러옴. lazy-init속성이 true이기 때문에 이때 객체가 생성된다.
TestBean t1 = ctx.getBean("t1", TestBean.class);
// getBean을 이용하여 동일한 bean인 "t1"을 호출하였지만 t1과 t2는 서로 다른 객체이다.
TestBean t2 = ctx.getBean("t1", TestBean.class);
init-method 와 destroy-method
init-method는 객체가 생성될 때 호출되는 메소드를 정의하는 속성이다.
destroy-method는 객체가 소멸될 때 호출되는 메소드이다. (ctx.close(); 하면 IoC컨테이너 내에 존재하던 모든 객체는 소멸된다.)
TestBean 클래스에 beanInit 메소드와 beanDestroy 메소드가 사용자에 의해 각각 "init메소드", "destroy메소드" 라고 출력하도록 정의되었다고 가정한다. 위와 같이 bean을 정의 하였다면,
// xml이 로딩됨. lazy-init속성이 true이기 때문에 이때 객체가 생성되지 않는다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/study/spring/config/beans.xml");
// getBean을 사용하여 bean을 블러옴. lazy-init속성이 true이기 때문에 이때 객체가 생성된다.
// init-method가 정의되어 있으므로 이곳에서 호출된다.
TestBean t1 = ctx.getBean("t1", TestBean.class);
System.out.printf("%s : t1객체입니다.\n", t1);
// destroy-method가 정의되어 있으므로 이곳에서 호출된다.
출력결과는
init메소드
com.study.spring.beans.TestBean@12345 : t1객체입니다.
destroy메소드
이렇게 될것이다!!
default-init-method 와 default-destroy-method
bean태그에 속성으로 정의했던 init-method와 destroy-method와는 달리 상위태그인 beans태그의 속성으로 지정된다.
만약 bean태그에 속성으로 init-method나 destroy-method가 정의되어 있지 않다면 default-init-method 나 default-destroy-method가 호출이 된다.
만약에 default-init-method 와 default-destroy-method, init-method와 destroy-method가 모두 정의되어 있다면????
default는 무시되고 bean에 지정되어 있는 메소드가 호출된다.
default-init-method 와 default-destroy-method 속성이 사용되고 있으나, 속성값으로 정의된 메소드가 정의되어 있지 않다면 .. 오류가 나지 않는다.
하지만, init-method와 destroy-method는 속성이 사용되고 있으나, 속성값으로 정의된 메소드가 정의되어 있지 않다면???? 오류난다.
즉, 메소드가 없을 경우
default-init-method 와 default-destroy-method -> 아무일도 일어나지 않음
init-method와 destroy-method -> 오류남.
BeanPostProcessor
BeanPostProcessor는 인터페이스이며 postProcessBeforeInitialization, postProcessAfterInitialization 라는 메소드를 정의하고있다.
postProcessBeforeInitialization는 init메소드가 호출되기 전에 먼저 호출되는 함수이다.
postProcessAfterInitialization는 intit메소드가 호출 된 후에 호출되는 함수이다.
즉, init메소드 호출 전 후로 가로채기 하는 메소드이다!
//init 메서드 호출 전
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("before");
return bean;
}
//init 메서드 호출 후
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("after");
return bean;
}
구현 클래스이기 때문에 Override를 해준것이고, 반환값은 Object 형인 bean이다.
bean객체마다 다음 메소드들을 활용하려면 String형 beanName매개변수를 사용하여 bean객체의 id값을 이용하여 함수를 활용하면 되겠다.
이 모든것은 개발자가 해왔다. spring을 사용해본적이 없는 나는 이게 아주 당연하다고 생각했다.
그런데
IoC는 개발자가 몇가지 셋팅만으로 전체 프로그램을 제어하는 제어권을 프레임워크가 가지는 것을 의미한다.
개발을 하다보면 반복되는 작업이 많은데 그런것을 프레임워크에 미리 구현을 해둔것.
'개발자는 어떠한 클래스를 이용해서 객체를 만들것이다' 와 같은 프레임워크가 판단할수 없는 것만 설정해주면 된다!
+ 2021-12-10 내용추가
스프링 핵심원리를 다시 공부하다가 보니까 설명을 너무 간단하게 한 것 같아서 추가해본다.
개발자의 입장에서 봤을 때 객체를 생성하고, 연결하고, 실행하는 흐름이 자연스러운 흐름이다. 우리가 예를 들어 스프링에서 AppConfig(DI컨테이너)처럼 구성을 담당하는 클래스를 사용함으로써 클라이언트가 직접 객체를 생성하고 연결, 실행하는 흐름이 아닌 AppConfig에서 인터페이스의 구현클래스를 설정하고 객체를 생성한다. 프로그램에 대한 제어의 흐름은 AppConfig가 모두 가지고 있는 것이며 인터페스들의 구현클래스는 그 역할에 대한 구현을 수행하는 로직만을 실행하게 된다.
이처럼 개발자가 흐름을 제어하는 것이 아니라 외부에서 흐름의 제어권을 가지게 되는 것을 제어의 역전이라고 한다.
프레임워크와 라이브러리
이 둘의 차이점은 무엇일까?
예를 들어, JUnit과 같은 프레임워크는 내가 작성한 코드를 제어하고 어떤 내부적인 로직을 통해서 코드를 대신 실행해주기 때문에 프레임워크가 맞다.
그러나 jQuery와 같은 라이브러리는 내가 코드를 작성하면서 필요할 때 사용함으로써 제어의 흐름을 내가 담당하기 때문에 프레임워크가 아니라 라이브러리이다.
POJO Class (Plain Old Java Object)
들어는 봤는데 명확하지 않았던 용어.
자바모델이나 기능, 프레임워크 등에 따르지 않고 홀로 독립적으로 단순한 기능만 가지는 객체들을 의미한다.
자바에서는 이러한 객체들을 Bean이라고도 부른다.
예를 들어서.. DB와 연동되는 소프트웨어를 구현한다고 하면
프레임워크에 영향을 받지 않는.. DAO나 VO같은 클래스가 POJO 클래스가 된다고 할 수 있겠다.
또한 학사관리 시스템을 만든다면, 학교정보나 학생들의 정보가 있는 클래스가 POJO클래스라고 할 수 있을 것.
위의 그림에서 IoC의 특징을 알 수 있었다.
제어권은 프레임워크에 있기 때문에 POJO클래스를 활용하여 스프링 컨테이너에서 작업을 진행할 때, 프로그램이 흘러가는 흐름에 대한 정보같은 것을 사용자가 만들어 주면 되겠다.
사용자가 정의한 데이터의 흐름, 위 그림에서 보이는 Metadata는 Xml 또는 자바로 만들 수 있겠다.
IoC 컨테이너의 종류
1. BeanFactory
2. ApplicationContext
1. BeanFactory
BeanFactory는 스프링 3.0이상에서는 더이상 사용되지 않고 ApplicationContext로 대체되고 있지만, 실제 업무에서는 스프링버전이 다양할 수 있기 때문에.. BeanFactory도 알아보자..!
- 클래스를 통해 객체를 생성, 전달
- 상속 등 객체관의 관계를 형성, 관리
이정도의 기능이 있다고 한다. 말로만 봐서는 그냥 '그렇군.' 싶은데 .. 코드로 봐야겠다.