스프링 들어가기 전..
스프링은 강의 교재가 잘되어 있습니다. 신입사원이 알아야 할 내용이 전부 들어가 있다.
실무에서는 3버전 쓴다.
<! 이번에 사용하는 방식은 오래된 버전인데, SI에서는 이 버전을 사용합니다. >
스프링이 나온 이유
EJB 방식이 비효율적이고 무겁다..
개발하기가 어렵고, 호환성이 없다.
*스프링은 스트럭처럼 단지 MVC를 하기위한 프레임워크가 아니라
*EJB에서 기존에 해왔던 작업을 할 수 있게 하는것이 주 목적이다.
Spring 장점
*경량 컨테이너: 객체의 라이프 사이클 관리
*DI(Dependency Injection 의존성 주입: 객체간의 Relation, 의존관계) 지원
->개발자가 new로 객체를 생성하지 않는다. 관리하지 않아도 된다. Spring이 생성한다.
AOP(Aspect Oriented Programming)지원
=핵심 관심사항에 공통 관심사항을 어떻게 적용시킬 것인가… => 중앙에서 관리 가능! 공통된 부분에 대해 중앙에서 관리. 유지보수/수정이 편리하다.
핵심 관심사항 : 비즈니스 서비스…
공통 관심사항 : 시큐리티, 트랜잭션…
POJO(Plain Old Java Object): 기존에 만들어진 자바 객체 Spring안에서 호환 가능
JDBC를 위한 다양한 API 와의 연동이 된다.
***다양한 API와의 연동 지원
= 모든 기술을 Spring에서 가져와서 연동 할 수 있다. (가장 큰 장점!)
- Application에서 사용할 Spring 자원들을 설정하는 파일
- Spring Container는 설정파일에 설정된 내용을 읽어 Appication에서 필요한 기능들을 제공한다.
- XML기반으로 작성한다. (4점대 이후에서는 JAVA파일도 가능하다.)
- Root Tag는 <beans>다.
- 파일명은 상관없다.
*Bean객체 주입 받기 - 설정파일 설정
- 주입할 객체를 설정파일에 설정한다.
id: 주입받을 곳에서 호출할 이름 설정
class: 주입할 객체의 클래스
<?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-2.5.xsd">
<bean id=“dao” class=“spring.di.model.MemberDAO”/>
</beans>
*Bean객체 실제로 주입 받기
public static void main(String [] args){
//설정파일이 어디 있는지를 저장하는 객체
Resource resource = new ClassPathResource("applicationContext.xml");
//객체를 생성해주는 factory 객체
BeanFactory factory = new XmlBeanFactory(resource);
//설정파일에 설정한 <bean> 태그의 id/name을 통해 객체를 받아온다.
MemberDAO dao = (MemberDAO)factory.getBean("dao");
}
*DI관련 주요 클래스
*명시적 객체선언
//스프링컨테이너에 객체를 등록하기 위해 xml파일에 작성하는 방법을 이용할것이다.
//bean태그로 객체를 등록해준다. class는 객체를 생성할 실제JAVA클래스의 경로를 지정해준다.
1)설정을 통한 객체 주입 예제 - constructor를 이용
package vo;
public class Person{
private String id,
private String name,
private int age;
public Person(String id){...} //1번 생성자
public Person(String id, String name){…} //2번 생성자
public Person(int age){…} //3번 생성자
}
//생성자에 주입
<bean id=“person” class=“vo.Person”>
<constructor-arg>
<value>abcde</value>
</constructor-arg>
</bean>
또는
<bean id=“person” class=“vo.Person”>
<constructor-arg value=“abc”/>
</bean>
public class BusinessService{
private Dao dao = null;
public BusinessService(Dao dao){
this.dao = dao;
}
}
<bean id=“dao” class=“spring.di.model.OracleDAO”/>
<bean id=“service” class=“spring.di.model.service.BusinessService”>
<constructor-arg>
<ref bean = “dao”/>
</constructor-arg>
</bean>
또는
<bean id=“service” class=“spring.di.model.service.BusinessService”>
<constructor-arg ref=“dao”>
</bean>
2) Property를 이용하는 예제
값을 주입 받을 객체 - Primitive Data Type 주입
package spring.vo;
public class Person{
private String id,
private String name,
private int age;
public void setId(String id) {…}
public void setName(String name) {…}
public void setAge(int age) {…}
<bean id=“person” class=“vo.Person”>
<property name="name">
<value>hong</value>
</property>
<property name="id" value="abcde"/>
<property name="age" value="20"/>
</bean>
값을 주입 받을 객체 - Bean 객체 주입
public class BusinessService{
private Dao dao = null;
public setDao(Dao dao){…}
}
<bean id=“dao” class=“spring.di.model.OracleDAO”/>
<bean id=“service” class=“spring.di.model.service.BusinessService”>
<property name=“dao”>
<ref bean =“dao”/>
</property >
</bean>
또는
<bean id=“service” class=“spring.di.model.service.BusinessService”>
< property name=“dao” ref=“dao”>
</bean>
*Bean 객체의 생성 단위
<bean>의 scope 속성을 이용해 설정
//명시적으로 의존성을 주입한다.
//이때 service객체는 생성자를 이용해서 oracleDao객체를 생성한 후, 이것을 생성시 파라미터로 주입받게 된다.
//이게 무슨 의미냐면,
<?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">
<!-- oracleDao 객체 생성 -->
<bean id="oracleDao" class="kosta.OracleDao"/>
<!-- dao 객체를 넘기는 서비스 객체 생성자를 이용해서 arg로 넘긴다.-->
<bean id="service" class="kosta.WriteService">
<constructor-arg ref="oracleDao"/>
</bean>
</beans>
//constructor-arg방법은 생성자 안에 파라미터를 받는방법.
//property 방법은 setter, getter방식을 사용하게 된다. default생성자 실행 이후 setter로 insect하는 방법.
package kosta;
public class WriteService implements Service{
private Dao dao;
//생성자방식으로 사용
public WriteService() {}
public WriteService(Dao dao) {
this.dao = dao;
}
public Dao getDao() {
return dao;
}
public void setDao(Dao dao) {
this.dao = dao;
}
@Override
public void insert() {
System.out.println("WriteService insert()호출");
dao.insertBoard();
}
}
객체를 생성하면서 파라미터가 있을때도 있음. 그때는 bean하위 태그로 constructor-arg나 property태그를 사용한다.
*명시적 의존성주입
1) constructor-arg 방식
2) property 방식
<?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">
<!-- oracleDao 객체 생성 -->
<bean id="oracleDao" class="kosta.OracleDao"/>
<bean id="mysqlDao" class="kosta.MysqlDao"/>
<!-- 1) dao 객체를 넘기는 서비스 객체 생성자를 이용해서 arg로 넘긴다.-->
<bean id="service" class="kosta.WriteService">
<constructor-arg ref="mysqlDao"/>
</bean>
<!-- 2) WriteService에 변수에 setter를 이용해서 값 넣기. WriteServicedao에 setter가 있어야 한다. -->
<bean id="service" class="kosta.WriteService">
<property name="dao" ref="mysqlDao"></property>
</bean>
</beans>
//실제로 Main에서 사용해보자.
//Resource를 생성한다.(applicationContext.xml 파일은 위에 XML)
//그리고 BeanFactory를 생성 후...
//BeanFactory의 getBean(id명)메서드를 사용해서 객체를 생성한다.
package kosta;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class Main {
public static void main(String[] args) {
Resource resource =
new ClassPathResource("applicationContext.xml");
BeanFactory factory =
new GenericXmlApplicationContext(resource); //스프링 컨테이너 생성
//writeService안의 insert메서드를 호출하고 싶어..!
//스프링컨테이너에 의해서 의존성주입이 실제로 되는지 확인해보자.
Service service = (Service) factory.getBean("service");
service.insert();
}
}
package kosta;
public class OracleDao implements Dao {
@Override
public void insertBoard() {
System.out.println("Oracle Dao insertBoard() 호출!");
}
}
package kosta;
public class MysqlDao implements Dao {
@Override
public void insertBoard() {
// TODO Auto-generated method stub
System.out.println("MySqlDao insertBoard()!");
}
}
*묵시적 방법
자동으로 패키지 단위로 객체를 가져오는방식.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- oracleDao 객체 생성 -->
<!-- 패키지 단위로 객체 가져오기. 가져올 클래스 위에 @Repository처럼 annotation해야합니다.-->
<!-- context:component-scan 태그로 객체를 가져옵니다 -->
<context:annotation-config/>
<context:component-scan base-package="kosta"/>
<bean id="service" class="kosta.WriteService">
</bean>
</beans>
//context:를 사용하기 전에 Namespace탭에서 context NameSpace를 사용하도록 설정을 해줘야 한다.
// bean태그를 사용할땐 하나하나 생성했지만...
<context:component-scan/> 태그를 사용하면 패키지단위로 불러 올 수 있다.
하지만, 클래스를 불러오는데에는 한가지 조건이 있는데,
바로 자동으로 불러올 클래스 위에 @annotaion으로 표시해줘야 한다.
예 = @Controller, @service, @Repository(DAO), @Component
자동으로 @annotaion되어있는 클래스를 가져온다☆
package kosta;
import org.springframework.stereotype.Repository;
@Repository
public class MysqlDao implements Dao {
@Override
public void insertBoard() {
// TODO Auto-generated method stub
System.out.println("MySqlDao insertBoard()!");
}
public MysqlDao(){};
}
*묵시적 의존성주입
//하지만 여기까지는 단순히 객체를 생성한거고, 아직 의존성 주입이 안되어있다.
의존성 주입을 위해서, Autowired를 사용한다 (명시적 방식 못씀!)
1) 3점대에서는 @Autowired를 사용한다. - *setter위에 @Autowired표기!
2) 4점대에서는 @Injection을 사용한다. - *id로 알아서 Mapping해주기 때문에 간편! 하지만 이름이 겹치면 큰일남!
아래엔 @Autowired 예이다.
//자동으로 의존성 주입하기
//@Autowired 이 의미는 Dao객체를 자동으로 얻어오기를 원한다는것.!
//스프링 컨테이너야, Dao 객체 있니?:/
//넹! 자동으로 가져왔어요 :D MysqlDao요!
//<!주의. 만약 스프링 컨테이너가 Dao객체를 2개 가져오면 에러가 납니다 ㅠㅠ expected single matcing..에러..>
//스프링 4점대에는 Autowired가 아니라 Inject을 사용합니다
@Autowired
public void setDao(Dao dao) {
this.dao = dao;
}
//패키지 단위로 객체를 가져올때,
Main에서는 resource를 명시적 방식과 가져오는것은 동일하지만,
factory는 ApplicationContext객체를 사용한다.
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
//패키지 단위로 가져올때 사용
ApplicationContext factory = new GenericXmlApplicationContext(resource);
정리하자면!
//자동으로 의존관계 설정하기
1.자동으로 생성할 객체를 class 위에 @controller, @service, @repository을 해야한다.
2. componentScan으로 패키지 내의 객체를 자동으로 가져온다.
3. @autowire나 @inject(4점대, 라이브러리 필요)를 사용해서 의존성을 주입해준다.
<! 이때, 자동으로 넣어야 할 객체를 어떻게 알까? => 데이터 타입을 기준으로 판단한다. 그래서 데이터타입이 겹치면 오류난다.!>
*XML방식이 아니라 JAVA에서 스프링컨테이너 사용
스프링컨테이너에서 객체를 관리하는 방법을, 위에서는 XML방식을 사용했지만. 이번에는 JAVA클래스로 사용해봅시다!
Configration역할을 하는 JAVA클래스 위에 @configration이라고 표시를 합니다!
그리고, 관리할 객체를 메서드로 등록하는데, 이때 메서드 이름은 XML방식에서 사용했었던 id명역할을 합니다.
의존성 주입은 마찬가지로 @Autowired나 @Inject로 사용합니다.
package kosta;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//configration역할을 하는 JAVA파일입니다. @configuration으로 표시하죠!
@Configuration
public class Factory {
@Bean
public Dao OracleDao() {//메서드 이름이 xml의 id명 역할을 합니다!
return new OracleDao();
}
//WriteService클래스 내에 Autowired가 선언되어 있다면,자동으로 의존성주입이 됩니다.
@Bean
public Service service() {
return new WriteService();
}
}
//Java Config 방식은 AnnotationConfigApplicationContext 메서드를 호출하고 전달인자는 JAVA파일이름.class이다.
실제로 잘되나 확인해보자.
package kosta;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class Main {
public static void main(String[] args) {
//JAVA Config방식을 사용할때
ApplicationContext factory =
new AnnotationConfigApplicationContext(Factory.class); //factory라는 Class를 사용할게
//스프링컨테이너에 의해서 의존성주입이 실제로 되는지 확인해보자.
Service service = (Service) factory.getBean("service");
service.insert();
}
}
*Spring AOP(Aspect Oriented Programming
==>설계단계부터 들어가야 한다. 잘 모르면 사용하기 어렵다.ㅠ
핵심관심사항과 공통관심사항으로 나눈다.
핵심관심사항: 업무 로직에 핵심적인 기능. client의 요구사항. CourseService, StudentService...
AOP는,
문제를 해결하기 위한 핵심 관심 사항과 전체에 적용되는
공통 관심사항을 기준으로 프로그래밍 함으로써 공통 모듈을 손쉽게 적용할 수 있게 해준다.
*Spring AOP 용어
공통 관심사항을
Aspect라는 단어라고 부른다. 예>트랜잭션, 로깅, 보안
호출되는 시점을
JoinPoint라고 부른다. 이는 Aspect가 적용 될 수 있는 지점이다. 예>메서드, 필드
Acpect가 적용될 JoinPoint을
PointCut이라고 한다. <PointCut을 어떻게 정하냐에 따라서 JoinPoint가 결정된다.>
어느시점에 어떤 Aspect를 적용할지 정의하는것을
Advice라고 한다. <예: 핵심관심사항 이전에 호출할지/이후에 호출할지 결정한다>
Spring에서 AOP 구현 방법
1)POJO Class를 이용
2)스프링 API
3) Annotaion이용
<aop:config>
<aop:pointcut id=“publicmethod” expression=“execution(public * org.kosta.spring..*(..))”/> -->pointcut 모든메서드.
<aop:aspect id=“logingAspect” ref=“writelog”> -->공통관심사항. 호출할 사항.
<aop:around pointcut-ref=“publicmethod” method=“logging”/> --> 전후로 loggin메서드 호출
</aop:aspect>
</aop:config>
AOP 설정 태그
1. <aop:config> : aop설정의 root 태그. – weaving들의 묶음.
2. <aop:aspect> : Aspect 설정 – 하나의 weaving에 대한 설정
3. <aop:pointcut> : Pointcut 설정
4. Advice 설정태그들
A. <aop:before> - 메소드 실행 전 실행될 Advice
http://edu.kosta.or.kr
B. <aop:after-returning> - 메소드 정상 실행 후 실행될 Advice
C. <aop:after-throwing> - 메소드에서 예외 발생시 실행될 Advice
D. <aop:after> - 메소드 정상 또는 예외 발생 상관없이 실행될 Advice – finally
E. <aop:around> - 모든 시점에서 적용시킬 수 있는 Advice 구현
AOP 간단 예제
//insert()를 호출하면 자동으로 공통 관심사항이 호출된다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- AOP 관련 설정용 xml파일. namespaces에서 aop를 추가 해 준다. -->
<!-- Aspect도 메모리에 올라가야 하니까, bean으로 선언 -->
<bean id="logAspect" class="kosta.LogginAspect"/>
<!-- expression 중요하다. 핵심관심사항을 표현식으로 넣는다.-->
<aop:config>
<aop:pointcut expression="execution(public * kosta..*Service.insert(..))" id="servicePointCut"/>
<aop:aspect id="loggingAspect" ref="logAspect">
<aop:around method="logging" pointcut-ref="servicePointCut"/>
</aop:aspect>
</aop:config>
</beans>
package kosta;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
public class LogginAspect {
private Log log = LogFactory.getLog(getClass());
//공통 관심 메서드 Aspect.
//언제 => advice : around() => 이전(핵심) 이후
public Object logging (ProceedingJoinPoint joinPonit)throws Throwable {
log.info("log start");
StopWatch stopWatch = new StopWatch();
try {
stopWatch.start();
//핵심 관심로직 호출
Object obj = joinPonit.proceed();//insert() 호출!
return obj;
} catch (Exception e) {
throw e;
}finally {
stopWatch.stop();
log.info("log end");
log.info(joinPonit.getSignature().getName() + "메서드 실행시" +
stopWatch.getTotalTimeMillis());
}
}
}
public class Main {
public static void main(String[] args) {
//하나는 자바 생성용 XML, 하나는 AOP 관련 XML 두개를 넣지만, 하나로 만들어준다!
String[] config = {
"applicationContext.xml",
"commonConcern.xml"
};
ApplicationContext factory =
new ClassPathXmlApplicationContext(config);
Service service = (Service) factory.getBean("service");
service.insert();
}
}
=> 실행 결과
여기서, 우리가 정한 범위외의 메서드가 호출됐을땐
AOP가호출되면 안된다.
정말로 그런지 테스트 해보자.
인터페이스 하나를 만들고 insert라는 메서드를 만든다.
인터페이스를 구현하는 클래스를 하나 만든다.
그 클래스 안에 "인터페이스 - insert()호출 "이라는 로그를 찍는 메서드를 하나 만든다.
<bean>객체를 하나 만든다.
main에서 그 클래스-메서드를 호출한다.
=> 안되는것 확인.
'Today I learned' 카테고리의 다른 글
1월28일 (0) | 2019.01.28 |
---|---|
1월25일 (0) | 2019.01.25 |
프런트 컨트롤러 디자인 패턴 (0) | 2019.01.21 |
Ajax & Javascript 정리 (0) | 2019.01.21 |
12월17일 (0) | 2019.01.17 |
댓글