반응형
     1.  SPRING AOP 의 특징 

1)  스프링은 Aspect의 적용 대상(target)이 되는 객체에 대한 Proxy를 만들어 제공.
2) 대상객체(Target)를 사용하는 코드는 대상객체(Target)를 Proxy를 통해서 간접적으로 접근
3) Proxy는 공통기능(Advice)을 실행한 뒤 대상객체(Target)의 실제 메서드를 호출하거나 대상객체(Target)의 실제 메소드가 호출된 뒤 공통기능(Advice)을 실행

AOP에 대해 자세하게 알기 전에 먼저 proxy에 대해 알아보자. 

* 프록시란?
프록시 서버는 기존의 핵심기능이 수행되는 순간 그 기능을 가로채어 앞뒤로 미리 설정된 프록시 기능을 수행해주는 역할을 합니다.

프록시 패턴의 핵심원리는 기존의 기능의 앞, 뒤로 프록시 기능을수행만 하면 된다는 것입니다. 그러므로 기존 기능만 알아서 반복동작한다면 프로그래머는 앞뒤로 덧붙일 기능만 작성하면 됩니다.

다이나믹 프록시는 이런 원리에 입각하여 기존의 메서드를 전부 재작성할 필요 없이 하나의 메서드에 덧붙일 새로운 프록시 기능만 완성시키면 자동으로 모든 메서드에 동일한 프록시 기능을 생성시켜줍니다


기능 10개를 프록시로 작성한다면 늘어난 기능만큼 프록시를 작성해야 한다. 이런걸 막기 위해 자바에서 나온 개념이 바로 다이나믹 프록시이다.


MethodInterceptor 인터페이스: 스프링의 어드바이스를 작성하기 위해 구현해야 할 (스프링에서 사용되는) 다이나믹 프록시 인터페이스입니다.
----> 우리가 MethodInterceptor를 구현하게 되면 반드시 invoke란 메서드를 구현해야 합니다. invoke메서드에 기존의 기능에 앞뒤로 덧붙이기만 하면 다이나믹 프록시가 완성됩니다. 그리고 이것을 포인트컷과 함께 어드바이저에 넘겨주면 끝 (용어를 모르겠다면 밑을 참고!)

     3.  용어 정리

1) 어드바이스(Advice): 특정 조인포인트에서 관점이 취하는 행동(action). "around", "before", "after" 어드바이스같은 여러 가지 타입의 어드바이스가 있다.  -  Joinpoint에서 실행되어야 하는 코드

2) 조인 포인트(Join point): 메서드의 실행이나 예외 처리같은 프로그램이 실행되는 중의 어떤 지점이다. 스프링 AOP에서 조인포인트는 항상 메서드 실행을 나타낸다. - 특정 작업이 실행되는 '시점'을 의미한다.

3) 관점(Aspect): 여러 클레스에 걸친 관심사의 모듈 - Advice와 Pointcut을 합쳐서 하나의 Aspect라고 한다.

4) 포인트컷(Pointcut): 조인포인트를 매칭하는 것(predicate)이다. 어드바이스는 포인트컷 표현식과 연결되고 포인트컷이 매치한 조인포인트에서 실행된다. - Target 클래스와 Advice가 결합(Weaving)될 때 둘 사이의 결합규칙을 정의하는 것이다

5) Weaving : AOP에서 Joinpoint들을 Advice로 감싸는 과정을 Weaving이라고 한다. Weaving 하는 작업을 도와주는 것이 AOP 툴이 하는 역할이다.

6) Target : 실질적인 비지니스 로직을 구현하고 있는 코드

어드바이스(Advice)란 특정 조인포인트에서 관점이 취하는 행동이라고 했다. 그렇다면 advice의 다양한 타입을 알아보자.

1) Before advice: joinpoint전에 수행되는 advice. 하지만 joinpoint를 위한 수행 흐름 처리(execution flow proceeding)를 막기위한 능력은 없다.
2) After returning advice: 메소드가 예외를 던지는것 없이 반환된다면 joinpoint 가 완성된 후에 수행되는 advice.
3) After throwing advice: 메소드가 예외를 던져서 빠져나갈때 수행되는 advice
4) After (finally) advice: join point를 빠져나가는 방법에 상관없이 수행되는 advice.
5) Around advice: 이것은 가장 강력한 종류의 advice이다. Around advice는 메소드 호출 전후에 사용자 정의 행위를 수행할수 있다. 짧게 수행하거나 예외를 던지는 것인지에 대해 책임을 진다.


    4. 포인트컷과 어드바이스

사실 설명만으로는 감이 잘 안올것이다. Spring에서 Aop 기술을 활용한 트랜잭션 예제를 살펴보며 이해하자.
저번 스터디때 트랜잭션은 두가지 방법이 있다고 했다. 그 중, 선언적 방법에는 @Transactional 어노테이션을 활용하는 방법과 <tx:advice>를 이용하는 방법이 있다. 우리 프로젝트(toyproject)에는 어노테이션 방법을 쓸 것이지만 <tx:advice>에 대해 개념은 알아두어야 할 것이다. 지금부터 알아보자!

<tx:annotation-driven />
<aop:config>
     <aop:advisor advice-ref="transactionAdvice" pointcut="bean(*Service)" />
</aop:config>

<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="exceptionPut" propagation="REQUIRES_NEW" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>


이 소스에 관해 하나씩 분석 해보자. 먼저 pointcut 에 관한 설명을 해보겠다.

<aop:advisor pointcut="bean(*Service)" advice-ref="transactionAdvice" />

"bean(*Service)"처럼 설정한다면 빈 중에서 Service로 끝나는 모든 빈을 선택하게 됩니다.

포인트컷은 학습테스트나 특별한 기능을 위해서라면 org.springframework.aop.Pointcut 인터페이스를 구현하여 따로 클래스로 만들 수도 있지만 보통은 위의 예제처럼 간편하게 <aop:advisor> 내에 위치시키는 방법이 일반적입니다. 다만 하나 이상의 포인트컷을 입력하고 싶다면 아래 이미지와 같이 구성할 수도 있습니다.



다음으로 우리가 알아볼 것은 바로 어드바이스입니다.


<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="exceptionPut" propagation="REQUIRES_NEW" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>

어드바이스는 포인트컷으로 선택한 빈에 적용될 부가기능을 뜻합니다. AOP는 트랜잭션만을 위한 기술이 아니기 때문에 필요하다면 어드바이스를 통해 포인트컷으로 선별될 빈(또는 클래스, 메서드)의 적용 기술을 자유롭게 변경할 수 있습니다. 물론 여기서 우리가 적용할 부가기능은 바로 트랜잭션입니다.

이런 어드바이스는 org.aopalliance.intercept.MethodInterceptor를 구현하여 만들어집니다. ( MethodInterceptor 인터페이스: 스프링의 어드바이스를 작성하기 위해 구현해야 할 (스프링에서 사용되는) 다이나믹 프록시 인터페이스라고 위에 설명해놓았다. 2번 참고.)

다음은 어드바이저이다.
포인트컷과 어드바이스를 통해 어드바이저를 만들고, 어드바이저는 어드바이스와 포인트컷의 정보를 참조하는 기능을 한다. 다음과 같은 그림을 보면 좀더 이해하기 편하겠다. 앞의  통 소스와 그림과 함께 보면 더욱 이해가 빠를 것이다.
5. 자동프록시생성기

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

자동프록시생성기는 기본적으로 org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator 클래스를 뜻합니다. 이 클래스가 빈으로 등록되어 있다면 자동으로 Advisor 인터페이스를 구현한 빈이 컨텍스트에 등록되었는지를 확인해주고 해당 어드바이저들에 정의되있는 포인트컷과 어드바이스를 해석하여 해당 요청이 왔을 때 자동으로 이 요청을 가로채어 프록시를 생성해줍니다. 사용법은 컨텍스트에 해당 빈을 생성해주기만 하는 것으로 끝이 납니다.

단, AOP 기술을 사용한다면  <aop:~>태그만 사용한다면 등록된 어드바이저들은 모두 자동프록시생성기를 통해 해당 포인트컷으로 클래스를 인터셉터하고 어드바이스에 등록된 기능을 수행한다는 보장한다. 


출처: http://truepia.tistory.com/275 [진실세상을 꿈꾸며]

http://egloos.zum.com/springmvc/v/498979

출처: http://devjms.tistory.com/70 [얼렁뚱땅 개발자]

출처  http://wiki.gurubee.net/pages/viewpage.action?pageId=26740833



반응형

'개발공부 > Spring' 카테고리의 다른 글

예외처리(1)  (0) 2020.10.01
Spring에서 Bean을 주입하는 방식  (0) 2020.03.16
SLF4J와 Logback  (1) 2018.06.26
Tiles란, Spring tiles3 적용법  (2) 2018.06.14
반응형
<Tiles 기본>
  1.  tiles 란?
-  반복적으로 사용되는 header, footer와 같은 정보를 한곳에 모아둔 프레임 워크

  1.   tiles3로 오면서 설정이 더욱 간단해 졌다. tiles3는 spring3.2 버전 이상부터 쓰일 수 있으니 참고바람.

  1.     pom.xml에 3가지 dependency를 추가한다.

pom.xml

<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-extras</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-servlet</artifactId>
    <version>3.0.0</version>
</dependency></p>


  1.    tiles를 유동적으로 사용하고 싶다면 다음과 같이 설정한다.  우선 모든 view들은 tiles를 정의한 tiles 설정 파일의  definition들에서
binding될 jsp 등의 view 파일들을 찾게됩니다. 만약 각 views.xml에서 view 파일을 못찾게 되면 우선순위가 2인 InternalResourceViewResolver 에서 해당 view 파일을 찾게 됩니다.

참고 >> 
view resolver
- View Resolver는 Spring의 DispatcherServlet이 Controller의 응답 결과를 가져올 때, 어떤 방식으로 view 객체를 가져올지 정하고 해당 객체를 생성한다.
- View Resolver를 구현한 클래스는 InternalResourceViewResolver, BeanNameViewResolver, XmlViewResolver, UrlBasedViewResolver 등이 있다.
- DispatcherServlet은 여러개의 ViewResolver를 가질 수 있는데, 'order' property에 따라 어떤 ViewResolver를 결정할지 우선순위를 정할 수 있다. 우선순위를 명시하지 않으면 가장 낮은 우선순위를 가진다.
- 우선순위가 높은 ViewResolver에게 View 객체를 요청하는데, 만약 null을 리턴한다면 그 다음 우선순위의 ViewResolver에게 객체를 요청하게 된다.
- InternalResourceViewResolver는 항상 mapping되는 view 객체를 리턴하고, 없다고 null을 반환하지 않으므로 항상 가장 낮은 우선순위로 두어야한다.



dispatcher-servlet.xml

<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView" />
  <property name="order" value="1" />
</bean>

// tiles의 우선순위를 1로 설정해둔다.

 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/views/"/>
  <property name="suffix" value=".jsp"/>
  <property name="order" value="2"></property>
 </bean>

//기존에 써있던 view resolver 에서 우선순위만 바꿔줬다.


<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
  <property name="definitions">
  <list>
  <value>/WEB-INF/tiles/tiles.xml</value>
  </list>
  </property>
</bean>

//tiles관련 설정파일 
//만약 여러개 하고 싶다면 list의 value를 추가해주면 된다.


  1. 다음은 tiles 설정파일 tills.xml

<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">

<tiles-definitions>
  <definition name="default" template="/WEB-INF/views/layout/layout.jsp">
  <put-attribute name="header" value="/WEB-INF/views/layout/header.jsp" />
  <put-attribute name="body" value=""/>
  <put-attribute name="footer" value="/WEB-INF/views/layout/footer.jsp" />
  </definition>

//기본적인 defiinition 태그를 하나 만들어둔다.

  <definition name="tiles" extends="default">
<put-attribute name="body" value="/WEB-INF/views/layout/mainTest.jsp" />
</definition>

//  defiinition 을 상속받아 여러 타일즈를 만들수 있다.

</tiles-definitions>


빨간색으로 표시한 definition name="tiles" <- 이부분이 중요하다.  이부분때문에 오류가 많이난다.

  1. layout.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
  pageEncoding="EUC-KR"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
</head>

<body>
  <div id="wrap">
  <div >
  <div>
  <div>
  <tiles:insertAttribute name="header" />
  </div>
  </div>
  <div>
  <div>
  <tiles:insertAttribute name="body" />
  </div>
  </div>
  <div>
  <div>
  <tiles:insertAttribute name="footer" />
  </div>
  </div>
  </div>
  </div>
</body>
</html>



기본적으로 만들고 싶은 틀을 html 형식으로 만들어 준다.    <tiles:insertAttribute name="footer" /> 의 name은 tiles.xml에서 설정한 name과 같아야 한다. 

  1. Controller mapping 추가

@RequestMapping(value = "/test", method = RequestMethod.GET)
  public String hello(Locale locale, Model model) {

  Date date = new Date();
  DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

  String formattedDate = dateFormat.format(date);

  model.addAttribute("serverTime", formattedDate );
  return "tiles";
  }


return 값과 definition에서 정의한 name이 반드시 일치하게 해야 404 에러가 안난다. 기본적인 설정은 완료하였다. 
응용버전은 추후 추가하도록 하겠다.

  1. 기본적인 부분 완성!  - header.jsp , footer.jsp, mainTest.jsp 는 커밋해놓았으니 각자 코드를 확인해보기 바란다!



<Tiles 응용>
앞서 소개한 tiles 를 우리 프로젝트에 응용할 수 있도록 해보겠다.





우리가 앞서 소개한 부분은 defulat이다. 근데 나는 left 메뉴가 있는화면도 필요하다면 tiles.xml에 <definition>을 추가할 수 있다.


<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">

<tiles-definitions>
  <definition name="default" template="/WEB-INF/views/layout/layout.jsp">
<put-attribute name="header" value="/WEB-INF/views/layout/header.jsp" />
<put-attribute name="body" value=""/>
<put-attribute name="footer" value="/WEB-INF/views/layout/footer.jsp" />
  </definition>

<1>
  <definition name="withLeft" template="/WEB-INF/views/layout/layout_left.jsp">
<put-attribute name="header" value="/WEB-INF/views/layout/header.jsp" />
<put-attribute name="left" value=""/>
<put-attribute name="body" value=""/>
<put-attribute name="footer" value="/WEB-INF/views/layout/footer.jsp" />
  </definition>  

  <definition name="tiles" extends="default">
<put-attribute name="body" value="/WEB-INF/views/layout/mainTest.jsp" />
</definition>

<2>
<definition name="user/*/*" extends="withLeft">
<put-attribute name="left" value="/WEB-INF/views/layout/left.jsp"/>
<put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
</definition>



</tiles-definitions>


<1>  template을 다르게 해서  definition을 추가했다. 이를 상속받아 <2>를 추가했다.

여기서 중요한것은 <2>번이다. 다들 이를 응용하여 개발하면 된다.
definition name="/" -- > controller mapping 형태를 말한다. 

참고>>>
definition name 형식 -
- ? : 한 글자, * : 아무글자나, [abc] : abc로 시작

IssueController.java
@RequestMapping(value={"/issue/list"} , method=RequestMethod.GET)
public String showIssueList(HttpServletRequest request) {
return "issue/issueList";
}
}


/issue/list를 매핑하여  issue/issueList를 return 한다.
그러면  issue가 {1}  issueList가 {2}가 된다.
즉 issue 폴더 아래에 있는 issueList에 적용한다는 것이다.


http://localhost:8081/toyProject/issue/list  를 호출하면 다음과 같은 화면이 나온다. 




layout_left.jsp 가 적용된 화면이니 이를 응용하여 프로젝트에 활용하면 된다 . 끝!







출처: http://creator1022.tistory.com/176 [무한도전]







반응형

'개발공부 > Spring' 카테고리의 다른 글

예외처리(1)  (0) 2020.10.01
Spring에서 Bean을 주입하는 방식  (0) 2020.03.16
SPRING AOP  (0) 2018.07.02
SLF4J와 Logback  (1) 2018.06.26

+ Recent posts