Java 에이전트(jdk 정적 에이전트, 동적 에이전트와 cglib 동적 에이전트)

9238 단어 cglibjdk대리
1. 에이전트는 자바에서 자주 사용하는 디자인 모델로 에이전트 클래스는 피에이전트 클래스의 관련 방법을 호출하고 관련 방법을 강화한다.사무, 로그, 경보 메일 등 비업무적인 코드를 넣는다.
2. jdk 정적 에이전트
1. 비즈니스 인터페이스

/** 
 *   
 * @author pc 
 * 
 */
public interface UserService { 
   
  //   
  public void addUser(); 
  //   
  public void editUser(); 
 
} 
2. 비즈니스 실현 클래스

/** 
 *   
 * @author pc 
 * 
 */
public class UserServiceImpl implements UserService { 
 
  public void addUser() { 
    System.out.println(" 。。。"); 
  } 
 
  public void editUser() { 
    System.out.println(" 。。。"); 
  } 
 
} 
3. 에이전트 클래스
/**
* 프록시 클래스
*
* @author pc
*
*/
public class UserServiceProxy implements UserService {
private UserServiceImpl userImpl;
public UserServiceProxy(UserServiceImpl countImpl) {
this.userImpl = countImpl;
}
public void addUser() {
System.out.println("대리류 방법, 강화되었습니다....");
System.out.println ("사무 시작...);
//위탁류를 호출하는 방법;
userImpl.addUser();
System.out.println ("처리 완료...);
}
public void editUser() {
System.out.println("대리류 방법, 강화되었습니다....");
System.out.println ("사무 시작...);
//위탁류를 호출하는 방법;
userImpl.editUser();
System.out.println ("사무가 끝났습니다.");
}
}
  
4. 테스트 클래스

public static void main(String[] args) { 
  UserServiceImpl userImpl = new UserServiceImpl(); 
  UserServiceProxy proxy = new UserServiceProxy(userImpl); 
  proxy.addUser(); 
  System.out.println("---------- ----------"); 
  proxy.editUser(); 
} 

5. 결과
대리류 방법, 증강...
사무가 시작되다.
사용자 추가...
처리 끝...
분할선
대리류 방법, 증강...
사무가 시작되다.
사용자 편집...
사무가 끝나다.
  
3. jdk 동적 에이전트
1. 비즈니스 인터페이스

/** 
 *   
 * @author pc 
 * 
 */
public interface UserService { 
   
  //   
  public void addUser(); 
  //   
  public void editUser(); 
 
} 
2. 비즈니스 인터페이스 구현 클래스

/** 
 *   
 * @author pc 
 * 
 */
public class UserServiceImpl implements UserService { 
 
  public void addUser() { 
    System.out.println(" 。。。"); 
  } 
 
  public void editUser() { 
    System.out.println(" 。。。"); 
  } 
} 
3. 에이전트 클래스

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
 
/** 
 * 
 * @author pc 
 * 
 */
public class ServiceInvocationHandler implements InvocationHandler { 
 
  //   
  private Object target; 
 
  public ServiceInvocationHandler(Object target) { 
    super(); 
    this.target = target; 
  } 
 
  /** 
   *   
   * @return 
   * @throws Throwable 
   */
  public Object getProxy() throws Throwable { 
    return Proxy.newProxyInstance(Thread.currentThread() 
        .getContextClassLoader(), this.target.getClass() 
        .getInterfaces(), this); 
    //  , 。 
    // return target; 
  } 
 
  /** 
   *  InvocationHandler  
   *  ,  
   */
  public Object invoke(Object proxy, Method method, Object[] args) 
      throws Throwable { 
    Object result = null; 
    System.out.println(" , 。。。"); 
    System.out.println(" 。。。"); 
    //   
    result = method.invoke(target, args); 
    System.out.println(" 。。。"); 
    return result; 
  } 
 
} 
4. 테스트 클래스

public class Test { 
  /** 
   * jdk , , ClassLoader 。 
   *  Proxy , , InvocationHandler  
   *  invoke() 。 
   * @param args 
   * @throws Throwable 
   */
  public static void main(String[] args) throws Throwable { 
    UserService userService = new UserServiceImpl(); 
    ServiceInvocationHandler handler = new ServiceInvocationHandler(userService); 
    //   
    UserService proxy = (UserService) handler.getProxy(); 
    proxy.addUser(); 
//   proxy.editUser(); 
 
  } 
 
} 
5. 테스트 결과
대리류 방법, 증강...
사무가 시작되다.
사용자 추가...
사무가 끝나다.
4. cglib 동적 에이전트
cglib의jar 패키지를 도입해야 하는데,
pom.xml 가입 종속성:

<!-- https://mvnrepository.com/artifact/cglib/cglib --> 
<dependency> 
  <groupId>cglib</groupId> 
  <artifactId>cglib</artifactId> 
  <version>2.2.2</version> 
</dependency> 
  
1. 비즈니스 클래스, 인터페이스 없음

/** 
 *   
 *   
 *  final , , 。 
 *  final ,  
 * @author pc 
 * 
 */
public class UserServiceImpl { 
 
  public void addUser() { 
    System.out.println(" 。。。"); 
  } 
 
  public void editUser() { 
    System.out.println(" 。。。"); 
  } 
} 
2. 에이전트 클래스

import java.lang.reflect.Method; 
 
import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 
 
/** 
 *  Cglib  
 * @author pc 
 * 
 */
public class UserServiceCglib implements MethodInterceptor{ 
 
  private Object target; 
   
  /** 
   *   
   * @param target 
   * @return 
   */
  public Object getInstance(Object target){ 
    this.target = target; 
    Enhancer enhancer = new Enhancer(); 
    enhancer.setSuperclass(this.target.getClass()); 
    //   
    enhancer.setCallback(this); 
    //   
    return enhancer.create(); 
  } 
   
  /** 
   *  MethodInterceptor 。 
   *   
   */
  public Object intercept(Object obj, Method method, Object[] args, 
      MethodProxy proxy) throws Throwable { 
    System.out.println(" 。。。");   
    Object result = proxy.invokeSuper(obj, args);   
    System.out.println(" 。。。");   
    return result;   
  } 
 
} 
3. 테스트 클래스

public class TestCglib { 
 
  public static void main(String[] args) { 
    UserServiceCglib cglib = new UserServiceCglib(); 
    UserServiceImpl bookFacadeImpl = (UserServiceImpl)cglib.getInstance(new UserServiceImpl()); 
    bookFacadeImpl.addUser(); 
//   bookFacadeImpl.editUser(); 
  } 
} 
4. 결과:
사무가 시작되다.
사용자 추가...
사무가 끝나다.
5. 업무 실현 클래스가final 클래스로 정의되면 다음과 같은 오류가 발생합니다

Exception in thread "main" java.lang.IllegalArgumentException: Cannot subclass final class class cn.xx.xx.cgilb.UserServiceImpl 
  at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446) 
  at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) 
  at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) 
  at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) 
  at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285) 
  at cn.pconline.proxy.cgilb.UserServiceCglib.getInstance(UserServiceCglib.java:30) 
  at cn.pconline.proxy.cgilb.TestCglib.main(TestCglib.java:7) 

5. 총결산
1. 원리
jdk 정적 에이전트의 실현은 비교적 간단하다. 일반적으로 직접 에이전트 대상은 피에이전트 대상을 직접 포장한다.
jdk 동적 에이전트는 인터페이스 에이전트입니다. 피에이전트 클래스 A는 업무 인터페이스를 실현해야 하고 업무 에이전트 클래스 B는 InvocationHandler 인터페이스를 실현해야 합니다.
jdk 동적 에이전트는 피에이전트 대상에 따라 프록시 클래스를 계승하고 이 업무 인터페이스를 실현하는 jdk 에이전트 클래스를 생성합니다. 이 클래스의 바이트 코드가 전송되는 ClassLoader를 불러와서 jdk 에이전트 대상 실례를 만들었습니다.
jdk 프록시 대상 실례가 생성될 때 업무 프록시 대상 실례는 Proxy 클래스에 값을 부여받는다. jdk 프록시 대상 실례도 업무 프록시 대상 실례가 있고 jdk 프록시 대상 실례는 반사를 통해 프록시 클래스의 업무 방법에 따라 해당하는 Method 대상 m(여러 개가 있을 수 있음)를 만든다.jdk 프록시 대상의 실례적인 업무 방법, 예를 들어proxy.addUser();이것은 먼저 대응하는 m대상을 매개 변수로 invoke() 방법(즉 invoke 방법의 두 번째 매개 변수)에 전달하고 jdk 프록시 대상의 실례적인 invoke() 리셋 방법을 호출합니다. invoke 방법에서 반사를 통해 피프록시 대상을 호출하는 방법, 즉result=method입니다.invoke(target, args);.
cglib 동적 에이전트는 계승 에이전트로 ASM 바이트 프레임워크를 통해 바이트 코드를 수정하여 새로운 하위 클래스를 생성하고 다시 쓰고 방법을 강화하는 기능입니다.
2. 장단점
jdk 정적 에이전트 클래스는 하나의 피에이전트 클래스로만 서비스할 수 있으며, 에이전트가 필요한 클래스가 비교적 많으면 너무 많은 에이전트 클래스가 생길 수 있습니다.jdk 정적 에이전트는 컴파일할 때class 파일을 생성하고 실행할 때 생성할 필요가 없으며 직접 사용할 수 있으며 효율이 좋습니다.
jdk 동적 에이전트는 반드시 인터페이스를 실현하고 반사를 통해 동적 에이전트 방법을 통해 시스템 성능을 소모해야 한다.그러나 너무 많은 프록시 클래스가 생기지 않아도 중복 코드의 발생을 피하고 시스템이 더욱 유연해진다.
cglib 동적 에이전트는 인터페이스를 실현할 필요가 없고 서브 바이트 코드를 생성함으로써 반사보다 빠르고 성능 문제가 없습니다.그러나 cglib는 피에이전트 클래스를 계승하기 때문에 피에이전트 방법을 다시 써야 하기 때문에 피에이전트 클래스는final 클래스가 될 수 없고 피에이전트 방법은final이 될 수 없습니다.
따라서 cglib의 응용은 더욱 광범위하다.
이상의 이 간단한 Java 에이전트(jdk 정적 에이전트, 동적 에이전트와 cglib 동적 에이전트)는 여러분께 공유된 모든 내용입니다. 여러분께 참고가 되고 저희를 많이 사랑해 주시기 바랍니다.

좋은 웹페이지 즐겨찾기