프레임워크 입니다.도구입니다.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());
}
}
언제 공통 관심 기능을 핵심 로직에 적용할 지를 정의적용하는 것공통으로 적용되는 기능