자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크
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 설정 파일
의존성이란
의존성 관계 주입(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)
제어의 역전(IoC) : 객체 관리에 대해 더이상 개발자과 관리하는 것이 아닌 DI(IoC)컨테이너가 관리하게 되는 것
package, import, lombok annotation 생략함
public class Car {
private int carNo;
private String carName;
}
public class People {
private String name;
private int age;
private Car car;
}
<?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>
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);
}
}
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 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>
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);
}
}
@Component : Bean으로 등록해주는 Annotation
@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 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>
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);
}
}
문제 : 객체의 참조 대상이 null로 출력됨 → xml의 Namespaces에서 context 체크 및 저장, xml파일에 <context:annotation-config /> 추가, 참조 대상이 되는 필드에 @Autowired 추가 →
@Autowired 사용 시 여러 개의 참조대상객체가 있으면 다시 문제 발생 → @Qualifier 를 사용하여 하나의 객체로 지정해줌 →
이번엔 그 해당 객체가 삭제되면 다시 문제 발생 → Autowired(required = false) 를 사용하여 지정 객체가 없더라도 객체를 생성하게끔함
Spring 또한 개념적으로 이해해야하는 부분이 많음
Spring으로 객체를 주입하는 것은 방법이 너무 많음
@Component 까지 빌드업되면서 이해하면서 사용하는 방법에 아직 미숙함
오늘 발생한 예외는 사용하면서 특별한 상황이 생기면 예외가 꼬리에 꼬리가 무는 형식이였다.
반의도적으로 예외를 만들었지만 상황에 따라 예외가 추가적으로 발생하는 상황이 생길 수도 있다는 것을 고려해야겠다.