객체 의존성
public class PetOwner{
private AnimalType animal;
public PetOwner() {
this.animal = new Dog();
}
}
- PetOwner 객체는 AnimalType 객체 (이 경우 Dog)에 의존
- PetOwner 객체는 AnimalType 객체의 생성을 제어
- PetOwner와 AnimalType 객체 사이가 연결됨
- AnimalType 객체를 변경하면 PetOwner 객체가 변경
PetOwner와 Dog는 강하게 결합이 되어있다 = tight coupling
-> 다른 경우를 적용하려면 소스코드를 바꿔야 하는 상황
(만약 Cat을 animal에 넣으려고 하면 PetOwner 코드를 바꿔줘야 한다. -> 다른 상황마다 코드를 바꿔야되는 상황)
ㄴ 해결하기 위해 나온 것이 Dependency Injection
의존성 주입이란?
- Bean Container가 설정 파일을 보고 적절한 bean(객체) 생성
ㄴ Spring에서 제공
ex) Bean A ->(Bean Container) 의존성 주입, Bean 생성 -> Bean B 짜잔 - Container가 생성자에 무엇을 주입하냐에 따라서 값이 달라진다.
예시)
public class PetOwner{
private AnimalType animal;
public PetOwner(AnimalType animal) {
this.animal = animal;
}
}
public class Dog
implements AnimalType{
//…
}
public class Cat
implements AnimalType{
//…
}
- 객체가 아닌 framework가 객체의 종속성을 주입하는 디자인 패턴
- framework에 의해 동적으로 주입되므로 객체간 결합이 줄어든다.
Spring Container
- 스프링 프레임워크의 핵심요소
- 빈을 포함하고 관리하는 역할
- 빈 생성(Object)
- 빈들을 연결
- 연결 설정
- 빈들의 완전한 라이프사이클을 관리
- 설정 방법 3가지
- XML
- Java annotations
- Java-based Configuration
- Spring은 2가지 컨테이너를 제공
- BeanFactory
- DI(Dependency injection)를 주로 사용한 가장 간단한 factory
- 자원이 제한적일 때 사용( mobile, applets 등)
- XMLBeanFactory: 가장 보편적으로 사용되는 implementation - ApplicationContext
- 좀 더 복잡한 factory
- 요청으로 빈을 연결하고 끊는다.
- Publish application events to listeners
- Enterprise aware functions
- ClassPathXmlApplicationContext: 가장 보편적으로 사용되는 implementation
ex)
ApplicationContext context =
new ClassPathXmlApplicationContext("kr/ac/hansung/spring/beans/bean.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
- BeanFactory
DI 예시
//DI를 받을 인터페이스
public interface AnimalType{
public void sound();
}
// Bean으로 등록 될 클래스들
public class Cat implements AnimalType{
String myName;
public void setMyName(String name){
this.myName = name;
}
public void sound() {
sysout("Cat name =" + myName + ": "+ "Meow!");
}
}
public class Dog implements AnimalType{
String myName;
public void setMyName(String name){
this.myName = name;
}
public void sound() {
sysout("Dog name =" + myName + ": "+ "Bow wow!");
}
}
public class PetOwner{
public AnimalType animal;
public PetOwner(AnimalType animal){
this.animal = animal;
}
public void play() {
animal.sound();
}
}
//Configure beans and dependencies
// animal.xml
...
//빈 정의
<bean id="dog" class = "package 명.Dog">
<Property name = "myName" value = "poodle"></property>
</bean>
<bean id="cat" class = "package 명.Cat">
<Property name = "myName" value = "bella"></property>
</bean>
//DI 부분
<bean id="petOwner" class = "package 명.PetOwner">
<constructor-arg ref = "cat" </constructor -arg> // dog로 바꿔도 java 소스에 영향 없음
</bean>
//main
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xml 위치/animal.xml");
PetOwner person = (PetOwner) context.getBean("petOwner");
person.play();
context.close();
Spring Bean Scope
- singleton (Default): 모든 getBean() 호출을 단일 빈 객체가 담당
- prototype: 모든 getBean() 호출을 새로운 객체가 담당
- request: 한 HTTP request 당 단일 빈 객체가 담당
- session: 한 HTTP session 당 단일 빈 객체가 담당
- global-session: 한 global HTTP session 당 단일 빈 객체가 담당
예시)
public class PetOwner{
String userName;
public String getUserName(){
sysout("Person name is " + userName);
return userName;
}
public void setUserName(String userName){
this.userName = userName;
}
public AnumalType animal;
public PetOwner(AnimalType anumal){
this.animal = animal;
}
public void play() {
animal.sound();
}
}
PetWoner person1 = (PetOwner) context.getBean("PetOwner");
person1.setUserName("Alice");
person1.getUserName();
PetOwner person2 = (PetOwner) context.getBean("PetOwner");
person2.getUserName();
// 결과
Person name is Alice
Person name is Alice
만약 xml 설정에서 perOwner의 scope 값을 prototype으로 설정하면
두번 째 출력값에 Alice 대신 null이 들어온다.//userName 값이 초기화 되지 않았기 때문
Dependency Injection Methods
- Contructor-based Injection
- 생성자를 통해 종속성을 전달 - Setter-based Injection
- setters 속성을 통해 종속성을 전달
Contructor-based Injection (모호성 존재)
기본 예시)
<bean id="petOwner" class="kr.ac.hansung.spring.PetOwner" >
<constructor-arg ref ="dog" />
</bean>
public class PetOwner {
public AnimalType animal;
public PetOwner(AnimalType animal) {
this.animal = animal;
}
…
}
1. 생성자가 1개 이상의 변수를 받을 때 -> 타입을 보고 결정한다.
예시)
<bean id="myCollege" class="com.korea.College">
<constructor-arg value=“500” type=“int”/>
<constructor-arg value=“123Abc” type=“java.lang.String”/>
</bean>
public class College {
private String collegeId;
private int totalStudents;
private String collegeAdd;
public College (int totalStudents, String collegeId){
this.totalStudents = totalStudents;
this.collegeId = collegeId;
}
public College (String collegeAdd, String collegeId){
this.collegeAdd = collegeAdd;
this.collegeId = collegeId;
}
}
2. 타입이 전부 존재하는 경우 -> 뒤에 index를 명시해서 순서를 나타낸다.
예시)
<bean id="myCollege" class="com.korea.College">
<constructor-arg value=“500” type=“int” index=“0”/>
<constructor-arg value=“123Abc” type=“java.lang.String” index=“1”/>
</bean>
public class College {
private String collegeId;
private int totalStudents;
private String collegeAdd;
public College (int totalStudents, String collegeId){
this.totalStudents = totalStudents;
this.collegeId = collegeId;
}
public College (String collegeAdd, int totalStudents){
this.totalStudents = totalStudents;
this. collegeAdd = collegeAdd;
}
}
Setter-based Injection
- Setter 메서드를 호출하는 설정(constructor-arg 대신 property 사용)
예시)
<bean id="petOwner" class="kr.ac.hansung.spring.PetOwner">
<property name="animal" ref="dog" />
</bean>
public class PetOwner {
public AnimalType animal;
public void setAnimal(AnimalType animal) {
this.animal = animal;
}
…
}
Spring Annotation
- xml 설정 대신 annotation을 사용하여 간단하게 설정을 할 수도 있다.
- @Required
- 요구 사항 체크를 할 수 있다.
public class Boy {
private String name;
private int age;
@Required
public void setName(String name){
this.name = name;
}
@Required
public void setAge(int age){
this.age = age;
}
// getters ...
}
<bean id=“boy” class=“Boy”>
<property name=“name” value=“Rony”/>
<property name=“age” value=“10”/>
</bean>
//만약 밑에 코드처럼 age를 빼먹는 다면 age속성이 요구된다는 메세지가 뜬다.
<bean id=“boy” class=“Boy”>
<property name=“name” value=“Rony”/>
</bean>
- @Autowired
- 의존성 주입을 xml 설정 대신 annotation을 다는 것만으로 설정할 수 있다.
public class Boy {
private String name;
private int age;
// getters and setters ...
}
public class College {
/* Autowired를 사용하면 지워도 되는 부분
private Boy student;
public void setStudent(Boy aboy){
this.stuendt = aboy;
*/
@Autowired
private Boy student;
}
}
<bean id=“boy” class=“Boy”>
<property name=“name” value=“Rony”/>
<property name=“age” value=“10”/>
</bean>
<bean id=“college” class=“College”>
/* Autowired를 사용하면 지워도 되는 부분
<property name=“student” ref=“boy”/>
*/
</bean>
- @Qualifier
- @Autowired를 사용했을 때 타입 모호성을 해결할 수 있다.
public class Boy {
private String name;
private int age;
// getters and setters ...
}
public class College {
@Autowired
@Qualifier(value=“tony”)
private Boy student;
// getters ...
}
<bean id=“boy1” class=“Boy”>
<qualifier value=“rony”/>
<property name=“name” value=“Rony”/>
<property name=“age” value=“10”/>
</bean>
<bean id=“boy2” class=“Boy”>
<qualifier value=“tony”/>
<property name=“name” value=“Tony”/>
<property name=“age” value=“8”/>
</bean>
<bean id=“college” class=“College”>
</bean>
- @Resource
- @Autowired와 같은 역할을 하지만 Autowired는 타입을 체크하여 주입하고 Resource는 이름(bean id)을 체크하여 주입한다.
<bean id=“boy1” class=“Boy”>
<property name=“name” value=“Rony”/>
<property name=“age” value=“10”/>
</bean>
<bean id=“boy2” class=“Boy”>
<property name=“name” value=“Tony”/>
<property name=“age” value=“8”/>
</bean>
<bean id=“college” class=“College”>
</bean>
public class College {
@Resource(name=“boy1”)
private Boy student;
// getters and setters ...
}
'Spring > 이론' 카테고리의 다른 글
DB 연동(with Spring JDBC) (0) | 2020.03.09 |
---|---|
관점 지향 프로그래밍(AOP, Aspect Oriented Programming) (0) | 2020.03.07 |
JSP(Java Server Pages) (0) | 2020.03.05 |
Servlet (0) | 2020.03.04 |
Spring Framework 개요 (0) | 2020.03.04 |
댓글