1. XML
스프링의 애플리케이션 컨텍스트는 XML에 담긴 DI 정보를 활용할 수 있습니다. DI 정보가 담긴 XML 파일은 <beans>를 루트 엘리먼트로 사용하고 <beans> 안에는 여러 개의 <bean>을 정의할 수 있습니다.
<bean> 태그에 사용되는 속성들
속성 이름 | 설명 |
id | 빈 객체의 고유 이름으로, 빈 id를 이용해 빈에 접근합니다. |
name | 객체의 별칭입니다. |
class | 생성할 클래스입니다. 패키지 이름까지 입력해야 합니다. |
constructor-arg | 생성자를 이용해 값을 주입할 때 사용합니다. |
property | setter를 이용해 값을 주입할 때 사용합니다. |
setter를 이용한 DI 기능
PersonService
public interface PersonService {
public void sayHello();
}
PersonServiceImpl
public class PersonServiceImpl implements PersonService {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
@Override
public void sayHello() {
System.out.println("이름: " + name);
System.out.println("나이: " + age);
}
}
application.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="personService" class="com.example.demo.PersonServiceImpl">
<property name="name">
<value>홍길동</value>
</property>
</bean>
</beans>
resources 폴더에 application.xml 파일을 생성한 후 PersonService 빈에 접근할 수 있도록 빈 id를 personService로 지정하고 <property> 태그를 이용해 PersonServiceImpl 클래스 객체의 name 속성에 <value> 태그의 값으로 초기화 합니다.
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
PersonService person = (PersonService) context.getBean("personService");
person.sayHello();
}
}
위와 같이 application.xml 파일을 읽어와서 context 객체를 생성하고 getBean 메서드를 이용하여 id가 personService인 빈을 생성합니다. 그리고 나서 person 객체의 sayHello() 메서드를 실행하면 아래와 같이 출력되는 것을 확인할 수 있습니다.
생성자를 이용한 DI 기능
PersonServiceImpl
public class PersonServiceImpl implements PersonService {
private String name;
private int age;
public PersonServiceImpl(String name) {
this.name = name;
}
public PersonServiceImpl(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public void sayHello() {
System.out.println("이름: " + name);
System.out.println("나이: " + age);
}
}
application.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="personService1" class="com.example.demo.PersonServiceImpl">
<constructor-arg value="이순신"/>
</bean>
<bean id="personService2" class="com.example.demo.PersonServiceImpl">
<constructor-arg value="이순신"/>
<constructor-arg value="23"/>
</bean>
</beans>
인자가 한 개인 생성자로 id가 personService1인 빈을 생성하고 인자가 두 개인 생성자로 id가 personService2인 빈을 생성합니다.
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
PersonService person1 = (PersonService) context.getBean("personService1");
person1.sayHello();
System.out.println();
PersonService person2 = (PersonService) context.getBean("personService2");
person2.sayHello();
}
}
수정자 때와 마찬가지로 context 객체를 생성하고 id가 personService1인 person1 빈과 id가 personService2인 person2 빈을 생성하고 각각 sayHello() 메서드를 호출하면 아래와 같이 출력되는 것을 확인할 수 있습니다.
의존 관계에 있는 다른 빈을 주입하는 경우
PersonServiceImpl
public class PersonServiceImpl implements PersonService {
private PersonRepository personRepository;
public void setPersonDAO(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Override
public void listPersons() {
personRepository.listPersons();
}
}
PersonRepository
public class PersonRepository {
public void listPersons() {
System.out.println("listMembers 메서드 호출");
System.out.println("회원정보를 조회합니다.");
}
}
application.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="personService" class="com.example.demo.PersonServiceImpl">
<property name="personRepository" ref="personRepository"/>
</bean>
<bean id="personRepository" class="com.example.demo.PersonRepository"/>
</beans>
id가 personDAO인 빈을 personService 빈에 주입합니다. 주입되는 데이터가 기본형이 아닌 참조형인 경우 ref 속성으로 설정해야 합니다.
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
PersonService person = (PersonService) context.getBean("personService");
person.listPersons();
}
}
context 객체를 생성하고 id가 personService인 빈을 생성한 후 person 객체를 이용해 listPersons() 메서드를 호출하면 아래와 같이 출력되는 것을 확인할 수 있습니다.
하지만 위와 같은 방법은 xml 파일에 bean을 일일이 등록해줘야 해서 매우 번거롭습니다. 그래서 xml 파일에 아래와 같이 component-scan을 등록해주면 base-package에서 지정한 패키지의 하위 패키지를 scanning해서 @Component 어노테이션이 붙은 클래스들을 자동으로 빈으로 등록해줍니다.
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example.demo"/>
</beans>
PersonServiceImple와 PersonRepository를 아래와 같이 작성하고 name이 personServiceImpl인 빈을 조회한 후 똑같이 실행하면 같은 결과가 출력됩니다.
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonRepository personRepository;
public void setPersonRepository(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Override
public void listPersons() {
personRepository.listPersons();
}
}
@Repository
public class PersonRepository {
public void listPersons() {
System.out.println("listMembers 메서드 호출");
System.out.println("회원정보를 조회합니다.");
}
}
참고로 @Service와 @Repository 그리고 @Controller 어노테이션은 @Component 어노테이션을 확장시킨 어노테이션이므로 scanning시 스프링 빈으로 자동으로 등록됩니다.
2. JAVA 설정파일
xml 파일이 아닌 JAVA 클래스를 이용해서도 빈을 설정할 수 있습니다.
먼저 ApplicationConfig라는 클래스를 생성한 뒤 아래와 같이 작성해줍니다.
@Configuration
public class ApplicationConfig {
@Bean
public PersonRepository personRepository() {
return new PersonRepository();
}
@Bean
public PersonServiceImpl personServiceImpl() {
PersonServiceImpl personService = new PersonServiceImpl();
personService.setPersonRepository(personRepository());
return personService;
}
}
자바 설정 파일은 클래스위에 @Configuration 어노테이션을 작성하고 빈으로 등록할 객체를 리턴하는 메소드 위에 @Bean 어노테이션을 추가해줌으로써 빈으로 등록할 수 있습니다. 그리고 나서 PersonServiceImpl과 PersonRepository에 작성했던 @Component 확장 어노테이션을 지워주고 아래 코드를 실행해주면 xml파일로 테스트했을 때와 같은 결과가 출력됩니다.
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
PersonService person = (PersonService) context.getBean("personServiceImpl");
person.listPersons();
}
}
3. JAVA 설정 파일 + Component Scan
xml 파일은 사용하기 싫은데 Component Scan은 사용하고 싶다면 자바 설정 파일에 Component Scan을 설정해주면 됩니다.
자바 설정 파일을 아래와 같이 작성해주고 다시 PersonServiceImpl과 PersonRepository 클래스에 각각 @Service와 @Repository 어노테이션을 붙여주고 테스트해보면 같은 결과가 출력됩니다.
@Configuration
@ComponentScan(basePackageClasses = ApplicationConfig.class)
public class ApplicationConfig {
}
'Spring' 카테고리의 다른 글
동시성 이슈 해결방법 (Synchronized, DB Lock, Redis Lock) (0) | 2022.12.20 |
---|---|
리팩토링 (1) | 2022.12.02 |
[Spring] Spring Framework, Spring Web MVC (0) | 2022.11.08 |
[Spring] SecurityConfig, OAuth2UserDetailsService 순환 참조 오류 (0) | 2022.11.06 |
[Spring] AOP (0) | 2022.09.28 |