앞선 포스팅의 경우 개인적으로 개념적인 부분을 따로 쪼개서 추가한 자료들이다. 이번 포스팅 부터는 토비의 스프링
책을 읽고 정리해서 TIL을 남기고자 한다.
혹시 문제가 된다면 lshn1007@hanyang.ac.kr 로 메일 주면 삭제하겠습니다.
개발자가 작성한 코드를 통해 객체를 생성하고, 메소드를 호출하는 등 코드를 사용하는 쪽에서 프로그램의 실행 흐름을 제어하는 것이 아니라, 역으로 프레임워크나 컨테이너 등이 제어권을 가지고 프로그램의 실행 흐름을 제어하는 것을 제어의 역전이라 한다.
// A 클래스의 생성자에서 B 클래스의 객체를 생성한다. (사용하는 쪽에서 실행 흐름을 제어)
public class A {
private B b;
public A() {
b = new B();
}
}
// 스프링 프레임워크가 미리 생성해둔 B 객체를 A 클래스에 주입하여 사용할 수 있게 한다. (프레임워크에서 실행 흐름을 제어)
public class A {
@Autowired
private B b;
}
@Configuration
: 애플리케이션 컨텍스트 또는 빈 팩토리가 사용할 설정정보라는 표시@Bean
: 메서드에서 반환하는 객체를 애플리케이션 컨텍스트 또는 빈 팩토리의 빈으로 등록하고자 할 때 사용하는 표시(@Configuration 어노테이션을 사용한 클래스 내에서만 사용 가능하다.)/**
* userDao, connectionMaker Bean 등록
*/
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao() {
return new UserDao(connectionMaker());
}
@Bean
public ConnectionMaker connectionMaker() {
return new DConnectionMaker();
}
}
위에서 생성한 Application Context(빈 팩토리) 는 아래와 같이 테스트해볼 수 있다.
/**
* 애플리케이션 컨텍스트에 등록된 빈 목록에서 userDao 빈 조회
*/
public class TestApplication {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao userDao = context.getBean("userDao", UserDao.class);
}
}
@Configuration
이 붙은 클래스를 설정 정보로 등록한다.@Configuration
클래스 내의 @Bean이 붙은 메소드의 이름을 가져와 빈 목록을 만든다.getBean()
메소드를 호출한다.애플리케이션 컨텍스트의 장점
애플리케이션 컨텍스트, 빈 팩토리와 동일하나, IoC 방식으로 빈을 관리한다는 의미에서 다르게 말할 때 사용
애플리케이션 컨텍스트는 ApplicationContext 인터페이스를 구현한 오브젝트를 가리키기도 하는데, 하나의 애플리케이션에서 보통 여러 개가 만들어져 사용된다. 이를 통틀어서 스프링 컨테이너라고 부를 수 있다.
스프링 프레임워크
IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용하는 용어
따라서 팩토리 패턴에서 유례된 IoC (스프링 컨텍스트) 를 싱글톤으로 관리하여 활용한다.
이와 관련해서는 앞선 포스팅에서 메인 주제로 다룬 적이 있다.
IoC 라는 용어는 매우 느슨하게 정의되어 폭넓게 사용되므로 스프링에서는 이를 좀 더 의도가 명확하게 드러나는 용어로 사용하기 위해 의존관계 주입이라는 용어를 사용하기 시작했다.
두 개의 서로 다른 클래스 또는 모듈이 있을 때 하나의 모듈이 다른 모듈을 사용할 때 가지게 되는 관계를 말한다
특정 모듈의 변화가 다른 모듈에 영향(ex. B를 수정하면, A도 수정되어야 함) 을 미칠 수 있기 때문에 중간에 인터페이스를 두는 등의 방식으로 의존관계를 제한해주는 것이 좋다. (결합도를 낮추어야 한다.)
/**
* 의존관계 검색을 이용하는 UserDao 생성자
*/
public UserDao() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
this.connectionMaker = context.getBean("connectionMaker", ConnectionMaker.class);
}
의존관계 검색은 코드에 오브젝트 팩토리 클래스나 스프링 API를 사용해야 되는데, 애플리케이션 컴포넌트가 성격이 다른 오브젝트에 의존하게 되는 것이므로 바람직하지 않다. 반면에 의존관계 주입은 개발자가 비즈니스 로직에 집중할 수 있도록 이러한 코드 없이 훨씬 단순하고 깔끔하게 처리가 가능하므로 특별한 경우를 제외하고는 의존관계 주입을 사용하는 것이 좋다.
public class UserDao {
private ConnectionMaker connectionMaker;
public void setConnectionMaker(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
}
@Configuration
public class DaoFactory {
@Bean
public UserDao userDao() {
UserDao userDao = new UserDao();
userDao.setConnectionMaker(connectionMaker());
return userDao;
}
@Bean
public ConnectionMaker connectionMaker() {
return new LocalDBConnectionMaker();
}
}
@Configuration
, @Bean
어노테이션을 활용한다굳이 xml을 사용할 필요는 없으나 필요하다면 구글링을 추천한다..
/**
* 클래스 설정 방식
*/
@Configuration
public class DataSourceConfiguration {
@Bean
public UserDao userDao() {
UserDao userDao = new UserDao();
userDao.setDataSource(dataSource());
return userDao;A
}
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.type(BasicDataSource.class)
.driverClassName("com.mysql.cj.jdcb.Driver")
.url("jdbc:mysql://localhost:3306/test")
.username("root")
.password("root")
.build();
}
}
/**
* XML 설정 방식
*/
<beans xmlns=...>
<bean id="userDao" class="com.corgi.dao.UserDao">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
</beans>
애플리케이션 컨텍스트가 XML 설정정보를 활용하기 위해서는 GenericXmlApplicationContext 를 사용하면 된다. GenericXmlApplicationContext 의 생성자 파라미터로 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
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="connectionMaker" class="springbook.user.dao.DConnectionMaker" />
<bean id="userDao" class="springbook.user.dao.UserDao">
<property name="connectionMaker" ref="connectionMaker" />
</bean>
</beans>
public class Main {
public static void main(String[] args) {
// 혹은 ClassPathXmlApplicationContext를 사용해 XML 설정정보를 사용할 수 있다.
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
}
}
jdbc 를 이용한 드라이버 설정이라던지 세부내용은 configure 파일을 따로 추가하거나 빈 팩토리 추가 과정에 세팅을 하면 된다.
@Configuration
public class DataSourceConfiguration {
@Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(com.mysql.jdbc.Driver.class);
dataSource.setUrl("jdbc:mysql://localhost/springbook");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}