- Aop (관점지향 프로그래밍)
1. 공통관심사항 - aop
:: (여러객체가 사용하거나, 거쳐가는 기능인지)
공통기능으로 어플리케이션 전반에 걸쳐 필요한 기능을
2. 핵심관심사항 - 원래쓰던 객체처럼 사용
:: (이 객체가 핵심의 기능인지)
기존의 공통부분의 코드를 클래스화해서 메서드 호출하는것까지는 성공했지만,
그 호출하는 기능까지는 분리시키질 못했다.그렇기때문에 쓸때마다 공통클래스를 호출하는데
만약 그 공통부분의 클래스를 여러곳에서 호출했는데
여러곳중 하나가 기능을 추가해서 매개변수가 하나라도 늘어났다면
모든 클래스에서 에러가 나고 수정을 해야한다.
그렇기때문에 '횡단관점의 분리'라는 AOP로는 그 호출까지도 완전히 분리시키는 작업을한다.
- Aop 주요 용어
Advice :: 언제 공통기능을 핵심 로직에 적용할지 정의
JoinPoint :: Advice를 적용 가능한 지점 == 메서드 호출, 필드 값 변경
Pointcut :: Joinpoint의 부분집합. 실제로 Advice가 적용되는 Joinpoint
Weaving :: Advice를 핵심 로직 code에 적용하는 것을 weaving이라 한다.
Target object :: 하나 또는 그 이상의 Aspect에 의해 advice 되는 객체 -> 핵심 로직을 구현하는 클래스
Aspect :: 여러객체에 공통으로 적용되는 공통 관심 사항을 Aspect라 한다.
Around :: 메서드 실행의 전과 후에 모두 작업을 할 수 있고
언제, 어떻게, 상황에 따라 결정하기 위해서 메서드는 실제로 실행할 모든 것을 획득한다.
- excution(수식어패턴? 리턴타입패턴 클래스이름패턴?이름패턴(파라미터패턴))
수식어패턴 :: 생략가능, (ex:public,protected)
리턴타입패턴 :: 리턴타입명시
클래스이름패턴 :: 생략가능, 클래스이름명시
이름패턴 :: 메서드 이름 명시
파라미터패턴 :: 매칭될 파라미터에 대해서 명시
각 패턴은 *을 이용해 모든 값을 표현 가능
..을 이용하면 0개이상이라는 의미를 표현
[applicationContext.xml]
1 2 3 4 5 6 7 8 9 10 | <!-- aop 사용시작 --> <aop:aspectj-autoproxy /> <!-- target이 잡히지 않을때 사용하는방법. --> <aop:config proxy-target-class="true" /> <!-- 어노테이션 사용하겠다는의미 --> <context:annotation-config /> <!-- spring.anno패키지에 있는 모든 클래스 스캔 --> <context:component-scan base-package="spring.aop" /> | cs |
[GreetingText.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class GreetingTest { public static void main(String[] args) { AbstractApplicationContext context = new GenericXmlApplicationContext("applicationContext2.xml"); GreetingService bean = (GreetingService) context.getBean("greeting"); bean.sayHello("홍길동"); try { bean.sayGoodbye("홍길동2"); } catch (Exception e) { System.out.println(e.getMessage()); } } } | cs |
AbstractApplicationContext에 사용하려는 'Spring Bean Configuration File'로 생성한 xml 파일을 담는다.
이때, xml파일로 저장한 태그들 정보 로딩과, @로 지정한 모든 정보들을 담아 가지고 있는다.
밑에 저장한 greeting 클래스를 getBean해서 빈생성한 후 .sayHello("홍길동"); 실행
그러나 xml파일에는 'greeting'이라는것이 없다. 그것을 xml에서 설정하지않고
어노테이션으로 자바 클래스에서 설정했기때문이다.
[GreetingServiceImple.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //greeting이라는 이름으로 사용할 bean 생성 @Component("greeting") public class GreetingServiceImpl implements GreetingService { private String greeting; //기본형데이터타입이나 String을 넣을 Value로 값 저장. @Value("scott") public void setGreeting(String greeting) { this.greeting = greeting; } public void sayHello(String name) { System.out.println("sayHello : " + greeting + ":" + name); } public void sayGoodbye(String name) throws Exception { System.out.println("sayGoodbye : " + greeting + ":" + name); System.out.println(":: 예외 발생 :: 강제예외"); throw new Exception(); } } | cs |
String 매개변수 하나를 받은 sayHello메서드가 실행되어야한다......................... 하지만.
public이라는 클래스의 메서드 실행이므로
밑에 LogAspect에 담은 표현식에따라 어노테이션이 실행된다.
@Component 라는 annotation(어노테이션)으로 xml에서 <bean>태그로 잡아주던 빈 컨테이너를
자바에서 바로바로 할 수 있게 해준다.
---------------------------------------------------------------------------------------------------
-- Component 설명글 -- 알면 지나가세요
★★★ @Component ★★★
일반 java Class파일은@Component 적어주면 된다.
빈 객체의 이름은 자동적으로 클래스명에서 첫문자만 소문자이고 나머진 같다
ex)Foo -> foo
빈의 이름을 따로 지정해주고 싶다면, @Component(""); 로 지정하면 된다.
빈객체의 scope(getBean할대마다 새로운주소값을 가지는 객체생성)를 지정해주려면
@Component밑에 @Scope("prototype")으로 빈의 범위를 지정할 수 있다.
@Bean
새로운 빈 객체를 제공할 때 사용.. 메서드에 붙힘.
--------------------------------------------------------------------------------------------------------------------------
[LogAspect.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | @Component @Aspect public class LogAspect { //아무런 기능도안하는 메서드를 선언해 pointCut으로 쓰기위한 표현식지정. @Pointcut("execution(public * * (..))") public void publicMethod() {} //표현식에 해당되는 클래스의 '메서드'가 실행되기 '전에' 먼저실행하기위한 before @Before("publicMethod()") public void beforeLogging(JoinPoint j) { System.out.println("뭘까요? : " +j.getSignature().getName()); System.out.println(":: 메서드 호출 전 :: "); } //표현식에 해당되는 클래스의 '메서드'가 실행한 후에 //리턴값이 있다면 실행해서. returning 변수에 담아서 실행 @AfterReturning(pointcut="publicMethod()", returning="returnValue") public void afterLogging(Object returnValue) { System.out.println(":: 메서드 호출 후 :: "); } //표현식에 해당되는 클래스의 '메서드'가 실행될때, //예외처리가 발생하면 AfterThrowing이 채가서 throwing 변수에 담아 실행한다. @AfterThrowing(pointcut="publicMethod()", throwing="ex") public void throwingLogging(Exception ex) { System.out.println(":: 예외 발생 = " + ex.getMessage()+ " :: "); } // 표현식에 해당되는 클래스의 '메서드'가 실행되는 후에 // 1. 리턴했던, 2. 예외발생을했던, 3. 메서드가 문제없이 끝났던 ==> 후에 무조건 실행한다 //같은 After형식이 있을때 순서는 After 가 먼저 실행되고 AfterReturning이 실행된다. @After("publicMethod()") public void alwaysLogging() { System.out.println(":: 항상 실행 ::"); } } | cs |
[PerformanceAspect.java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | @Component @Aspect public class PerformanceAspect { @Pointcut("execution(public * spring.aop..*.sayHello(..))") private void pointCut() {} //메서드 실행의 전과 후 모두 작업할수있는 공통 로직. //위의 표현식에 해당하는 클래스의 메서드가 실행되면 무조건 Around를 먼저 실행하고 //원래 실행되려던 메서드는 .proceed()가 실행한다.. @Around("pointCut()") public Object timeCheck(ProceedingJoinPoint joinPoint) throws Throwable{ Signature s = joinPoint.getSignature(); String methodName = s.getName(); long startTime = System.nanoTime(); System.out.println("[Log]METHOD before : " + methodName + " time check start"); Object obj = null; try { obj = joinPoint.proceed(); }catch(Exception e) { System.out.println("[Log]METHOD error : " + methodName); } long endTime = System.nanoTime(); System.out.println("[Log]METHOD After : " + methodName + " time check end"); System.out.println("[Log] " + methodName + " Procedding time is " + (endTime - startTime)+ "ns"); return obj; } } | cs |
'JAVA > Spring' 카테고리의 다른 글
Spring - JdbcDaoSupport (0) | 2018.09.10 |
---|---|
Spring을 통한 jdbc연결 (0) | 2018.09.10 |
Spring예제 - setter방식 (2) | 2018.09.06 |
Spring예제 - bean과 aop혼합사용 (0) | 2018.09.05 |
Spring예제 - bean컨테이너 사용 (1) | 2018.09.05 |