자바 동적 에이전트 구현 코드

1.대리 모드
대리 모델 은 자주 사용 하 는 디자인 모델 중 하나 이자 개발 에서 흔히 볼 수 있 는 디자인 모델 이다.
간단하게 설명 하면 대리 모델 은 바로 유형 을 분리 하 는 것 이다.예 를 들 어 여자친 구 에 게 생일 을 보 내 고 싶 고 스타 를 찾 아 생일 노래 를 부 르 는 것 이다.네 여자 친구 의 우상 은 주걸륜 이다.주걸륜 을 찾 아 생일 을 보 내 고 노래 를 부 르 고 싶 지만 주걸륜 과 연락 이 잘 되 지 않 는 다.즉,소 셜 네트워크 서비스 에 연락 하 는 것 도 너 를 잘 거들 떠 보지 않 을 것 이다.그래서 주걸륜 의 매니저 에 게 연락 해서 소통 할 수 있 습 니 다.매니저 는 주걸륜 의 대리 입 니 다.
실현 과정:
1.노래의 인 터 페 이 스 를 정의 하고 업 무 를 대표 한다.

public interface ISing {
   void sing();
}
2.주걸륜 은 노래 를 부 르 는 업무 가 있 고 업무 가 뛰 어 나 인 터 페 이 스 를 실현 한다.

/**
*    
*/
public class JayImp implements ISing {
   @Override
   public void sing() {
       System.out.println("say happy birthday to you girl friend");
  }
}
3.매니저 가 업 무 를 받 을 때 매니저 의 구조 함 수 는 스타 와 연결 되 어야 한다.
매니저 가 노래 를 부 르 는 업 무 를 맡 았 는데 오늘 은 주걸륜 이 부 르 는 것 일 수도 있 고 내일 은 매니저 가 스타 가 바 뀌 었 을 수도 있다.예 를 들 어 채 이 린 도 가능 하 다.

/**
*    
*/
public class JayProxy implements ISing{
   ISing target;
   /**
    *       ,       
    * @param target
    */
   public JayProxy(ISing target) {
       this.target = target;
  }
   @Override
   public void sing() {
       target.sing();
  }
}
4.매니저 에 게 연락 해 노래 를 부 르 고,주걸륜 이 노래 를 부 르 고 나 면 매니저 가 돈 을 받 고,very happy

public class MoneyOwner {
   public static void main(String[] args) {
       JayImp jay = new JayImp();
       //            ,           
       JayProxy jayProxy = new JayProxy(jay);
       jayProxy.sing();
  }
}
집행 결 과 를 보 니 모두 가 기뻐 하 는 구나,네 여자 친 구 는 매우 기뻐 하 는 구나.
图片
위의 이 방법 은 바로 대리 모델 의 실현 이다.
그러나 프 록 시 클래스 는 한 종류 만 대리 할 수 있 습 니 다.모든 서 비 스 를 위해 프 록 시 클래스 를 만 들 면 바보 같 습 니 다.
그리고 인터페이스 가 바 뀌 면 대리 클래스 도 바 뀌 어야 돼 요.너무 불편 해 요.주걸륜 씨 는 영화 도 찍 고 예능 도 하고 노래 도 쓰 고 업무 도 많아 요.
자,정적 대리 가 할 말 도 했 습 니 다.여 기 를 보면 이해 하지 못 할 것 이 없 을 것 이 라 고 믿 습 니 다.다음은 저희 가 본 격 적 으로 오늘 의 정식,동적 대 리 를 시작 하 겠 습 니 다.
2.동적 에이전트
동적 프 록 시 는 자바 가 제공 하 는 프 록 시 방식 입 니 다.이 기술 의 핵심 점 은 운영 기간 에 인 터 페 이 스 를 강화 하고 클 라 스 대상 을 생 성 한 다음 에 가상 컴퓨터 에 불 러 오 는 것 입 니 다.간단 한 것 은 가상 컴퓨터 가 인 터 페 이 스 를 실현 하 는 클 라 스 를 만 드 는 것 입 니 다.
잔말 말고 먼저 동적 대 리 를 실현 하 자.
첫 번 째 정의 인터페이스,위의 코드 는 이미 ISing 이 있 으 면 중복 정 의 를 하지 않 습 니 다.
두 번 째 단 계 는 인 터 페 이 스 를 실현 하고 위의 코드 도 JayImp 를 실현 하 며 정 의 를 반복 하지 않 습 니 다.이번 에는 매니저 가 가수,임 준걸 을 한 명 더 계 약 했 습 니 다.실현 을 보 세 요.

package org.pdool.dynamic;
/**
*    
*/
public class JJImp implements ISing {
   @Override
   public void sing() {
       System.out.println("I am JJ! happy birthday to you");
  }
}
세 번 째 단 계 는 매니저 가 계약 가 수 를 동태 적 으로 파견 할 수 있다.매니저 가 Invocation Handler 를 실현 해 야 모든 방법 을 통일 적 으로 처리 할 수 있다.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JayAgentFactory implements InvocationHandler {
   Object target;
   public JayAgentFactory(Object target) {
       this.target = target;
  }
   //      
   public ISing CreatProxyedObj() {
       return (ISing) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
  }
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object invoke = method.invoke(target, args);
       logAfter(invoke);
       return invoke;
  }
   public void logAfter(Object invoke) {
       System.out.println("   " + invoke);
       System.out.println("   ++ ");
  }
}
제4 단계 업무 접수

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JayAgentFactory implements InvocationHandler {
   Object target;
   public JayAgentFactory(Object target) {
       this.target = target;
  }
   //      
   public ISing CreatProxyedObj() {
       return (ISing) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
  }
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object invoke = method.invoke(target, args);
       logAfter(invoke);
       return invoke;
  }
   public void logAfter(Object invoke) {
       System.out.println("   " + invoke);
       System.out.println("   ++ ");
  }
}
요약:동적 대 리 는 자바 가 제공 하 는 실현 방식 으로 Invocation Handler 의 실현 류 가 필요 합 니 다.
1.왜 편집기 가 인터페이스 방법 을 제시 할 수 있 습 니까?편집 기 를 강하 게 돌리 기 때문에 힌트 가 있 을 수 있 습 니 다.
2.생 성 된 메모리 클 라 스 는 기본 구조 함수 로 Invocation Handler 인자 가 필요 합 니 다.
3.프 록 시 클 라 스 를 만 드 는 핵심 매개 변 수 는 클래스 로 더,인터페이스,그리고 Invocation Handler 서브 클래스 입 니 다.
클래스 로 더 보증 과 목표 클래스 가 같은 로 더 에 있 습 니 다.호출 할 수 있 습 니 다.서로 다른 로 더 가 불 러 오 는 클래스 간 에 호출 되 지 않도록 합 니 다.
인 터 페 이 스 는 바로 네가 대리 할 인터페이스 이다.
Invocation Handler 하위 클래스 는 전송 기 입 니 다.모든 메 시 지 를 차단 처리 하고 전송 합 니 다.
3.원리 연구
실현 보 았 습 니 다.원 리 를 탐구 하 세 요.동적 에이전트 의 가장 근본 적 인 것 은 인터페이스 에 따라 메모리 클 라 스 를 만 드 는 것 입 니 다.이 단 계 는 어떻게 실현 되 었 는 지 원본 코드 를 따라 보 겠 습 니 다.
图片
1.클론 인터페이스 함수 정보
2.지정 한 프 록 시 클래스 를 찾 거나 생 성 합 니 다.캐 시 에 있 으 면 캐 시 를 사용 하고 없 으 면 생 성 합 니 다.
3.반 사 를 통 해 대리 류 의 구조 함 수 를 얻는다.
4.구조 함 수 를 통 해 프 록 시 대상 을 만 들 고 Invocation Handler 와 관련 된 대상 을 만 듭 니 다.

  /** parameter types of a proxy class constructor */
   private static final Class<?>[] constructorParams =
      { InvocationHandler.class };
프로 세 스 를 보 았 습 니 다.대리 클 라 스 가 어떤 모습 인지 보 겠 습 니 다.

import sun.misc.ProxyGenerator;
public class Test {
   public static void main(String[] args) {
       //      class  
       System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
       ProxyGenerator.generateProxyClass("Xiangcai", JayImp.class.getInterfaces());
  }
}
위의 함 수 를 실행 하면 프로젝트 의 경로 에서 Xiangcai.class 를 생 성 하 는 것 을 볼 수 있 습 니 다.
图片
이어서 xiangcai.class 에 어떤 것 이 있 는 지 편집기 로 끌 어 다 놓 으 면 됩 니 다.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.pdool.dynamic.ISing;
public final class xiangcai extends Proxy implements ISing {
   private static Method m1;
   private static Method m2;
   private static Method m3;
   private static Method m0;
   public xiangcai(InvocationHandler var1) throws {
       super(var1);
  }
   public final boolean equals(Object var1) throws {
       try {
           return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
      } catch (RuntimeException | Error var3) {
           throw var3;
      } catch (Throwable var4) {
           throw new UndeclaredThrowableException(var4);
      }
  }
   public final String toString() throws {
       try {
           return (String)super.h.invoke(this, m2, (Object[])null);
      } catch (RuntimeException | Error var2) {
           throw var2;
      } catch (Throwable var3) {
           throw new UndeclaredThrowableException(var3);
      }
  }
//     !!!       
   public final void sing() throws {
       try {
           super.h.invoke(this, m3, (Object[])null);
      } catch (RuntimeException | Error var2) {
           throw var2;
      } catch (Throwable var3) {
           throw new UndeclaredThrowableException(var3);
      }
  }
   public final int hashCode() throws {
       try {
           return (Integer)super.h.invoke(this, m0, (Object[])null);
      } catch (RuntimeException | Error var2) {
           throw var2;
      } catch (Throwable var3) {
           throw new UndeclaredThrowableException(var3);
      }
  }
   static {
       try {
           m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
           m2 = Class.forName("java.lang.Object").getMethod("toString");
           m3 = Class.forName("org.pdool.dynamic.ISing").getMethod("sing");
           m0 = Class.forName("java.lang.Object").getMethod("hashCode");
      } catch (NoSuchMethodException var2) {
           throw new NoSuchMethodError(var2.getMessage());
      } catch (ClassNotFoundException var3) {
           throw new NoClassDefFoundError(var3.getMessage());
      }
  }
}
sing 을 실현 하 는 인 터 페 이 스 를 볼 수 있 고 invoke handler 를 호출 하 는 방법 invoke 를 볼 수 있 습 니 다.자,진실 이 밝 혀 졌 습 니 다.아 시 겠 습 니까?
어떤 사람 은 이 치 를 나 는 다 알 지만 쓸 줄 모 르 지만 좋 은 응용 장면 을 보지 못 해서 한동안 이런 것 을 파악 하지 못 했다.다음은 응용 장면 을 구체 적 으로 살 펴 보 자.
4.응용
절단면 프로 그래 밍(AOP)에 서 는 특정 방법 을 차단 해 야 하 며,보통 동적 에이전트 방식 을 선택한다.구체 적 인 예 를 들 어 spring-data-jpa 의 실현
구체 적 인 사용:
spring 에서 데이터베이스 에 접근 하 는 사용

import com.tao.springboot.hibernate.entity.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
위의 인터페이스 만 실현 하면 데이터 베 이 스 를 직접 조작 할 수 있 습 니 다.간단 하지 않 습 니까?
몇 가지 문제 가 있 습 니 다.조금 만 생각해 보 세 요.
1,두 개의 범 형 은 무슨 뜻 입 니까?
2.데이터 베 이 스 는 어디 에 연결 되 어 있 습 니까?어떻게 주입 되 었 습 니까?
3.인터페이스 만 실현 하면 데이터 베 이 스 를 어떻게 조작 합 니까?
첫 번 째 문제 의 답:
  • Customer 는 표 대상 에 대응 하 는 entity 실체 이다
  • Long 은 시계의 메 인 키 유형 입 니 다두 번 째 답:
    데이터베이스 연결 은 spring 이 시 작 될 때 spring 용기 에 자동 으로 주입 되 며,Jpa Repository 의 실현 클래스 에 자동 으로 주입 된다.
    세 번 째 답:
    모든 인 터 페 이 스 는 spring 이 시 작 될 때 프 록 시 클래스 를 생 성 합 니 다.목표 클래스 target 은 클래스 Simple Jpa Repository 입 니 다.
    분류 도 를 보다
    图片
    Jpa Repository 의 정 의 를 보 세 요.모두 일반적인 방법 입 니 다.
    
    public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
       List<T> findAll();
       List<T> findAll(Sort var1);
       List<T> findAllById(Iterable<ID> var1);
       <S extends T> List<S> saveAll(Iterable<S> var1);
       void flush();
       <S extends T> S saveAndFlush(S var1);
       void deleteInBatch(Iterable<T> var1);
       void deleteAllInBatch();
       T getOne(ID var1);
       <S extends T> List<S> findAll(Example<S> var1);
       <S extends T> List<S> findAll(Example<S> var1, Sort var2);
    }
    Simple Jpa Repository 의 정 의 를 보십시오.
    
    public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
       private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";
       private final JpaEntityInformation<T, ?> entityInformation;
      private final EntityManager em;//   !!!
       private final PersistenceProvider provider;
       @Nullable
       private CrudMethodMetadata metadata;
       //       
          @Transactional
       public void delete(T entity) {
           Assert.notNull(entity, "The entity must not be null!");
           this.em.remove(this.em.contains(entity) ? entity : this.em.merge(entity));
      }
    다음 과 같은 코드 호출:
    
    Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), JpaRepository.class.getInterfaces(), new SimpleJpaRepository(());
    주:뜻 만 표현 할 뿐 구체 적 인 실현 은 그렇지 않 을 것 입 니 다.
    5.총화
    모든 일이 풀 렸 습 니 다.다음은 정리 하 겠 습 니 다.
    1.정적 대 리 는 대리 모델 의 실현 이 고 특정한 구체 적 인 인터페이스 에 대한 실현 이다.
    2.동적 대 리 는 jdk 가 제공 하 는 방식 으로 인터페이스 가 필요 하 며 다른 실현 방식 cglib,javassit 등 이 있 습 니 다.
    3.동적 프 록 시 는 실 행 될 때 class 파일 을 생 성하 고 자동 으로 불 러 오 는 class 입 니 다.
    4.동적 대 리 는 반사 호출 을 바탕 으로 하 는 기술 이다.
    5.동적 에이 전 트 는 class 를 metaspace 로 생 성 합 니 다.
    6.프레임 에 많이 활용
    7.spring data jpa 의 실현 복호화
    이 글 은 여기까지 입 니 다.당신 에 게 도움 을 줄 수 있 기 를 바 랍 니 다.또한 당신 이 우리 의 더 많은 내용 에 관심 을 가 져 주 실 수 있 기 를 바 랍 니 다!

    좋은 웹페이지 즐겨찾기