원래 Spring Bean Configuration File을 만들 때 xml형식으로 Bean에 id를 주고, property에 속성(value)값을 주어서 데이터에 setter injection
을 해주었다.
원래 Spring Bean Configuration File 형식
이것을 이제 xml문서가 아닌 Java의 코드로 구현하는 방법을 알아보겠다.
- xml 설정이 너무 길어짐에 따라 그 대안으로 나타났다.
- Class/Method/Field에 Annotation을 달아 그 자체로 설정이 가능하도록 한다.(단, xml이 우선순위가 더 높다)
@Annotation
을 사용해서 데이터를 설정해준다.- 스프링(Spring)이 코드를 줄일 때 @애너테이션을 사용해서 줄인다. (일종의 약속)
@Configuration
: 선언해주면 Spring Bean Configuration File 하고 하는일이 같아진다.
@Bean
: Bean을 만드는 method (메소드 이름이 Bean의 이름(id), 반환타입이 Bean의 타입(class))
@Configuration
public class SpringBeanConfig {
@Bean
public Song song1() {
Song song = new Song();
song.setTitle("오르트구름");
song.setGenre("인디");
return song;
}
}
프로그램이 실행 중에 자신의 구조와 동작을 검사하고, 조사하고, 수정하는 것이다.
Reflection
을 이용하면 Annotation 지정만으로 원하는 클래스를 주입할 수 있다.
Annotation
은 기본적으로 활성화되지 않기 때문에 xml에 명시적인 활성화 작업이 필요하다.Legacy Project를 생성하면 자동으로 생성되는 servlet-context.xml
파일에서 진행해주면 된다.
아래 Namespaces를 눌러주면 여러가지 체크 칸이 나온다.
그 중 context - http:www.springframework.org/schema/context
를 선택해주고, source로 돌아오면된다.
그 중 context 라고 적힌 태그들을 만들여 주면된다.
- 해당 변수 및 메서드에 스프링이 관리하는 Bean을 자동으로 매핑해주는 개념이다.
- 변수, Setter, Constructor, 일반 method에 적용이 가능하다.
<property>
,<contructor-arg>
태그와 동일한 역할을 한다.@Autowired
는 주로 타입(Type)을 이용해 주입하므로 동일한 Bean타입의 객체가 여러개 있을 경우 Bean을 찾기위해@Qualifier
어노테이션을 함께 사용해야 한다.
- 유일한 빈 구별 : @autowired로 연결한 Bean목록에서 유일한 Bean을 구별한다. (@Qualifier(value="빈이름")
- 타입 지정 : 연결할 빈의 값 타입을 지정한다. @Qualifier("serviceName")
연결할 빈의 타입을 지정한 경우 springbeans.xml에 선언한 이름을 작성해 준다.
@Autowired
@Qualifier("hiService")
springbeans.xml
<bean id="hiService" class="spring.service.HiService"></bean>
특정 패키지 안의 클래스들을 scan하고, Annotation을 확인한 후 bean인스턴스를 생성한다.
@Component
@Controller
@Service
@Reposittory
등의 Annotation이 존재해야 bean을 생성할 수 있다.@Auttowired
와 @Qualifier
Annotation을 인식할 수 있다.ApplicationContext안에 이미 등록된 bean들의 Annotation을 활성화 하기 위해 사용된다.
@Auttowired
와 @Qualifier
Annotation을 인식할 수 있다.스프링 MVC Component들을 그것의 디폴트 설정을 가지고 활성화하기 위해 사용된다.
@Controller
에 요청을 보내기 위해 필요한 HandlerMapping과 HandlerAdapter를 bean으로 등록한다. (등록된 bean에 의해 요청 url과 컨트롤러를 매칭할 수 있다.)@Controller
컨트롤러 에서는 @RequestMapping, @ExceptionHandler 등과 같은 주석을 통해 해당 기능을 사용할 수 있도록 한다. (근본적으로 @Controller없이 아무것도 못한다.)servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.gdu.app01" />
</beans:beans>
위의 beans:beans태그의 속성안에 xmlns:context="http://www.springframework.org/schema/context"
속성이 들어가있는 것을 확인할 수 있다.
우선 자바 객체를 만들어준다. Song
객체와 Singer
객체 두가지를 만들어보겠다.
Singer
package com.gdu.app1.java01;
public class Singer {
// field
private String name;
private Song song; // 대표곡 1개
// constructor
public Singer() {
}
public Singer(String name, Song song) {
super();
this.name = name;
this.song = song;
}
// getter/setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Song getSong() {
return song;
}
public void setSong(Song song) {
this.song = song;
}
}
Song
public class Song {
// field
private String title;
private String genre;
// default constructor
public Song() {
}
// constructor
public Song(String title, String genre) {
super();
this.title = title;
this.genre = genre;
}
// getter/setter
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getGenre() {
return genre;
}
public void setGenre(String genre) {
this.genre = genre;
}
}
Spring Bean Configration File.java
이제 SpringBeanConfig를 만들어줄건데, SpringBeanConfigFile.xml이 아닌 Java로 만들어 줄것이다.
@Configuration
: 선언해주면 Spring Bean Configuration File 하고 하는일이 같아진다.
@Bean
: Bean을 만드는 method (메소드 이름이 Bean의 이름(id), 반환타입이 Bean의 타입(class))
package com.gdu.app1.java01;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringBeanConfig {
/*
[ 1. 메소드에 이름(id)를 주는 방법 ]
<bean id="song1" class="Song">
<property name="title" value="제목1"/>
<property name="genre" value="장르1"/>
</bean>
*/
@Bean
public Song song1() {
Song song = new Song();
song.setTitle("오르트구름");
song.setGenre("인디");
return song;
}
/*
[ 2. bean에 직접 이름(name)을 주는 방법 ]
<bean id="song2" class="Song">
<property name="title" value="제목2"/>
<property name="genre" value="장르2"/>
</bean>
*/
@Bean(name="song2") // @Bean에 name값을 지정하면 id로 사용된다.
public Song asdfghjkl() { // 이름(id)을 Bean에 줘버리면 메소드 이름은 아무거나 적어도된다.
Song song = new Song();
song.setTitle("불꽃");
song.setGenre("힙합");
return song;
}
/*
[ 3. 생성자에 값을 주는 방법 ]
<bean id="song3" class="Song">
<constructor-arg value="제목3"/>
<constructor-arg value="장르3"/>
</bean>
*/
@Bean
public Song song3() {
return new Song("우리서로사랑하지는말자", "힙합");
}
// Question.
// song1을 가지는 singer1을 만들어 보자.
// setter injection
@Bean
public Singer singer1() {
Singer singer = new Singer();
singer.setName("윤하");
singer.setSong(song1());
return singer;
}
// song2를 가지는 singer2를 name값으로 만들어 보자.
// setter injection
@Bean(name="singer2")
public Singer 한요한() {
Singer singer = new Singer();
singer.setName("한요한");
singer.setSong(asdfghjkl());
return singer;
}
// song3을 가지는 singer3을 만들어보자.
// constructor injection
@Bean
public Singer singer3() {
return new Singer("기리보이", song3());
}
}
실행을 위한 Main Class를 생성해보자.
Main Class
package com.gdu.app1.java01;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
public class SpringMain {
public static void main(String[] args) {
// 스프링(Spring)이 코드를 줄일 때 @애너테이션을 사용해서 줄인다. (일종의 약속)
AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(SpringBeanConfig.class);
Singer s1 = ctx.getBean("singer1", Singer.class);
System.out.println(s1.getName());
System.out.println(s1.getSong().getTitle());
System.out.println(s1.getSong().getGenre());
Singer s2 = ctx.getBean("singer2", Singer.class);
System.out.println(s2.getName());
System.out.println(s2.getSong().getTitle());
System.out.println(s2.getSong().getGenre());
Singer s3 = ctx.getBean("singer3", Singer.class);
System.out.println(s3.getName());
System.out.println(s3.getSong().getTitle());
System.out.println(s3.getSong().getGenre());
}
}
결과
- 0에서 100사이의 랜덤 정수 5개를 가지는
List
를 생성하고,- 임의의 상장 3가지를 담은
Set
을 생성하고,- 주소와 연락처를 담은
Map
을 생성하자.
Student Class
package com.gdu.app1.java02;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private List<Integer> scores; // 0 ~ 100 사이의 랜덤 점수 5개
private Set<String> awards; // 임의의 상장 3개
private Map<String, String> contact; // 연락처(Address, Tel)
public List<Integer> getScores() {
return scores;
}
public void setScores(List<Integer> scores) {
this.scores = scores;
}
public Set<String> getAwards() {
return awards;
}
public void setAwards(Set<String> awards) {
this.awards = awards;
}
public Map<String, String> getContact() {
return contact;
}
public void setContact(Map<String, String> contact) {
this.contact = contact;
}
}
Spring Bean Configration File.java
package com.gdu.app1.java02;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringBeanConfig {
@Bean
public Student stud() { // <bean id="stud" class="Student">
// List
List<Integer> scores = new ArrayList<Integer>();
for(int cnt = 0; cnt < 5; cnt++) {
scores.add((int)(Math.random() * 101) + 1); // 101개의 난수가 발생 (0~100)
}
// Set
Set<String> awards = new HashSet<String>();
awards.add("개근상");
awards.add("인기상");
awards.add("우수상");
// Map
Map<String, String> contact = new HashMap<String, String>();
contact.put("address", "서울");
contact.put("tel", "02-123-2342");
// 객체 데이터 생성
Student student = new Student();
student.setScores(scores);
student.setAwards(awards);
student.setContact(contact);
return student;
}
}
Main Class
package com.gdu.app1.java02;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
public class SpringMain {
public static void main(String[] args) {
AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(SpringBeanConfig.class);
Student student = ctx.getBean("stud", Student.class);
System.out.println(student.getScores());
System.out.println(student.getAwards());
System.out.println(student.getContact());
}
}