xml 파일에 bean태그를 이용하여 bean을 직접 정의할 수 있다.

bean태그에는 bean객체의 생성시점과 생명주기를 직접 설정할 수 있는 속성들이 있다 한개한개 알아보자.

 

 

 

lazy-init

 

게으른..초기화..? 

이 속성을 true값으로 설정하면 xml을 로딩할 때 객체가 바로 생성되지 않고 getBean을 사용해야 객체가 생성된다.

 

 

 

<bean id="t1" class="com.study.spring.beans.TestBean" lazy-init="true"/>

 

 

// 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);

 

 

 

 

 

 

 

scope

 

scope속성이 singleton이면 한번 생성된 객체가 다시 생성되지 않는다. (singleton이 default값이다.)

scope속성이 prototype이면 호출 될 때마다 객체를 생성할 수 있다.

 

 

 

<bean id="t1" class="com.study.spring.beans.TestBean" lazy-init="true" scope="prototype" />

 

 

 

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컨테이너 내에 존재하던 모든 객체는 소멸된다.)

 

 

 

<bean id="t1" class="com.study.spring.beans.TestBean" lazy-init="true" init-method="beanInit" destroy-method="beanDestroy" />

 

 

 

 

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값을 이용하여 함수를 활용하면 되겠다.

'JAVA > Spring' 카테고리의 다른 글

컬렉션 주입  (0) 2020.04.09
의존성 주입 (Dependency Injection)  (0) 2020.04.09
IoC 컨테이너  (0) 2020.04.07
Maven 설정  (0) 2020.04.07
스프링 MVC 프레임워크의 구조  (0) 2020.03.31

IoC (Inversion Of Control) : 제어역전

 

 

어떠한 제어권을 역전한다는 이야기냐...?

 

어떠한 객체를 생성하거나, 그 객체를 셋팅하거나, 객체를 활용하여 작업을 한다거나 ..

이 모든것은 개발자가 해왔다. 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도 알아보자..!

 

- 클래스를 통해 객체를 생성, 전달

- 상속 등 객체관의 관계를 형성, 관리

 

이정도의 기능이 있다고 한다. 말로만 봐서는 그냥 '그렇군.' 싶은데 .. 코드로 봐야겠다.

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="test1" class="com.study.spring.beans.TestBean" />
</beans>

 

 

 

beans.xml 파일이다.

test1이라는 이름의 빈을 한개 만들었고 클래스패스를 입력해주었다.

 

 

 

public static void test1() {
	ClassPathResource resource = new ClassPathResource("com/study/spring/config/beans.xml");
	XmlBeanFactory factory = new XmlBeanFactory(resource);

	TestBean t1 = factory.getBean("test1", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = factory.getBean("test1", TestBean.class);
	System.out.printf("t1 : %s\n", t2);
}

 

 

 

BeanFactory에서 빈을 활용하기 위해서는 ClassPathResource 를 사용하여 빈을 만든 xml의 path를 정의해준다.

XmlBeanFactory 에 ClassPathResource에서 만든 변수를 넣어줌으로서 활용이 가능하다.

factory.getBean하여 정의해준 bean 객체를 가지고 옴으로써 활용할 수 있겠다.

 

t2라는 변수를 한번더 테스트 해본 이유는 IoC컨테이너의 특성을 알아보기 위해서이다.

id가 test1인 bean객체를 가져올 때 객체가 생성되어 있지 않는 상태라면 객체를 생성한 후 주소값을 받고 그 객체를 버리지 않고 가지고 있다. (IoC컨테이너에서 컨테이너는 보관의 개념인가보다.)

그러므로 똑같은 id의 bean객체를 가져오면 두 결과는 같은 객체가 되겠다.

즉, 생성된 객체는 더이상 생성되지 않으며 Singleton이라고 할 수 있겠다.

 

 

 

 

그런데

 

만약 beans.xml파일이 패키지 내부가 아닌 패키지 외부에 있다면????

 

 

 

public static void test2() {
	FileSystemResource resource = new FileSystemResource("beans.xml");
	XmlBeanFactory factory = new XmlBeanFactory(resource);

	TestBean t1 = factory.getBean("test2", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = factory.getBean("test2", TestBean.class);
	System.out.printf("t2 : %s\n", t2);
}

 

 

ClassPathResource 대신에 FileSystemResource를 사용해주면 되겠다. 그리고 xml의 경로 역시 패키지의 경로를 제외하고 beans.xml만 써주면 된다.

 

 

 

 

 

 

 

 

2. ApplicationContext

BeanFactory보다는 더 많이 활용되는 ApplicationContext이다.

 

- 클래스를 통해 객체를 생성, 전달

- 상속 등 객체관의 관계를 형성, 관리

- Bean에 이벤트를 발생시킬 수 있음

.. 등등

 

BeanFactory가 가지고 있는 기능을 포함한 더 많은 기능을 가지고 있다.

 

 

 

public static void test3() {
	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/study/spring/config/beans.xml");

	TestBean t1 = ctx.getBean("test1", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = ctx.getBean("test1", TestBean.class);
	System.out.printf("t2 : %s\n", t2);

	ctx.close();
}

 

 

ApplicationContext를 사용할 때에는 ClassPathXmlApplicationContext 를 사용하여 xml의 패스를 넣어주기만 하면 해당 bean객체를 자동으로 생성해준다.

 

자동으로 객체를 생성해주는 시점은 사용자가 변경해 줄 수 있다.

Default값은 getBean을 하지 않아도 자동으로 객체를 생성해주었다.

 

BeanFactory에서의 예제와 마찬가지로 ApplicationContext도 객체를 생성하고 보관하고 있기 때문에 t1과 t2는 같은 객체라는 결과를 얻을 수 있었다.

 

 

 

 

 

beans.xml이 패키지의 외부에 있다면??

 

 

 

public static void test4() {
	FileSystemXmlApplicationContext fctx = new FileSystemXmlApplicationContext("beans.xml");

	TestBean t1 = fctx.getBean("test2", TestBean.class);
	System.out.printf("t1 : %s\n", t1);

	TestBean t2 = fctx.getBean("test2", TestBean.class);
	System.out.printf("t1 : %s\n", t2);

	fctx.close();
}

 

 

ClassPathXmlApplicationContext 대신에 FileSystemXmlApplicationContext 를 사용하여 xml파일의 path를 지정해주면 되겠다.

'JAVA > Spring' 카테고리의 다른 글

컬렉션 주입  (0) 2020.04.09
의존성 주입 (Dependency Injection)  (0) 2020.04.09
Bean 객체의 생성시점과 생명주기  (0) 2020.04.08
Maven 설정  (0) 2020.04.07
스프링 MVC 프레임워크의 구조  (0) 2020.03.31

Maven이란?

 - 자바 프로젝트의 빌드를 자동으로 해주는 도구!

 

개발자가 xml에 작성한 프로젝트 정보를 토대로 컴파일을 하고, 라이브러리를 연결하는 등의 작업을 해준다.

Maven 서버를 통해 라이브러리를 다운받아서 설정하는 작업또한 수행한다.

 

 

 

간단하게 이클립스에서 메이븐 프로젝트를 생성하고, pom.xml을 활용하여 의존성을 설정해보자.

 

spring.io 홈페이지에 접속하여 스프링 최신버전이 뭔지 보니... 

5.2.5버전이 최신버전이다. ok

 

구글에 maven이라고 검색하니까 mvnrepository 사이트가 나온다.

여기에 spring context라고 검색하면 spring버전이 나온다. 

최신버전의 사용을 해보자. 5.2.5 relese를 클릭해보았다.

 

아래 Maven탭에 있는 코드를 클릭하면 자동으로 복사된다.

해당 내용을 pom.xml파일에 붙여넣었더니 자동으로 설치가 된다.

 

 

 

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.5 RELESE</version>
  </dependency>
</dependencies>

 

 

 

 

로그를 활용하기 위해서

 

slf4j 와 logback도 같은 방법으로 추가했다.

 

 

 

 

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.study.spring</groupId>
	<artifactId>SpringBasic</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<!-- xml에서 사용할 속성들 -->
	<properties>
		<!-- 자바 버전 -->
		<java-version>1.8</java-version>
		<!-- 스프링 버전 -->
		<!-- <org.springframework-version>5.2.5.RELEASE</org.springframework-version> -->
		<org.springframework-version>4.3.25.RELEASE</org.springframework-version>
		<org.slf4j-version>1.7.30</org.slf4j-version>
		<logback-classic-version>1.2.3</logback-classic-version>
	</properties>

	<!-- 프로젝트에서 사용할 라이브러리 버전 -->
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback-classic-version}</version>
			<exclusions>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>slf4j-api</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>
	</dependencies>
    
</project>

 

 

 

xml에서 빠르게 속성을 변경하기 위해서 맨위에 버전들을 따로 정리하였다.

 

 

 

Maven Dependencies가 정상적으로 추가됨을 확인할 수 있었다.

'JAVA > Spring' 카테고리의 다른 글

컬렉션 주입  (0) 2020.04.09
의존성 주입 (Dependency Injection)  (0) 2020.04.09
Bean 객체의 생성시점과 생명주기  (0) 2020.04.08
IoC 컨테이너  (0) 2020.04.07
스프링 MVC 프레임워크의 구조  (0) 2020.03.31

MVC패턴 Model2 의 그림이다.

 

MVC Model2

 

 

1. 클라이언트가 요청하면 Controller가 그 요청을 받고,

2. 받은 요청에 대한 적절한 Service를 찾고,

3. 그 서비스가 DAO와 연결되어

4. DAO는 적절한 쿼리문을 활용하여 데이터베이스에서 결과를 얻고,

5. 얻어진결과가 return되어 service -> controller 단까지 올라가고,

6. controller에서 적절한 view를 return 한다.

 

 

스프링 MVC 프레임워크 구조

 

 

1. 클라이언트가 요청하는 내용을 DispatcherServlet이 받는다.

2. 요청을 HandlerMapping이 받아서 적절한 Controller를 찾아준다.

3. HandlerAdapter가 해당 Controller에서 적절한 Method를 찾아준다.

4. MVC모델 2패턴으로 구현된 어플리케이션이라면, 여기서 controller -> service -> DAO -> DB 의 과정이 일어난다.

5. 적절한 반환값을 DispatcherServlet이 받는다.

6. ViewResolver가 처리결과를 출력한 적잘한 View를 찾는다.

7. View가 실행되어 클라이언트가 결과를 본다.

 

 

'JAVA > Spring' 카테고리의 다른 글

컬렉션 주입  (0) 2020.04.09
의존성 주입 (Dependency Injection)  (0) 2020.04.09
Bean 객체의 생성시점과 생명주기  (0) 2020.04.08
IoC 컨테이너  (0) 2020.04.07
Maven 설정  (0) 2020.04.07

+ Recent posts