*. beans.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 name="foo" class="com.varxyz.jvx330.di.example1.Foo">
<constructor-arg ref="bar" />
</bean>
<bean name="foo2" class="com.varxyz.jvx330.di.example1.Foo">
<property name="bar" ref="bar"/>
</bean>
<bean name="bar" class="com.varxyz.jvx330.di.example1.Bar" />
</beans>
*. AppMain.java
public class AppMain {
public static void main(String[] args) {
String config = "com/varxyz/jvx330/di/example1/beans.xml";
GenericApplicationContext context = new GenericXmlApplicationContext(config);
Foo foo = context.getBean("foo", Foo.class);
System.out.println(foo);
Foo foo1 = context.getBean("foo", Foo.class);
System.out.println(foo1); // hash 값이 같음, 같은 객체를 재활용하고 있음
Foo foo2 = context.getBean("foo2", Foo.class);
System.out.println(foo2);
context.close();
}
}
스프링 컨테이너는 기본적으로 XML 파일을 통해 Bean 객체와 연관 관계를 설정
스프링 설정 파일은 DTD방식 설정과 스키마 방식 설정 모두 지원
스프링은 관리할 Bean을 등록하기 위해서 <Bean>
태그를 사용
스프링은 주어진 클래스의 생성자를 이용하여 Bean을 생성
<constructor-arg>
태그 정의가 없다면, 아규먼트(함수 변수에 넣는 값)가 없는 생성자를 이용
스프링은 기본적으로 하나의 클래스 당 하나의 Bean을 생성하여 재사용
Bean 태그의 속성
name
: id와 용도는 동일하지만, '/' 같은 특수문자를 포함할 수 있음id
: 생성된 Bean 객체를 위한 식별 값class
: 생성할 Bean의 클래스로써 패키지를 포함한 완전한 클래스 명을 지정scope
: Bean의 scope 속성 (singleton(디폴트), prototype, request, session, global-session)abstract
: 이 값이 true 일 때, 해당 Bean 인스턴스를 생성하지 않음factory-method
: 싱글톤 클래스의 경우 해당 객체를 얻기 위한 메소드를 지정init-method
: Bean이 생성된 후, Bean 객체에 대한 초기화 작업을 처리할 메소드를 지정destory-method
: Bean 소멸 직전에 자원 해체와 같은 소멸 작업을 처리할 메소드를 지정빈 객체들 간의 의존관계 설정에 대한 방식
객체들 간의 상호 참조 형태를 객체 자신들이 아닌 외부 어셈블러에 의해 수행
관련 참조 및 매핑 정보를 외부 파일로 제공
1. 객체들 간의 의존 관계를 약하게 하고 (loose coupling)
2. 코드들에 대한 단위 테스트가 쉬움
스프링 프레임워크는 스프링 컨테이너를 통해 DI를 제공
스프링 컨테이너는 Bean 객체들의 생성, 저장, 소멸 등과 같은 라이프사이클 관리를 수행
Bean 설정 매핑 정보를 바탕으로 Bean들 간의 의존 관계를 설정
예시)
Resource resource = new ClasspathResource("com/varxyz/jvx330/di/example1/beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
Foo foo = (Foo)factory.getBean("foo");
*. beans.xml
<bean name="foo" class="com.varxyz.jvx330.di.example1.Foo">
<constructor-arg ref="bar" />
</bean>
<bean name="foo2" class="com.varxyz.jvx330.di.example1.Foo">
<property name="bar" ref="bar"/> // 상속받는 관계 정의
</bean>
<bean name="bar" class="com.varxyz.jvx330.di.example1.Bar" />
*. AppMain.java
public class AppMain {
public static void main(String[] args) {
String config = "com/varxyz/jvx330/di/example1/beans.xml"; // beans 경로
GenericApplicationContext context = new GenericXmlApplicationContext(config); // beans.xml를 불러오는 컨테이너 생성
Foo foo = context.getBean("foo", Foo.class);
System.out.println(foo);
Foo foo1 = context.getBean("foo", Foo.class);
System.out.println(foo1); // hash 값이 같음, 같은 객체를 재활용하고 있음
Foo foo2 = context.getBean("foo2", Foo.class);
System.out.println(foo2);
context.close();
}
}
pom.xml에 lombok 넣기 / (https://mvnrepository.com/artifact/org.projectlombok/lombok/1.18.24)
기존의 get, set 속성을 다음과 같이 쉽게 정의
@Getter
@Setter
@AllArgsConstructor
*. beans.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 name="memberService" class="com.varxyz.jvx330.di.example3.MemberService">
<constructor-arg ref="memberDao" />
</bean>
<bean name="memberDao" class="com.varxyz.jvx330.di.example3.MemberDao" />
</beans>
*. AppConfig.java
@Configuration // 설정 관련된 클래스 임을 설정
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberDao());
}
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
}
*. AppMain.java
public class AppMain {
public static void main(String[] args) {
// String config = "com/varxyz/jvx330/di/example3/beans.xml"; // XML 방식
// GenericApplicationContext context = new GenericXmlApplicationContext(config); // XML 방식
GenericApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 클래스Configuration방식
MemberService memberService = context.getBean("memberService", MemberService.class);
memberService.getAllMembers().forEach(member -> System.out.println(member));
// 아래와 같은 문법, 일정 자바 버전 부터 사용 가능
// List<Member> list = memberService.getAllMembers();
// for (Member member : list) {
// System.out.println(member);
// }
context.close();
}
}
autowire="byName"
을 사용하여, Bean 객체의 id 혹은 name과 BeanClass 의 필드명와 일치하는 것을 찾아 자동으로 연결*. bean.xml
<bean name="byNameClient" class="com.varxyz.jvx330.di.example4.ex1.ByNameClient" autowire="byName" />
<bean name="jmsNamingService" class="com.varxyz.jvx330.di.example4.ex1.DnsNamingServiceImpl" />
*. ByNameClient.java
public class ByNameClient {
private NamingService namingService;
// JmsNamingService
public NamingService getJmsNamingService() {
return namingService;
}
public void setJmsNamingService(NamingService namingService) {
this.namingService = namingService;
}
public void service(String name) {
Object o = namingService.lookup(name);
System.out.println(o);
}
public static void main(String[] args) {
String config = "com/varxyz/jvx330/di/example4/ex1/beans.xml";
GenericApplicationContext context = new GenericXmlApplicationContext(config);
ByNameClient client = context.getBean("byNameClient", ByNameClient.class);
client.service("myQueue");
context.close();
}
autowire="byType"
을 사용하여, Bean 객체의 class(type) 와 BeanClass의 class(type)가 일치하는 것을 찾아 자동으로 연결*. bean.xml
<bean name="byTypeClient" class="com.varxyz.jvx330.di.example4.ex2.ByTypeClient"
autowire="byType" />
<bean name="jmsNamingService" class="com.varxyz.jvx330.di.example4.ex2.JmsNamingServiceImpl" />
<!-- <bean name="dnsNamingService" class="com.varxyz.jvx330.di.example4.ex2.DnsNamingServiceImpl" /> -->
*. ByNameClient.java
public class ByTypeClient {
private NamingService service;
public NamingService getNamingService() {
return service;
}
public void setNamingService(NamingService service) {
this.service = service;
}
public void service(String name) {
Object o = service.lookup(name);
System.out.println(o);
}
public static void main(String[] args) {
String config = "com/varxyz/jvx330/di/example4/ex2/beans.xml";
GenericApplicationContext context = new GenericXmlApplicationContext(config);
ByTypeClient client = context.getBean("byTypeClient", ByTypeClient.class);
client.service("myQueue");
context.close();
}
}
@Autowired
을 사용해서 설정해줄 수 있음*. CartController.java
public class CartController {
@Autowired
@Qualifier("sessionCartService") // 두 개의 중복된 서비스 중에 하나를 선택
private CartService service;
@Autowired
@Qualifier("cookieCartService") // 두 개의 중복된 서비스 중에 하나를 선택
private CartService service2;
public CartController() {
System.out.println("CartController 생성");
}
public void processRequest() {
service.addItem();
service2.addItem();
}
}
*. QualifierAutowireTest.java
public class QualifierAutowireTest {
public static void main(String[] args) {
String config = "com/varxyz/jvx330/di/example5/ex2/beans.xml";
GenericApplicationContext context = new GenericXmlApplicationContext(config);
CartController controller = context.getBean("cartController", CartController.class);
controller.processRequest();
context.close();
}
}
@Component
을 입력한 클래스로 대체 가능*. bean.xml
<bean name="menuItemService" class="com.varxyz.jvx330.di.example6.MenuItemService" />
<bean name="menuItemDao" class="com.varxyz.jvx330.di.example6.MenuItemDao" />
*. MenuTest.java
public class MenuTest {
public static void main(String[] args) {
String config = "com/varxyz/jvx330/di/example6/beans.xml";
GenericApplicationContext context = new GenericXmlApplicationContext(config);
MenuItemService controller = context.getBean("menuItemService", MenuItemService.class);
controller.addMenuItem(new MenuItem("아아", 1500));
controller.addMenuItem(new MenuItem("아바라", 2500));
controller.addMenuItem(new MenuItem("민초라", 3000));
for (MenuItem findAll : controller.getAllMenuItems()) {
System.out.println(findAll);
}
System.out.println("-------------------------------------");
System.out.println(controller.getNameMenuItems("아아"));
context.close();
}
}
@Component
방법*. MenuItemService.java
public interface MenuItemService {
public void addMenuItem(MenuItem Item);
public List<MenuItem> findAllMenuItem();
public MenuItem findNameMenuItem(String name);
}
*. MenuItemDao.java
@Component("menuItemDao")
public class MenuItemDao {
private static final List<MenuItem> menuItems = new ArrayList<MenuItem>();
public void addMenuItem(MenuItem menuItem) {
if (!menuItems.contains(menuItem)) { // 중복되지 않으면 넣는다
menuItems.add(menuItem);
}
}
public List<MenuItem> findAllMenuItems() {
return menuItems;
}
public MenuItem findNameMenuItems(String name) {
for (MenuItem menuItem : menuItems) {
if (menuItem.getName().equals(name)) {
return menuItem;
}
}
throw new RuntimeException(name + " menu does not exist");
}
}
*. MenuItemServiceImpl.java
@Component("menuItemService")
public class MenuItemServiceImpl implements MenuItemService {
@Autowired
private MenuItemDao menuItemDao;
// 신규 메뉴 아이템 등록
@Override
public void addMenuItem(MenuItem menuitem) {
menuItemDao.addMenuItem(menuitem);
}
// 모든 메뉴 조회
@Override
public List<MenuItem> findAllMenuItem() {
return menuItemDao.findAllMenuItems();
}
// 이름으로 메뉴 조회
@Override
public MenuItem findNameMenuItem(String name) {
return menuItemDao.findNameMenuItems(name);
}
}
*. MenuTest.java
public class MenuTest {
public static void main(String[] args) {
GenericApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MenuItemService controller = context.getBean("menuItemService", MenuItemService.class);
// 1.등록
controller.addMenuItem(new MenuItem("아아", 1500));
controller.addMenuItem(new MenuItem("아바라", 2500));
controller.addMenuItem(new MenuItem("민초라", 3000));
// 2.조회
List<MenuItem> list = controller.findAllMenuItem();
for (MenuItem item : list) {
System.out.println(item);
}
System.out.println("------------------------------------");
// 3.검색
MenuItem item = controller.findNameMenuItem("아아");
System.out.println(item);
context.close();
}
}