스프링(Spring) 프레임워크

실습 보충

*. 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();
	}
}

Bean 생성과 의존 관계

  • 스프링 컨테이너는 기본적으로 XML 파일을 통해 Bean 객체와 연관 관계를 설정

  • 스프링 설정 파일은 DTD방식 설정과 스키마 방식 설정 모두 지원

  • 스프링은 관리할 Bean을 등록하기 위해서 <Bean> 태그를 사용

  • 스프링은 주어진 클래스의 생성자를 이용하여 Bean을 생성

  • <constructor-arg> 태그 정의가 없다면, 아규먼트(함수 변수에 넣는 값)가 없는 생성자를 이용

  • 스프링은 기본적으로 하나의 클래스 당 하나의 Bean을 생성하여 재사용

  • Bean 태그의 속성

  1. name : id와 용도는 동일하지만, '/' 같은 특수문자를 포함할 수 있음
  2. id : 생성된 Bean 객체를 위한 식별 값
  3. class : 생성할 Bean의 클래스로써 패키지를 포함한 완전한 클래스 명을 지정
  4. scope : Bean의 scope 속성 (singleton(디폴트), prototype, request, session, global-session)
  5. abstract : 이 값이 true 일 때, 해당 Bean 인스턴스를 생성하지 않음
  6. factory-method : 싱글톤 클래스의 경우 해당 객체를 얻기 위한 메소드를 지정
  7. init-method : Bean이 생성된 후, Bean 객체에 대한 초기화 작업을 처리할 메소드를 지정
  8. destory-method : Bean 소멸 직전에 자원 해체와 같은 소멸 작업을 처리할 메소드를 지정

DI(Dependency Injection)

  • 빈 객체들 간의 의존관계 설정에 대한 방식

  • 객체들 간의 상호 참조 형태를 객체 자신들이 아닌 외부 어셈블러에 의해 수행

  • 관련 참조 및 매핑 정보를 외부 파일로 제공

    	1. 객체들 간의 의존 관계를 약하게 하고 (loose coupling)
    	2. 코드들에 대한 단위 테스트가 쉬움

스프링 DI 컨테이너

  • 스프링 프레임워크는 스프링 컨테이너를 통해 DI를 제공

  • 스프링 컨테이너는 Bean 객체들의 생성, 저장, 소멸 등과 같은 라이프사이클 관리를 수행

  • Bean 설정 매핑 정보를 바탕으로 Bean들 간의 의존 관계를 설정

스프링 컨테이너 인터페이스

BeanFactory

  • Bean 객체를 관리하고 Bean들 간의 의존 관계를 설정해 주는 기능을 제공
  • 구현체로는 XmlBeanFactory 클래스 등이 있음

예시)

Resource resource = new ClasspathResource("com/varxyz/jvx330/di/example1/beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
Foo foo = (Foo)factory.getBean("foo");

ApplicationContext

  • BeanFactory 인터페이스의 자식 인터페이스, 일반적인 애플리케이션 개발 시 주로 사용
  • BeanFactory의 Bean 관리 기능과 더불어 자원처리 추상화, 메시지, 이벤트, 국제화 등을 지원

WebApplicationContext

  • 웹 애플리케이션 개발 시 사용되며, 웹 애플리케이션 당 하나씩 존재하는 컨테이너
  • ApplicationContext 인터페이스를 상속하며, Bean Scope에 대한 추가 기능 정의
  • 구현체로써 XmlWebApplicationContext 클래스 등이 있음

실습1

  • 상속받는 관계를 xml에서 정의해줌

*. 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();
	}
}

실습2

@Getter
@Setter
  • 기존의 생성자를 다음과 같이 쉽게 정의
@AllArgsConstructor

실습3

  • beans.xml와 AppConfig.java 는 같은 내용을 의미함

*. 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

  • XML 방식과 클래스 방식으로 할 때 사용하는 문법이 다름
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();
	}
}

실습4

  • 여러 메서드가 중복 실행될 때, 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

  • 1개만 만들어야 오류가 나지 않음
	<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();
	}
}

실습5

  • 실습4의 방법은 클래스에@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();
	}
}

실습6

  • bean.xml 의 내용을 @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();
	}
}

profile
안녕하세요. 맡은 업무를 확실하게 수행하는 웹 개발자가 되기 위하여 끊임없이 학습에 정진하겠습니다.

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN