Java 반사와 에이전트에 대한 간단한 설명

9412 단어 java반사대리
자바 반사 메커니즘과 동적 에이전트는 자바를 더욱 강하게 한다. 스프링의 핵심 개념인 IoC, AOP는 반사 메커니즘과 동적 에이전트를 통해 이루어진다.
1 Java 반사
예:

User user = new User();
user.setTime5Flag("test");
 
Class<?> cls = Class.forName("com.test.User");
// public, ! cls.getDeclaredMethod(), 
Method method = cls.getMethod("getTime5Flag");
String res1 = (String) method.invoke(user);
System.out.println(res1);
// int, int.class!Integer.class!=int.class!
method = cls.getMethod("setTime5Flag", String.class); 
method.invoke(user, "Rollen");
method = cls.getMethod("getTime5Flag");
String res2 = (String) method.invoke(user);
System.out.println(res2);
하나의 객체를 통해 전체 패키지 이름과 클래스 이름을 얻을 수 있습니다.

user.getClass().getName();// 
user.getClass().getSimpleName();// 
class 가져오기:

Class.forName("com.test.User");
com.test.User.class;
user.getClass();
class를 통해 하나의 대상을 실례화하다

User user = (User) cls.newInstance();// 
모든 구조 함수 얻기

Constructor<?> cons[]=cls.getConstructors(); // 
cons[0].newInstance();// , 
하나의 클래스로 이루어진 모든 인터페이스 얻기

Class<?> intes[] = cls.getInterfaces();
부류를 얻다

cls.getSuperClass();
수식자를 얻다

int mo = cls.getModifiers();
int mo = cons[0].getModifiers();
int mo = method.getModifiers();
Modifier.toString(mo);
획득 방법 매개 변수

method.getParametors();
cons[0].getParametors();
가져오기 방법 매개 변수 유형

method.getParametorTypes();
cons[0].getParametorTypes();
가져오기 방법은 모든 이상 유형을 표시합니다.

method.getExceptionTypes();
클래스 선언의 모든 속성 가져오기

Field[] field = cls.getDeclaredFields(); // private
field[0].getModifiers();
field[0].getType();
부류 성명, 인터페이스 성명, 부류 성명의 모든public 속성을 포함하여 이 클래스의 모든 공개 속성을 가져옵니다.

cls.getFields();
액세스 가능한 지정 속성 설정

field.setAccessible(true);
field.set(obj,'ces');
field.get(obj);
* getFields () 와 getDeclaredFields () 의 차이점: getFields () 는 클래스에서 공유로 선언된 필드만 접근할 수 있으며, 개인 필드는 접근할 수 없으며, 다른 클래스에서 계승된 공유 필드는 접근할 수 있습니다.getDeclaredFields()는 클래스의 모든 필드에 접근할 수 있습니다.public,private,protect와 무관하지만 다른 클래스에서 계승된 필드에 접근할 수 없습니다
*getMethods()와 getDeclaredMethods()의 차이점: getMethods()는 클래스에서 공유로 성명된 방법만 접근할 수 있고, 개인적인 방법은 접근할 수 없으며, 다른 클래스에서 계승된 공유 방법에 접근할 수 있습니다.getDeclaredMethods()는 클래스의 모든 필드에 접근할 수 있습니다.public,private,protect와 상관없이 다른 클래스에서 계승된 방법에 접근할 수 없습니다
*getConstructors()와 getDeclaredConstructors()의 차이점: getConstructors()는 클래스에서public로 선언된 구조 함수만 접근할 수 있습니다.getDeclaredConstructors()는 클래스의 모든 구조 함수에 접근할 수 있습니다.public,private,protect와 무관합니다
반사를 통해 수조의 정보를 얻고 수정합니다

int[] temp={1,2,3,4,5};
Class<?> demo = temp.getClass().getComponentType();
System.out.println(" : "+demo.getName());//int
System.out.println(" : "+Array.getLength(temp));//5
System.out.println(" : "+Array.get(temp, 0));//1
Array.set(temp, 0, 100);
System.out.println(" : "+Array.get(temp, 0));//100
그룹 유형 가져오기

cls.getComponentType();
그룹 유형 여부 판단

cls.isArray();
2 Java 에이전트
프록시 모델은 자주 사용하는 자바 디자인 모델로 그 특징은 프록시 클래스와 의뢰 클래스가 같은 인터페이스를 가진다는 것이다. 프록시 클래스는 주로 의뢰 클래스를 위해 메시지를 미리 처리하고 필터링하며 메시지를 의뢰 클래스에 전달하고 사후 처리 메시지 등을 책임진다.대리류와 위탁류 사이에는 일반적으로 관련 관계가 존재한다. 하나의 대리류의 대상은 하나의 위탁류의 대상과 관련된다. 대리류의 대상 자체는 진정으로 서비스를 실현하지 않고 위탁류의 대상을 호출하는 관련 방법을 통해 특정한 서비스를 제공한다.
에이전트의 창설 시기에 따라 에이전트 종류는 두 가지로 나눌 수 있다.
• 정적 에이전트: 프로그래머가 만들거나 특정 도구가 자동으로 원본 코드를 생성하여 컴파일합니다.프로그램이 실행되기 전에 프록시 종류의.class 파일이 이미 존재합니다.
• 동적 에이전트: 프로그램이 실행될 때 자바 반사 메커니즘으로 바이트 코드를 동적으로 생성합니다.
2.1 정적 에이전트

public interface Count { 
  public void queryCount();
}
public class CountImpl implements Count {
  public void queryCount() { 
    System.out.println(" ...");
  }
}
// 
public class CountProxy implements Count { 
  private CountImpl countImpl;  
  public CountProxy(CountImpl countImpl) { 
    this.countImpl = countImpl; 
  }  
  @Override 
  public void queryCount() { 
    System.out.println(" ");      
    countImpl.queryCount(); //  ;
    System.out.println(" "); 
  }
} 
// 
public class TestCount { 
  public static void main(String[] args) { 
    CountImpl countImpl = new CountImpl(); 
    CountProxy countProxy = new CountProxy(countImpl); 
    countProxy.queryCount();  
  } 
}
코드를 관찰하면 모든 프록시 클래스가 하나의 인터페이스에만 서비스를 제공할 수 있다는 것을 알 수 있다. 그러면 프로그램 개발에서 반드시 너무 많은 프록시가 생길 것이다. 그리고 모든 프록시 조작은 호출하는 방법이 다른 것을 제외하고 다른 조작은 똑같다. 이때 틀림없이 중복 코드일 것이다.이 문제를 해결하는 가장 좋은 방법은 하나의 에이전트 클래스를 통해 모든 에이전트 기능을 완성할 수 있다는 것이다. 그러면 이때 반드시 동적 에이전트를 사용하여 완성해야 한다.
2.2 동적 에이전트
동적 프록시 클래스의 바이트 코드는 프로그램이 실행될 때 자바 반사 메커니즘에 의해 동적으로 생성되며, 프로그래머가 수동으로 원본 코드를 작성할 필요가 없다.동적 에이전트 클래스는 프로그래밍 작업을 간소화할 뿐만 아니라 소프트웨어 시스템의 확장성을 향상시켰다. 왜냐하면 자바 반사 메커니즘은 임의의 유형의 동적 에이전트 클래스를 생성할 수 있기 때문이다.
2.2.1 JDK 동적 에이전트
java.lang.reflect 패키지의 Proxy 클래스와 InvocationHandler 인터페이스는 동적 프록시 클래스를 생성하는 능력을 제공합니다.
InvocationHandler 인터페이스:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
매개변수 설명:
Object proxy: 프록시된 객체를 나타냅니다.
Method method: 호출할 방법
Object[]args: 메소드 호출 시 필요한 매개 변수
InvocationHandler 인터페이스의 하위 클래스를 에이전트의 최종 조작 클래스로 상상하여 ProxySubject를 교체할 수 있습니다.
Proxy 클래스:
Proxy 클래스는 에이전트를 전문적으로 완성하는 작업 클래스로 하나 이상의 인터페이스를 통해 동적으로 구현 클래스를 생성할 수 있으며 다음과 같은 조작 방법을 제공합니다.
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException
매개변수 설명:
ClassLoader loader: 클래스 로더
Class[] interfaces: 모든 인터페이스 얻기
InvocationHandler h: InvocationHandler 인터페이스의 하위 클래스 인스턴스 얻기
동적 에이전트를 완성하려면 먼저 에이전트의 구체적인 동작을 완성하기 위해 InvocationHandler 인터페이스의 하위 클래스를 정의해야 합니다.

interface Subject {
  public String say(String name, int age);
}
class RealSubject implements Subject {
  @Override
  public String say(String name, int age) {
    return name + " " + age;
  }
}
//JDK 
class MyInvocationHandler implements InvocationHandler {
  private Object target = null;
  // 
  public Object bind(Object target) {
    this. target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),
          target.getClass().getInterfaces(), this); // (cglib )
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println(“before method!”);
    Object temp = method.invoke(target, args);
    System.out.println(“after method!”);
    return temp;
  }
}
class hello {
  public static void main(String[] args) {
    MyInvocationHandler demo = new MyInvocationHandler();
    Subject sub = (Subject) demo.bind(new RealSubject());
    String info = sub.say("Rollen", 20);
    System.out.println(info);
  }
}
그러나 JDK의 동적 에이전트는 인터페이스에 의해 이루어진다. 만약에 어떤 종류가 인터페이스를 실현하지 못하면 JDK 에이전트를 사용할 수 없다. 그러면 cglib 동적 에이전트를 사용해야 한다. 
2.2.2 CGLIB 동적 에이전트
JDK의 동적 에이전트 메커니즘은 인터페이스의 클래스만 에이전트할 수 있고 인터페이스가 실현되지 않은 클래스는 JDK의 동적 에이전트를 실현할 수 없다.
cglib는 클래스를 대상으로 에이전트를 실현하는 것이다. 그 원리는 지정된 목표 클래스에 대해 하위 클래스를 생성하고 그 중에서 덮어쓰는 방법으로 강화를 실현하는 것이다. 그러나 계승이기 때문에final 수식된 클래스에 대해 에이전트를 할 수 없다.

public interface BookFacade { 
  public void addBook(); 
} 
public class BookFacadeImpl1 { 
  public void addBook() { 
    System.out.println(" ..."); 
  } 
} 
 
import java.lang.reflect.Method;  
import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 
//cglib 
public class BookFacadeCglib implements MethodInterceptor { 
  private Object target;  
  // 
  public Object getInstance(Object target) { 
    this.target = target; 
    Enhancer enhancer = new Enhancer(); 
    enhancer.setSuperclass(this.target.getClass()); 
    //   
    enhancer.setCallback(this); 
    //   
    return enhancer.create(); 
  }  
  @Override 
  //   
  public Object intercept(Object obj, Method method, Object[] args, 
      MethodProxy proxy) throws Throwable { 
    System.out.println(" "); 
    Object temp = proxy.invokeSuper(obj, args); 
    System.out.println(" "); 
    return temp;  
  } 
} 
public class TestCglib {
  public static void main(String[] args) { 
    BookFacadeCglib cglib = new BookFacadeCglib(); 
    BookFacadeImpl1 bookCglib = (BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); 
    bookCglib.addBook(); 
  } 
}
자바 반사와 에이전트가 여러분께 공유하는 모든 내용을 간단히 말씀드리겠습니다. 참고 부탁드리며 많은 응원 부탁드립니다.

좋은 웹페이지 즐겨찾기