[스프링 프레임워크/Spring Framework] Annotation(어노테이션)/ AOP(Aspect Oriented Programming) 05

2013. 3. 15. 16:19Information Technology/Spring

오늘은 [스프링 프레임워크/Spring Framework] Annotation(어노테이션)/ AOP(Aspect Oriented Programming) 에 대해서 알아보도록 하겠습니다.

 

□ Autowire

ByName : 등록된 빈중에 class가 지니고 있는 setter 매서드를 다 찾고 세터 메서드의 property가 일치하는게 있다면 묶어줌 (setter 시 사용)

 

byType : 등록된 이름은 상관없음, Outputter 서비스의 유형, 서브타임 (생성자 활용시 많이 사용)

 

※ 한번 등록된 빈은 계속 사용된다. Single ton(객체를 한 개만 유지하는 패턴)

But 한번 사용된 빈을 새로 만들어서 쓰는 설정이 있다.(@scope > prototype, 매번 생성)

 

○ Autowire 실습예제

 

□ Annotation (어노테이션)

- xml에 있던 속성을 자바코드로 넣어줌

@autowired

- OutputService 기능이 일치하는 것을 묶어줌

@value

- 같은 타입이 있는지 확인 > 같은 타입이면 bean name이 같은걸 실행

@ Required

- 필수로 받게 함, 강제로 자바소스에 setter 값을 넣어야 하는 경우 사용

@ Scope

- 매번 만들건지 설정 가능

 

○ Autoscan (오토스캔)

@Component

스프링 네가 관리해야 하는 빈

클래스에다가 어노테이션을 줌으로써 빈 설정시 클래스 경로를 따로 주지 않는다.

 

※ 최근에는 xml을 지원하면서 에노테이션도 지원하는 방향으로 간다.

========================= 여기 까지 DI ============================

 

[스프링 프레임워크/Spring Framework] Annotation(어노테이션)/ AOP(Aspect Oriented Programming) 중 AOP에 대해서 알아보겠습니다.

 

□ [ AOP (Aspect Oriented Programming)/ 관점지향 프로그래밍 ] , (관심사의 분리)

○ 그림 설명

• 핵심 비즈니스 로직

- 계좌이체, 입출금, 이자계산

• 핵심 로직에 적용되는 공통 로직

- 로깅, 보안, 트랜잭션

[그림 출처 : www.egovframe.go.kr/Egovcmm,.jsp

 

□ AOP 용어 정리

○ Concern

애플리케이션을 개발하기 위하여 관심을 가지고 구현 해야 하는 각각의 기능들을 관심 사항(Concern)이라 함

○ core concern

핵심 관심 사항

해당 애플리케이션이 제공하는 핵심이 되는 비즈니스 로직 의미

○ cross-cutting concern

횡단[공통] 관심 사항

하나의 영역에서만 활용되는 고유한 관심 사항(Concern)이 아니라, 여러 클래스 혹은 여러 계층의 애플리케이션 전반에 걸쳐서 공통적으로 필요로 하는 기능들 의미

 

※ 스프링은 Proxy에 기반한 Weaving을 지원함

소스 코드나 클래스 정보 자체를 변경하지 않음

프록시를 이용하여 AOP적용

프록시 기반의 AOP는 핵심 로직을 구현한 프록시를 통해서 핵심 로직을 구현한 객체에 access

프록시 기반의 제한사항 : 메소드 호출할 경우에만 Advice를 적용

• 핵심로직 실행 전, 후 / 예외가 발생했을 때

• 메소드 호출 전, 호출 후, 예외, 항상 즉 4가지 경우

• 즉 객체가 생성되고 변경이 되었을 때는 절대 사용할 수가 없다.

 

□ AOP 주요 용어

□ Proxy

 

□ Spring에서의 AOP

- Spring에서는 자체적으로 런타임시에 위빙하는 "프록시 기반의 AOP"를 지원

- 프록시 기반의 AOP는 메소드 호출 조인포인트만 지원

- Spring에서 어떤 대상 객체에 대해 AOP를 적용할 지의 여부는 설정 파일, 에노테이션을 통해서 지정

- Spring은 설정 정보를 이용하여 런타임에 대상 객체에 대한 프록시 객체를 생성 따라서, 대상 객체를 직접 접근하는 것이 아니라 프록시를 통한 간접 접근을 하게 됨

- Spring은 완전한 AOP 기능을 제공하는 것이 목적이 아니라 Enterprise Application을 구현하는데 필요한 기능을 제공하는 것을 목적으로 하고 있음

- 필드값 변경 등 다양한 조인포인트를 이용하려면 AspectJ와 같은 다른 AOP솔루션을 이용해야 함

 

□ 프록시 가반의 AOP 적용 process

 

□ Spring AOP 프록시의 종류

○ 핵심 로직 구현 방법에 따른 proxy 종류

 

□ Spring에서의 AOP

○ AOP 구현을 위한 개발 방법

• XML 스키마 기반의 POJO 클래스를 이용한 AOP 구현

• 애노테이션 기반의 AOP

 

□ AOP 실습

- getBean > greeting 요청 > 팩토리 자체가 등록되는게 아니라 팩토리가 객체를 생성한 것이 등록이 됨, 즉 ProxyFactoryBean을 부르면 Proxy가 리턴이 됨, 공통로직이 다 실행된 체로

<!-- proxy 만들어 주는 공장, 타겟을 맵핑하는 -->

    <bean id="greeting" class="org.springframework.aop.framework.ProxyFactoryBean"

        p:target-ref="greetingTarget">

        <property name="interceptorNames">

            <list>

                <value>transformAdvisor</value>

                <value>logAdvisor</value>

            </list>

        </property>

        </bean>

 

[구조도]

 


package com.asianaidt.sample1.api;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class AfterLogAdvice implements AfterReturningAdvice {

	// 의미 있는 매개변수는 returnValue
	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args,
			Object target) throws Throwable {
		
		System.out.println("method complete.....................");

	}

}



package com.asianaidt.sample1.api;

public interface GreetingService {
	void sayHello(Person person);
	void sayGoodbye(Person person);

}


package com.asianaidt.sample1.api;

public class GreetingServiceImpl implements GreetingService {

	@Override
	public void sayHello(Person person) {
		System.out.println(person.getAge()+"살인"+person.getName()+"야 안녕");

	}

	@Override
	public void sayGoodbye(Person person) {
		System.out.println("잘가 " + person.getName());
	}

}



package com.asianaidt.sample1.api;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;



public class GreetingTest {

	public static void main(String[] args) {
		
		
		ApplicationContext container = new ClassPathXmlApplicationContext("applicationContext1-1.xml");

		// big >= small
		GreetingService greetingService = (GreetingService)container.getBean("greeting");
	
		greetingService.sayHello(new Person("Daniel",7));
		System.out.println("============================");
		greetingService.sayGoodbye(new Person("jia",5));
		
	}

}


package com.asianaidt.sample1.api;

public class Person {
	private String name;
	private int age;
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}


package com.asianaidt.sample1.api;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

// 핵심로직의 정보를 담고 있는 class
public class TransformAdvice implements MethodBeforeAdvice {

	
	// 핵심로직 실행전에 실행되는 로직
	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("try to transform................");
		Person p = (Person)args[0];
		p.setName(p.getName().toUpperCase());
	}

}




	

	
	
	


	
	

	

	

	
	
	

	
	

	
	
		
			
				transformAdvisor
				logAdvisor