[Spring] Spring, POJO, IOC, DI

JH·2023년 4월 25일

Spring

목록 보기
1/9

1. TIL

A. Spring

자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크

  • POJO (Plain Old Java Object) 기반의 구성 : 일반적인 Java 코드로 객체 구성 가능(특정 라이브러리에 종속적이지 않음)

  • IoC (Inversion of Control) : 제어의 역전
    DI (Dependency Injection) : 의존성 주입

  • 엔터프라이즈급 애플리케이션 개발을 위한 종합 기능 경량화 솔루션

환경설정

Spring Reference
https://docs.spring.io/spring-framework/docs/

Spring framework 구성
https://docs.spring.io/spring-framework/docs/5.0.0.RC2/spring-framework-reference/images/spring-overview.png

STS : Eclipse 기반의 Spring 최적화 IDE
https://github.com/spring-attic/toolsuite-distribution/wiki/Spring-Tool-Suite-3#full-distribution-on-eclipse-416

Maven : Java 기반 프로젝트 빌드 자동화 도구 (pom.xml 파일을 통해 설정 관리)
https://mvnrepository.com/


Project Structure
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet-context-hierarchy

구조

- src/main/java : 자바 소스 코드
- src/main/resources : 프로젝트 실행시 필요한 설정 (xml, properties, ...)
- src/main/webapp : maven을 통해 생성된 Web 프로젝트 기본 directory
- src/main/resources : static 파일(js, css, image, ...)
- src/main/webapp/WEB-INF : 외부에서 접근 불가능
- src/main/webapp/WEB-INF/classes : 컴파일된 클래스 파일
- src/main/webapp/WEB-INF/spring : 스프링 환경 설정 파일
- src/main/webapp/WEB-INF/views : 프로젝트 페이지 파일(html, jsp)
- src/test/java : 자바 테스트 코드
- src/test/resources : 테스트시 필요한 설정
- servlet-context.xml : servlet 요청관련 객체 정의(ViewResolver, Interceptor, 등)
- root-context.xml : view 기능을 제외한  비즈니스 로직 객체 설정(service, repository, 등)
- web.xml : WAS 구동시 웹 관련 설정
- pom.xml : Maven 설정 파일


B. DI

1. DI (Dependency Injection)

의존성이란

  • 한 객체가 다른 객체를 사용할 때
  • 기능 추가 또는 변경 시, 소스 코드 변경이 불가피

의존성 관계 주입(DI) : 의존 관계를 주입하는 것
Spring에서는 개발자가 아닌 DI컨테이너가 관리함


XML 생성자 주입 (Constructor Injection)

<bean id="고유값" class="지정 클래스">
	<constructor-arg name="" value="" />
</bean>

XML 필드 주입 (Field Injection)

<bean id="고유값" class="지정 클래스">
	<property name="" value="" />
	<property name="" ref="참조bean 고유값" />
</bean>

Annotation 생성자 주입

// ver1
public class Market {
	private Product product;
			    
	@Autowired 
	public Market(Product product) {
	this.product = new Product();
	}
}
			
// ver2
@RequiredArgsConstructor
public class Market {
	private final Product product;
	}

Annotation 필드 주입

public class Market {
	@Autowired
	private Product product;
	}

Annotation 수정자 주입

public class Market {
	private Product product;
	@Autowired
	public void setProduct(Product product) {
		this.product = product
	}
}

Bean : DI 컨테이너가 관리하는 자바의 POJO(Plain Old Java Object)


C. IoC (Inversion of Control)

1. IoC

제어의 역전(IoC) : 객체 관리에 대해 더이상 개발자과 관리하는 것이 아닌 DI(IoC)컨테이너가 관리하게 되는 것


D. Ex)

package, import, lombok annotation 생략함

1. XML로 생성자, 필드 주입

Class

public class Car {
	private int carNo;
	private String carName;
}
public class People {
	private String name;
	private int age;
	private Car car;
}

xml

<?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="c1" class="step01.model.domain.Car">
		<constructor-arg name="carNo" value="1001"/>
		<constructor-arg name="carName" value="c1"/>
	</bean>
	
	<bean id="p1" class="step01.model.domain.People">
		<property name="name" value="DEV" />
		<property name="age" value="26" />
		<property name="car" ref="c1" />
	</bean>
	
	<bean id="p2" class="step01.model.domain.People">
		<property name="name" value="DEVOPS" />
		<property name="age" value="29" />
		<property name="car" ref="c1" />
	</bean>
	
	<!-- 
		property 는 아래 처럼 객체를 만듦
		People p1 = new People();
		p1.setName("DEV");
	 -->
	 
</beans>

Main

public class Test01 {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("step01.xml");
		
		// step01
		// context 영역이 있는 객체를 들고온거임
		Car c1 = context.getBean("c1", Car.class); //Car객체에 대한 클래스를 가져옴
		System.out.println(c1);
		
		People p1 = context.getBean("p1", People.class);
		System.out.println(p1);
		
		People p2 = context.getBean("p2", People.class);
		System.out.println(p2);
		
		// p1, p2 같은 객체, 다른 객체? --> 다른 객체임
		System.out.println(p1 == p2);
		
		// p2, p3 같은 객체, 다른 객체? --> 같은 객체(기본적으로 컨텍스트는 : singleton 방식으로 객체를 만듦)
		People p3 = context.getBean("p2", People.class);
		System.out.println(p2 == p3);
	}

}

2. Annotation으로 주입

Class

public class Car {
	private int carNo;
	private String carName;
}
public class People {
	private String name;
	private int age;
	
	@Autowired(required = false) // required = false : 지정 객체가 존재하지 않더라도 기본 null 값으로 People 객체를 생성함
	@Qualifier("c2") // 여러 개의 주입 대상 객체가 존재할 때 하나의 객체를 지정하는 것
}

xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<context:annotation-config />

	<bean id="c1" class="step02.model.domain.Car" />
	<bean id="c2" class="step02.model.domain.Car" />
		
	<bean id="p1" class="step02.model.domain.People" />
</beans>

Main

public class Test2 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("step02.xml");
		
		Car c1 = context.getBean("c1", Car.class);
		System.out.println(c1);
		
		People p1 = context.getBean("p1", People.class);
		System.out.println(p1);
	}
}

3. @Component

@Component : Bean으로 등록해주는 Annotation

Class

@Component
public class Car {
	private int carNo;
	private String carName;
}
@Component
public class People {
	private String name;
	private int age;
	
	@Autowired(required = false)
	@Qualifier("c2") // c2가 없어도 required 때문에 알아서 참조함

xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

	<context:component-scan base-package="step03.model.domain"></context:component-scan>
</beans>

Main

public class Test3 {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("step03.xml");
		
		Car c1 = context.getBean(Car.class);
		System.out.println(c1);
		
		People p1 = context.getBean(People.class);
		System.out.println(p1);
	}
}


2. 에러

문제 : 객체의 참조 대상이 null로 출력됨 → xml의 Namespaces에서 context 체크 및 저장, xml파일에 <context:annotation-config /> 추가, 참조 대상이 되는 필드에 @Autowired 추가 →

@Autowired 사용 시 여러 개의 참조대상객체가 있으면 다시 문제 발생 → @Qualifier 를 사용하여 하나의 객체로 지정해줌 →

이번엔 그 해당 객체가 삭제되면 다시 문제 발생 → Autowired(required = false) 를 사용하여 지정 객체가 없더라도 객체를 생성하게끔함


3. 보완 해야 할 것

Spring 또한 개념적으로 이해해야하는 부분이 많음

Spring으로 객체를 주입하는 것은 방법이 너무 많음
@Component 까지 빌드업되면서 이해하면서 사용하는 방법에 아직 미숙함


4. 느낀점

오늘 발생한 예외는 사용하면서 특별한 상황이 생기면 예외가 꼬리에 꼬리가 무는 형식이였다.

반의도적으로 예외를 만들었지만 상황에 따라 예외가 추가적으로 발생하는 상황이 생길 수도 있다는 것을 고려해야겠다.

profile
잘해볼게요

0개의 댓글