AOP 방면 프로 그래 밍

Dynamic Proxy 와 Spring AOP
 
Spring 에서 제공 하 는 내 장 된 AOP 지원 은 동적 AOP 메커니즘 을 바탕 으로 이 루어 집 니 다.기술적 인 측면 에서 볼 때 이른바 동적 AOP,즉 동적 프 록 시 모드 를 통 해 대상 의 방법 호출 전후 에 해당 하 는 처리 코드 를 삽입 하 는 것 이다.반면 Spring AOP 의 동적 프 록 시 모드 는 자바 Dynamic Proxy(인터페이스 지향)와 CGLib(Class 지향)를 기반 으로 이 루어 진다.앞서 언급 했 듯 이 Spring Framework 의'사무 관리'서 비 스 는 사실상 AOP 메커니즘 을 통 해 이 루어 졌 다.우 리 는 여기 서'사무 관리'를 예 로 들 어 동태 AOP 의 실현 에 대해 연 구 를 하고 한편 으로 는 동태 AOP 의 실현 원 리 를 탐구 하 며 다른 한편 으로 는 Spring 중의 사무 관리 체제 에 대한 이 해 를 강화 할 수 있다.
 
다음은 Dynamic Proxy 의 예 입 니 다.
 
AOPHandler.java
 
package aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class AOPHandler implements InvocationHandler {

	private static Log logger = LogFactory.getLog(AOPHandler.class);
	private List interceptors = null;
	private Object originalObject;
	/**
	*         
	* @param obj
	* @return
	*/
	public Object bind(Object obj) {
	this.originalObject = obj;
	return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
	obj
	.getClass().getInterfaces(), this);
	}
	/**
	*  Invoke   ,     Interceptor,   
	*    (before)、   (after)      (exceptionThrow)  
	*/
	public Object invoke(Object proxy, Method method, Object[] args)
	throws Throwable {
	Object result = null;
	Throwable ex = null;
	InvocationInfo invInfo = new InvocationInfo(proxy, method, args,
	result, ex);
	logger.debug("Invoking Before Intercetpors!");
	System.out.println("Invoking Before Intercetpors!");
	invokeInterceptorsBefore(invInfo);
	try {
		logger.debug("Invoking Proxy Method!");
		System.out.println("Invoking Proxy Method!");
		result = method.invoke(originalObject, args);
		invInfo.setResult(result);
		logger.debug("Invoking After Method!");
		System.out.println("Invoking After Method!");
		invokeInterceptorsAfter(invInfo);
		} catch (Throwable tr) {
		invInfo.setException(tr);
		logger.debug("Invoking exceptionThrow Method!");
		System.out.println("Invoking exceptionThrow Method!");
		invokeInterceptorsExceptionThrow(invInfo);
		throw new AOPRuntimeException(tr);
		}
		return result;
		}
		/**
		*   Interceptor
		* @return
		*/
		private synchronized List getIntercetors() {
		if (null == interceptors) {
		interceptors = new ArrayList();
		//Todo:    ,  Interceptor  
		interceptors.add(new MyInterceptor());	
		}
		return interceptors;
		}
		/**
		*        
		* @param invInfo
		*/
		private void invokeInterceptorsBefore(InvocationInfo invInfo) {
		List interceptors = getIntercetors();
		int len = interceptors.size();
		for (int i = 0; i < len; i++) {
			((Interceptor) interceptors.get(i)).before(invInfo);
			}
			}
			/**
			*        
			* @param invInfo
			*/
			private void invokeInterceptorsAfter(InvocationInfo invInfo) {
			List interceptors = getIntercetors();
			int len = interceptors.size();
			for (int i = len - 1; i >= 0; i--) {
			((Interceptor) interceptors.get(i)).after(invInfo);
			}
			}
			/**
			*         
			* @param invInfo
			*/
			private void invokeInterceptorsExceptionThrow(InvocationInfo
			invInfo) {
			List interceptors = getIntercetors();
			int len = interceptors.size();
			for (int i = len - 1; i >= 0; i--) {
			((Interceptor)
			interceptors.get(i)).exceptionThrow(invInfo);
			}
			}
			

}

 
 AOP Runtime Exception.java 이상 처리
package aop;

public class AOPRuntimeException extends RuntimeException {
	
	AOPRuntimeException(Throwable e)
	{
		
	}

}

 
 Interceptor.java 차단기 인터페이스
 
package aop;

public interface Interceptor {
	public void before(InvocationInfo invInfo);
	public void after(InvocationInfo invInfo);
	public void exceptionThrow(InvocationInfo invInfo);
	}

 MyInterceptor.java 차단기 의 실현:
package aop;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MyInterceptor implements Interceptor{
	
	private static Log logger = LogFactory.getLog(MyInterceptor.class);
	public void before(InvocationInfo invInfo) {
	logger.debug("Pre-processing");
	System.out.println("Pre-processing");
	System.out.println("beginTransaction");
	}
	public void after(InvocationInfo invInfo) {
	logger.debug("Post-processing");
	System.out.println("Post-processing");
	System.out.println("endTransaction");
	}
	public void exceptionThrow(InvocationInfo invInfo) {
	logger.debug("Exception-processing");
	System.out.println("Exception-processing");
	System.out.println("rollback();");
	}

}

 
AOFactory.java 생 성 에이전트 공장
 
package aop;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class AOPFactory {
	
	private static Log logger = LogFactory.getLog(AOPFactory.class);
	/**
	*          
	* @param clzName
	* @return
	* @throws ClassNotFoundException
	*/
	public static Object getClassInstance(String clzName){
	Class cls;
	try {
	cls = Class.forName(clzName);
	return (Object)cls.newInstance();
	} catch (ClassNotFoundException e) {
	logger.debug(e);
	throw new AOPRuntimeException(e);
	} catch (InstantiationException e) {
	logger.debug(e);
	throw new AOPRuntimeException(e);
	} catch (IllegalAccessException e) {
	logger.debug(e);
	throw new AOPRuntimeException(e);
	}
	}
	/**
	*        ,  AOP    
	* @param clzName
	* @return
	*/
	public static Object getAOPProxyedObject(String clzName){
		AOPHandler txHandler = new AOPHandler();
		Object obj = getClassInstance(clzName);
		return txHandler.bind(obj);
		
	}

}

 
InvocationInfo.java
 
package aop;

import java.lang.reflect.Method;

public class InvocationInfo {
	
	Object proxy;
	Method method;
	Object[] args;
	Object result;
	Throwable Exception;
	public InvocationInfo(Object proxy, Method method, Object[] args,
	Object result, Throwable exception) {
	super();
	this.proxy = proxy;
	this.method = method;
	this.args = args;
	this.result = result;
	Exception = exception;
	}
	public Object getResult() {
	return result;
	}
	public void setResult(Object result) {
	this.result = result;
	}
	public Object[] getArgs() {
	return args;
	}
	public void setArgs(Object[] args) {
	this.args = args;
	}
	public Throwable getException() {
	return Exception;
	}
	public void setException(Throwable exception) {
	Exception = exception;
	}
	public Method getMethod() {
	return method;
	}
	public void setMethod(Method method) {
	this.method = method;
	}
	public Object getProxy() {
	return proxy;
	}
	
	public void setProxy(Object proxy) {
		this.proxy = proxy;
		}

}

 UserDAO.java
에이전트 가 필요 한 인터페이스
package aop;

public interface UserDAO {
	
	public void saveUser();

}

 UserDAOImp.java
 
 
package aop;

public class UserDAOImp implements UserDAO {

	public void saveUser() {
		// TODO Auto-generated method stub
        System.out.println("UserDAOImp saveUser");
	}
 
}

 TestAOP.자바 테스트 클래스
 
package aop;

public class TestAOP {
	
	public static void main(String[] args){
		
		Object ob = AOPFactory.getAOPProxyedObject("aop.UserDAOImp");
		UserDAO dao = (UserDAO)ob;
		dao.saveUser();
		
	}

}

  
실행 결과:
 
Invoking Before Intercetpors!
Pre-processing
beginTransaction
Invoking Proxy Method!
UserDAOImp saveUser
Invoking After Method!
Post-processing
endTransaction

  
프 록 시 효과 CGLib 와 Spring AOP 표시
 
Spring 에 서 는 CGLib 를 인터페이스 없 는 동적 에이전트 로 도입 했다.CGLib 는 Dynamic Proxy 의 프 록 시 메커니즘 과 기본적으로 유사 하지만 동적 으로 생 성 된 프 록 시 대상 은 특정한 인터페이스의 실현 이 아니 라 목표 클래스 에 대한 확장 하위 클래스 입 니 다.다시 말 하면 Dynamic Proxy 가 되 돌아 오 는 동적 프 록 시 클래스 는 목표 클래스 가 실현 하 는 인터페이스의 또 다른 실현 버 전 으로 목표 클래스 에 대한 프 록 시(예 를 들 어 UserDAOProxy 와 UserDAOImp 의 관계)를 실현 했다.CGLib 가 되 돌아 오 는 동적 프 록 시 클래스 는 대상 프 록 시 클래스 의 하위 클래스(프 록 시 클래스 가 UserDAOImp 클래스 로 확장 되 었 습 니 다)입 니 다.
 
CGLIB.프로젝트 를 참조 하려 면 몇 개의 jar 패 키 지 를 가 져 와 야 합 니 다:antlr-2.7.2.jar,asm-attrs.jar,aspectj-1.6.1.jar,aspectjrt.jar,aspectjweaver.jar
 
AOPInstrumenter.java
 
package aop;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class AOPInstrumenter implements MethodInterceptor{
 
 private static Log logger =
  LogFactory.getLog(AOPInstrumenter.class);
  private Enhancer enhancer = new Enhancer();
  public Object getInstrumentedClass(Class clz) {
  enhancer.setSuperclass(clz);
  enhancer.setCallback(this);
  return enhancer.create();
  }
  
  public Object intercept(
    Object o,
    Method method,
    Object[] methodParameters,
    MethodProxy methodProxy)
    throws Throwable {
    logger.debug("Before Method =>"+method.getName());
    System.out.println("Before Method =>"+method.getName());
    Object result = methodProxy.invokeSuper(o, methodParameters);
    logger.debug("After Method =>"+method.getName());
    System.out.println("After Method =>"+method.getName());
    return result;
    }

}


 
 
UserDAOImp.java
 
package aop;

public class UserDAOImp {
 
 public void saveUser()
 {
  System.out.println("UserDAOImp method saveUser");
 }

}


  
TestAOPCGLib.java
package aop;

public class TestAOPCGLib {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  
  AOPInstrumenter aopInst = new AOPInstrumenter();
  UserDAOImp userDAO =
  (UserDAOImp) aopInst.getInstrumentedClass(UserDAOImp.class);
 
  userDAO.saveUser();

 }

}


 
 
TestAOPCLib 의 실행 결 과 는:
 
Before Method =>saveUser
UserDAOImp method saveUser
After Method =>saveUser

 

좋은 웹페이지 즐겨찾기