Spring Framework에서는 AOP 사용을 위하여 XML방식도 지원을 한다.

        

AOP라는 네임스페이스 태그를 사용하면 된다.

 

XML 방식 사용 시, XML선언에 하단 내용을 추가해주여야 한다.

(기존 내용에서 xmlns:aop, xsi:schemaLocation의 aop 부분이 추가되었다.)

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		https://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

XML을 사용하여 AOP 전체 예제 내용

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<aop:config>
		<aop:aspect id="aspect" ref="schemaBasedCls">
		
			<aop:pointcut id="executionTest" expression="execution(* com.example.aop.PrintCls.*(..))"/>
			
			<aop:before 
				pointcut-ref="executionTest" 
				method="beforeTest"/>
			<aop:after-returning
        		pointcut-ref="executionTest"
       			returning="retVal"
        		method="executionAndReturnValTest"/>
		  	<aop:after-throwing
		        pointcut-ref="executionTest"
		        throwing="ex"
		        method="executionAndAfterThrowingValTest"/>
		  	<aop:after
        		pointcut-ref="executionTest"
        		method="executionAndAfterTest"/>
			<aop:around
        		pointcut-ref="executionTest"
        		method="executionAndAroundTest"/>
		</aop:aspect>
	</aop:config>
	
	<bean id="schemaBasedCls" class="com.example.aop.SchemaBasedCls"></bean>
	<bean id="printCls" class="com.example.aop.PrintCls"></bean>
</beans>
package com.example.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ImportResource;

import com.example.aop.PrintCls;

@SpringBootApplication
@ImportResource("classpath:aop.xml")
public class DemoSchemabasedApplication {
	private static final Logger logger = LoggerFactory.getLogger(DemoSchemabasedApplication.class);	
	
	public static void main(String[] args) {
		ConfigurableApplicationContext run = SpringApplication.run(DemoSchemabasedApplication.class, args);
		
		PrintCls bean = run.getBean(PrintCls.class);

		logger.info("--------------    bean method start	--------------");
		bean.printExample();
		logger.info("--------------    bean method end	--------------");
		
		logger.info("--------------    bean return method start    --------------");
		bean.returnStr();
		logger.info("--------------    bean return method end    --------------");
		
		logger.info("--------------    bean throw method start    --------------");
		try {
			bean.returnThrow();
		} catch (Exception e) {
		}
		logger.info("--------------    bean throw method end    --------------");
	}
}
package com.example.aop;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PrintCls {

	private static final Logger logger = LoggerFactory.getLogger(PrintCls.class);
	
	public void printExample() {
		logger.info("*** printExample");
	}
	
	public String returnStr() {
		String value = "testReturning";
		logger.info("*** print returning Str" + value );
		return value;
	}
	
	public void returnThrow() throws Exception {
		String msg = "execption test";
		logger.info("*** print throw " + msg);
		throw new Exception(msg);	
	}
}
package com.example.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SchemaBasedCls {
	private static final Logger logger = LoggerFactory.getLogger(SchemaBasedCls.class);
	
	//--before--
	public void beforeTest() {
		logger.info("before start");
		logger.info("before end");
	}
	//--before--
	
	//--AfterReturning--
	public void executionAndReturnValTest(String retVal) {
		logger.info("execution and afterReturning Value start");
		logger.info("Value :" + retVal);
		logger.info("execution and afterReturning Value end");
	}
	//--AfterReturning--
	
	//--AfterThrowing--
	public void executionAndAfterThrowingValTest(Exception ex) {
		logger.info("execution and AfterThrowing Value start");
		logger.error(ex.getMessage());
		logger.info("execution and AfterThorwing Value end");
	}
	//--AfterThrowing--
	
	//--After--
	public void executionAndAfterTest() {
		logger.info("execution and After start");
		logger.info("execution and AFter end");
	}
	//--After--
	
	//--Around--
	public void executionAndAroundTest(ProceedingJoinPoint pjp) {
		logger.info("execution and around start");
		logger.info(pjp.getSignature().getName() + " Before Method Execution");
		try {
			pjp.proceed();
		} catch (Throwable e) {
			logger.info(pjp.getSignature().getName() + "Throw Method Execution");
		} finally {
			// Do Something useful, If you have
		}
		logger.info(pjp.getSignature().getName() + " After Method Execution");
		logger.info("execution and around end");
	}
	//--Around
}

AOP

- 기본적인 개념은 공통 관심 사항을 구현한 코드를 핵심로직을 구현한 코드 안에 삽입한다는 것.

   

AOP 용어

- Aspect : 공통 코드 ( ex : 트랙잭션, 로깅 )

- Advice : 공통코드를 적용하는 시점. ( 특정 메소드 실행전, 특정 메소드 실행후 등등 )

- Joinpoint : Advice가 적용 가능한 지점. 

- Pointcut : JointPoint중에서 Aspect가 적용되는 위치.

- Introduction : 함수나 멤버변수를 추가적으로 선언하는 기능

- Weaving : 핵심로직에서 Aspect가 동작이 되는 것.

    Weaving 방식

    1. 컴파일 시

    2. 클래스 로딩시

    3. 런타임 시

 

Spring에서 제공되는 AOP.

- @AspectJ ( 어노테이션 방식 )

- Schema-based AOP ( XML 방식 )



시스템의 요구사항이나 설계에 따라 상황에 맞는 AOP를 사용하면 되지만, 

Schema-based AOP가 가진 단점을 이해해야 한다.

 

1. XML방식이기 때문에 완전한 캡슐화 되지는 않는다.

- 설정파일에 XML과 빈(Bean)에 대한 선언이 분할되어 사용되기 때문이다.

2. XML에 선언 된 포인트 컷을 결합 할 수 없습니다. 

@Pointcut("execution(* get*())")
public void propertyAccess() {}

@Pointcut("execution(org.xyz.Account+ *(..))")
public void operationReturningAnAccount() {}

@Pointcut("propertyAccess() && operationReturningAnAccount()")
public void accountPropertyAccess() {}
<aop:pointcut id="propertyAccess"
        expression="execution(* get*())"/>

<aop:pointcut id="operationReturningAnAccount"
        expression="execution(org.xyz.Account+ *(..))"/>