프레임워크
입니다.도구
입니다.Spring의 핵심개념으로 IoC/DI
, AOP
, PSA
, POJO
가 있습니다. 지금부터 이들에 대해 살펴보겠습니다.
제어가 뭐지?
, 역전되기 전에는 어떤 상황이지?
, 왜 역전시켰지?
라는 의문이 들었었습니다.자바의 객체를 생성하고 의존관계를 부여하는 권한
을 말합니다.Obj obj = new Obj();
라는 코드를 입력해 객체를 생성했습니다. 개발자
에게 있었다는 말입니다.A.class
에서 B b = new B();
라는 코드를 실행하기 때문에 A.class
가 자신이 사용할 객체(B)를 직접 만들어서 사용하고 있다는 의미이기도 합니다. Container
입니다. 즉, 우리가 가지고 있던 제어권
이 컨테이너
에게 넘어간 상황을 제어의 역전
이라고 부릅니다.여기까지만 보면 뭔가 중요한 걸 빼았겼다는 느낌이 들어 부정적으로 느껴질 수 있지만 그렇지 않습니다.
제어권이 넘어갔다는 건귀찮은 작업을 누군가에게 떠넘길 수 있게 된
감사한 일입니다.
런타임 시점
에 결정하게 됩니다.BeanFactory 인터페이스
, ApplicationContext 인터페이스
가 존재하는데 Beanfactory를 상속받아 기능을 확장한 인터페이스가 ApplicationContext이기 때문에 주로 ApplicationContext를 사용합니다.Dependency Lookup
과 Dependency Injection
이 있습니다.일반적으로 다음과 같이 A객체에서 직접 B객체를 선언하여 사용합니다.(의존성 주입X)
class A{
private B b;
public A(){
b = new B();
}
}
외부에서 의존성을 주입하는 방법은 다음과 같습니다.
class A{
private B b;
// setter로 주입
public void setB(B b){
this.b = b;
}
// 생성자로 주입
public A(B b){
this.b = b;
}
}
xml과 annotation는 의존성을 어떻게 주입해 달라는
주문서
컨테이너는 주문서에 따라 의존성을 조립해주는주체
로 이해할 수 있습니다.
public static void main(String[] args){
Exam exam = new Exam();
ExamConsole console = new InlineExamConsole(exam); // 생성자를 통해 exam객체를 inlineExamConsole에다가 주입하고 있습니다.
// ExamConsole console = new GridExamConsole(exam);
console.print();
}
<beans>
<!-- Exam exam = new NewlecExam();과 동일한 역할을 합니다. -->
<bean id = "exam" class = "spring.di.entity.NewlecExam"/>
<!-- Examconsole console = new GridExamConsole();과 동일한 역할을 합니다. -->
<bean id = "console' class ="spring.di.ui.GridExamConsole" >
<!-- console.setExam();과 동일한 역할을 합니다. 주입하는 객체를 value또는 ref로 선언해주면 됩니다.
이때 ref의 값은 같은 beans의 있는 bean의 id를 값으로 받습니다. -->
<property name="exam" ref = "exam" />
</bean>
<beans>
만들어진 XML은 ApplicationContext에 의해 실행됩니다.
ClassPathXmlApplicationContext
: Application의 root로부터 xml을 찾습니다.FileSystemXmlApplicationContext
: 파일로 된 xml을 찾습니다.XmlWebApplicationContext
: 웹과 관련된 xml을 찾습니다.AnnotationConfigApplicationContext
: xml이 아닌 어노테이션을 지시서로 사용합니다. scan이 필요합니다.사용예시1) 기본선언
Public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("패키지 경로/파일이름.xml");
}
사용예시2) 이름으로 객체 꺼내기
Public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("spring/di/setting.xml");
// 이름으로 객체를 가져올 때에는 해당 객체가 어떤 타입인지를 모르기 때문에 형변환이 필요합니다.
ExamConsole console = (ExamConsole) Context.getBean(“console”);
}
사용예시3) 자료형으로 객체 꺼내기
Public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("spring/di/setting.xml");
ExamConsole console = context.getBean(ExamConsole.class);
}
<bean id = "exam" class ="spring.di.entity.NewlecExam">
<property name="kor" value = "20" />
<property name = "kor">
<value> "20" </value>
<property>
</bean>
<bean id = "exam" class ="spring.di.entity.NewlecExam">
<constructor-arg value="30" />
<constructor-arg index = "1" value="50" />
<constructor-arg name="kor" value="50" />
<constructor-arg name="kor" type = "float" value="50" />
</bean>
index,name을 부여하지 않으면 적은 순서대로 생성자 인자가 됩니다.
index를 사용하면 임의의 순서를 지정할 수 있습니다.
name을 사용하면 특정 인자라는걸 명시할 수 있습니다.
매개변수는 동일하고 매개변수의 타입만 다른 생성자가 오버로딩 되어 있다면 type을 명시해 어떤 생성자를 사용할지 지정할 수 있습니다.
p:를 통해 변수를 넘겨주는 방법도 있습니다.
<bean id = "exam" class ="spring.di.entity.NewlecExam" p:kor="10" p:eng="20">
</bean>
주입이 아닌 일반적인 방법
List<Exam> exams = new ArrayList<>();
exams.add(new NewlecExam(1,1,1,1));
for(Exam e : exams){
System.out.println(e);
}
Public static void main(String[] args){
List<Exam> exams = (List<Exam>)context.getBean("exams");
}
주입1. constructor-arg에 list안에 bean을 넣습니다.
<bean id = "exams" class "java.util.ArrayList"/>
<constructor-arg>
<list>
<bean id = "exam" class = "spring.di.entity.NewlecExam" p:kor="10" p:eng="20"> // 빈을 직접 생성
<ref bean="exam"/> // 같은 .xml에 있는 bean을 참조
</list>
<constructor-arg>
</bean>
주입2. <util:>태그 이용합니다.
<util:list id="exams" list-class="java.util.ArrayList">
<bean id = "exam" class ="spring.di.entity.NewlecExam" p:kor="10" p:eng="20"
<ref bean="exam"/>
</util:list>
빈(Bean)
이라고 부릅니다.<?xml>
<beans>
<bean id="" class="">
<property>
</bean>
<beans>
타입
을 이용해 의존성을 주입합니다. 만약 동일한 Bean타입 객체가 여러개 있다면 원하는 Bean을 찾기 위해 @Qualifier를 같이 사용해야 합니다.이름
을 이용해 의존성을 주입합니다.<xml>
<beans>
<context:component-scan base-package=""/>
</beans>
@Component
public class Service{
@Autowired
private DAO dao;
}
핵심 관심 사항
과 공통 관심 사항
으로 분리(관심사의 분리)하겠다는 의미입니다.MainProcess proxy = (MainProcess) Proxy.newProxyInstance(loader, interfaces, h);
(MainProcess): 형변환
loader: 실제 객체의 정보
interfaces: 배열형태의 인터페이스 정보
h: 보조업무(InvokationHandler())
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Sub {
public static void main(String[] args) {
MainProcess realObj = new MainProcessImpl(1,2,3); // 실제객체
MainProcess Proxy_Obj = (MainProcess)Proxy.newProxyInstance(MainProcessImpl.class.getClassLoader(),
new Class[] {MainProcess.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 보조업무
long start = System.currentTimeMillis();
Thread.sleep(1000);
// 핵심 업무 호출
Object result = method.invoke(realObj, args);
// 보조업무
long end = System.currentTimeMillis();
long time = (end-start);
System.out.println(time);
return result;
}
}
); // 프록시 객체
System.out.println(Proxy_Obj.sum()); // 실제객체가 아니라 프록시에서 메서드를 호출
// System.out.println(realObj.sum()); // 물론 실제객체에서 호출하는 것도 문제없음
}
}
Before
, After Running
, After Throwing
, Around
의 proxy를 제공하고 있습니다.<beans>
<bean id="MainProcess" class="MainProcess"></bean>
<bean id="SubProcess" class="AroundAdvice"></bean>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"> // proxy빈을 생성합니다.
<property name="target" ref="MainProcess"/> // 핵심업무를 정의합니다.
<property name="SubProcess"> // 보조업무를 정의합니다.
<list>
<value>SubProcess</value>
</list>
</property>
</bean>
<beans>
public class AroundAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable{
// 보조 업무
long start = System.currentTimeMillis();
// 핵심 업무
Object result = invocation.proceed();
// 보조 업무
long end = System.currentTimeMillis();
int time = end-start;
System.out.println(time);
return result;
}
}
public class test{
public static void main(String[] args){
ApplicationContext context = new CalssPAthXmlApplicationContext("setting.xml");
MainProcess proxy = (MainProcess)context.getBean("proxy");
System.out.println(proxy.sum());
}
}
언제
공통 관심 기능을 핵심 로직에 적용할 지를 정의적용
하는 것공통으로 적용되는 기능