AOP--프록시 모드, 차단기의 간편한 실현 및 원리
다음은 로그 기록을 추가하는 것을 예로 삼아 정적 에이전트의 사용을 분석합니다.사용자 관리 클래스 UserManagerImpl을 생성하고 사용자 추가 방법addUser를 생성하여 확장성을 극대화하고 다음과 같은 공통 인터페이스 UserManager를 생성합니다.
인터페이스 코드:
package com.snail.pattern;
public interface UserManager {
public void addUser(String userId,String userName);
}
클래스 코드 구현:
package com.snail.pattern;
public class UserManagerImpl implements UserManager {
public void addUser(String userId, String userName) {
try {
//System.out.println(" ");
System.out.println("HelloWorld!");
//System.out.println(" !");
}catch(Exception e) {
e.printStackTrace();
//System.out.println(" !");
throw new RuntimeException();
}
}
}
코드를 통해 알 수 있듯이 주석 안의 로그 내용은 업무 논리와 아무런 관계가 없고 어느새 결합성을 증가시킨다. 만약에 많은 종류에 이런 로그 코드를 추가해야 한다면 작업량은 말하지 않아도 알 수 있고 수정하기도 매우 번거롭다.정적 에이전트를 사용하여 인쇄 로그의 코드를 에이전트 클래스에 추출하면 에이전트 클래스와 업무 논리 클래스를 통해 같은 부류를 계승하고 클라이언트는 에이전트 클래스를 직접 호출하여 수요를 완성한다. 그러면 클라이언트와 업무 논리 클래스의 결합을 해결할 수 있다.예제 코드는 다음과 같습니다.
package com.snail.pattern;
public class UserManagerImplProxy implements UserManager{
private UserManager userManager;
public UserManagerImplProxy(UserManager userManager){
this.userManager = userManager;
}
@Override
public void addUser(String userId, String userName) {
try {
System.out.println(" ");
userManager.addUser(userId, userName);
System.out.println(" !");
}catch(Exception e) {
e.printStackTrace();
System.out.println(" !");
}
}
}
클라이언트 호출 코드는 다음과 같습니다.
package com.snail.pattern;
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());
userManager.addUser("0111", " ");
}
}
정적 에이전트는 업무 논리와 무관한 코드를 격리하고 결합을 낮추며 업무 논리류를 업무 논리에 더욱 집중하게 하지만 코드량을 줄일 수 없고 시스템의 중복 코드가 너무 많아 프로그래머의 작업량을 증가시켰다.따라서 JDK 동적 에이전트는 이 문제를 완벽하게 해결했다. 동적 에이전트는 시스템 운행 기간에 클래스에 동적 에이전트를 추가한 다음에 에이전트 클래스를 조종하여 목표 클래스에 대한 호출을 완성할 수 있다.
계속해서 상기 예를 들어 정적 에이전트를 동적 에이전트로 바꾸고 추상 클래스 UserManager와 목표 클래스 UserManager Impl의 코드는 변하지 않으며 정적 에이전트 클래스 UserManager ImplProxy를 삭제하고 LoadHandler 클래스를 추가하여 InvocationHandler 인터페이스의 invoke 방법을 실현하도록 한다. 코드는 다음과 같다.
package com.snail.pattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogHandler implements InvocationHandler {
// targetObject
private Object targetObject;
//Proxy
public Object newProxyInstance(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(" !");
for(int i=0;i<args.length;i++){
System.out.println(args[i]);
}
Object ret = null;
try{
//
ret = method.invoke(targetObject, args);
System.out.println(" !");
}catch(Exception e){
e.printStackTrace();
System.out.println(" !");
throw e;
}
return ret;
}
}
Proxy 클래스가 만든 목표 클래스는 최소한의 인터페이스를 실현해야 하며, newProxyInstance 방법을 호출할 때 목표 클래스의 클래스 마운트와 인터페이스와 일치해야 한다.invoke 방법은 Filter의doFilter 방법과 매우 유사합니다. 목표 클래스의 모든 방법을 UserManagerImpl에 도착하기 전에 캡처하고, 우리의 요구에 따라 미리 처리한 후에 UserManagerImpl을 계속 호출합니다.
invoke 방법의 통용성을 유지하기 위해 목표 방법의 매개 변수는 수조args 형식으로 전달되며, 방법에 반환 값이 있으면 반환하고 반환 값이 없으면 반환null로 되돌아옵니다.이렇게 되면 프로그래머는 모든 목표 클래스에 프록시 클래스를 설계할 필요가 없다. 로그를 출력해야 하는 모든 클래스가 이 LogHandler를 공용할 수 있다. 로그 기능을 사용하지 않으려면 LogHandler 클래스를 직접 삭제할 수 있고 원래 기능에 아무런 영향을 주지 않는다. 마치 모니터의 보호막을 벗기는 것처럼 모니터의 사용에 영향을 주지 않는다.
클라이언트 호출 코드는 다음과 같습니다.
package com.snail.pattern;
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
LogHandler logHandler = new LogHandler();
UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
userManager.addUser("id", "name");
}
}
상기 두 편의 블로그를 통해 저는 여러분들이 AOP의 원리와 응용 장소에 대해 반은 알고 있고 문장에 오류가 발생할 수 있다고 믿습니다. 여러분의 아낌없는 가르침을 바랍니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Exception Class에서 에러 코드 해석 ~초기초편~직장에서 C# 프로젝트가 내뿜는 오류 코드를 구문 분석하고 오류의 위치를 확인하기 위해 Exception class를 활용할 수 있었습니다. 지금까지 Exception Class 에 대해서 별로 파악할 수 없었기 때...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.