Java 동적 에이전트(JDK 인터페이스 에이전트 및 Cglib 클래스 에이전트)

8122 단어
프록시 모드
프록시 모델은 자주 사용하는 자바 디자인 모델로 프록시 클래스와 위탁 클래스가 같은 인터페이스를 가진 것이 특징이다. 프록시 클래스는 주로 위탁 클래스의 사전 처리 메시지, 메시지 필터, 정보를 위탁 클래스에 전달하고 사후 처리 메시지 등을 책임진다.대리류와 위탁류 사이에는 일반적으로 관련 관계가 존재한다. 하나의 대리류의 대상은 하나의 위탁류의 대상과 관련된다. 대리류의 대상 자체는 진정으로 서비스를 실현하지 않고 위탁류의 대상과 관련된 방법을 호출하여 특정한 서비스를 제공한다. 
대리의 창설 시기에 따라 대리류는 두 가지로 나눌 수 있다. 
정적 에이전트: 프로그래머가 만들거나 특정 도구가 자동으로 원본 코드를 생성하고 컴파일합니다.프로그램이 실행되기 전에 프록시 클래스의.class 파일이 이미 존재합니다. 
동적 에이전트: 프로그램이 실행될 때 반사 메커니즘을 이용하여 동적으로 만들어집니다. 
정적 에이전트:
BookInterface.java
public interface BookInterface
{
    /**
     *  
     * Description: <br> 
     * @see
     */
    void addBook();
}

BookImpl.java
public class BookImpl implements BookInterface
{

    @Override
    public void addBook()
    {
        System.out.println("stati@BookImpll#addBook");
    }

}

BookProxy.java
/**
 *       
 * @author lyh
 * @version 2013-4-16
 * @see BookProxy
 * @since
 */
public class BookProxy implements BookInterface
{

    private BookImpl bookImpl;
    
    /**
     *  
     * @param bookImpl
     */
    public BookProxy(BookImpl bookImpl)
    {
        this.bookImpl = bookImpl;
    }
    
    @Override
    public void addBook()
    {
        System.out.println("Before Advice");
        
        bookImpl.addBook();
        
        System.out.println("After Advice");
    }

}

Will.java
/**
 *  
 * @author lyh
 * @version 2013-4-16
 * @see Will
 * @since
 */
public class Will
{

    /**
     * Description: <br>
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        BookImpl impl=  new BookImpl();
        
        BookProxy proxy = new BookProxy(impl);
        
        // 
        proxy.addBook();
    }

}

코드를 관찰하면 모든 프록시 클래스가 하나의 인터페이스에만 서비스를 제공할 수 있다는 것을 알 수 있다. 그러면 프로그램 개발에서 반드시 너무 많은 프록시가 생길 것이다. 그리고 모든 프록시 조작은 호출하는 방법이 다른 것을 제외하고 다른 조작이 똑같다. 그러면 이때는 틀림없이 중복 코드이다.이 문제를 해결하는 가장 좋은 방법은 하나의 에이전트 클래스를 통해 모든 에이전트 기능을 완성할 수 있다는 것이다. 그러면 이때 반드시 동적 에이전트를 사용해야 한다.다시 한 번 동적 에이전트를 보십시오: JDK 동적 에이전트에는 클래스와 인터페이스가 포함되어 있습니다 (구체적으로는 API 매뉴얼 참조): InvocationHandler 인터페이스 (이 인터페이스에 대한 설명이 명확한 문장을 추천합니다.http://www.cnblogs.com/yixiwenwen/archive/2012/11/14/2770068.html):  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 new Proxy Instance(ClassLoader loader, Class [] interfaces, Invocation Handler h) throws Illegal Argument Exception 매개 변수 설명: ClassLoader loader: 클래스 로더 Class[] interfaces: 모든 인터페이스 가져오기 InvocationHandler h: InvocationHandler 인터페이스의 하위 클래스 가져오기
Ps: 클래스 로더는Proxy 클래스의 new Proxy Instance () 방법에서 클래스 로더 클래스의 실례가 필요합니다. 클래스 로더는 실제적으로 클래스 로더에 대응하고 자바에는 주로 세 종류의 로더가 있습니다.Booststtrap ClassLoader: 이 마운트는 C++로 작성되어 일반 개발에서는 볼 수 없습니다.Extendsion ClassLoader: 확장 클래스를 불러오는 데 사용되며, 일반적으로 jre\lib\ext 디렉터리의 클래스에 대응합니다.AppClassLoader: (기본값) classpath가 지정한 클래스를 불러옵니다. 가장 자주 사용하는 것은 마운트기입니다. 
동적 프록시와 정적 프록시 클래스가 대조되는 것은 동적 프록시 클래스입니다. 동적 프록시 클래스의 바이트 코드는 프로그램이 실행될 때 자바 반사 메커니즘에 의해 동적으로 생성되며, 프로그램이 직접 원본 코드를 작성할 필요가 없습니다.동적 프록시 클래스는 프로그래밍 작업을 간소화할 뿐만 아니라 소프트웨어 시스템의 확장성을 향상시켰다. 왜냐하면 자바 반사 메커니즘은 임의의 유형의 동적 프록시 클래스를 생성할 수 있기 때문이다.java.lang.reflect 패키지의 Proxy 클래스와 InvocationHandler 인터페이스는 동적 프록시 클래스를 생성하는 능력을 제공합니다. 
JDK 동적 인터페이스 에이전트:
BookInterface.java
public interface BookInterface
{
    /**
     *  
     * Description: <br> 
     * @see
     */
    void addBook();
    
    /**
     *  
     * Description: <br> 
     * @see
     */
    void intercept();
}

BookImpl.java
public class BookImpl implements BookInterface
{


    @Override
    public void addBook()
    {
        System.out.println("dynamic@BookImpl#addBook");
    }
    
    @Override
    public void intercept()
    {
        System.out.println("dynamic@BookImpl#intercept is intercepted...");
    }


}

BookProxy.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


/**
 * JDK      
 * @author lyh
 * @version 2013-4-16
 * @see BookProxy
 * @since
 */
public class BookProxy implements InvocationHandler
{
    /**
     *  
     */
    private Object target;

    public Object getInstance(Object target)
    {
        this.target = target;
        
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
            target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object obj, Method method, Object[] args)
        throws Throwable
    {
        System.out.println("Before Advice");
        
        if("intercept".equals(method.getName()))
        {
            System.out.println("intercept method is intercepted");
            
            return null;
        }
        
        // target  obj
        Object  result = method.invoke(target, args);
        
        System.out.println("After Advice");
        
        return result;
    }

}

Will.java
/**
 *   
 * @author lyh
 * @version 2013-4-16
 * @see Will
 * @since
 */
public class Will
{

    /**
     * Description: <br>
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        BookProxy proxy = new BookProxy();
        BookInterface impl = (BookInterface)proxy.getInstance(new BookImpl());
        
        //impl.addBook();
        impl.intercept();
    }
}

그러나 JDK의 동적 에이전트는 인터페이스에 의해 이루어진다. 만약에 일부 종류가 인터페이스를 실현하지 못하면 JDK 에이전트를 사용할 수 없다. 그러면 cglib 동적 에이전트를 사용해야 한다. 
Cglib 동적 에이전트 JDK의 동적 에이전트 메커니즘은 인터페이스의 클래스만 에이전트할 수 있고 인터페이스를 실현하지 못하는 클래스는 JDK의 동적 에이전트를 실현할 수 없다. cglib은 클래스를 대상으로 에이전트를 실현하는 것이다. 그의 원리는 지정된 목표 클래스에 대해 하위 클래스를 생성하고 그 중국법을 덮어 증강시키는 것이다. 그러나 계승을 사용하기 때문에final 수식의 클래스를 에이전트할 수 없다.Cglib 동적 클래스 에이전트:
BookClass.java
public class BookClass
{
    /**
     *    cglib 
     * Description: <br> 
     * @see
     */
    public void addBook()
    {
        System.out.println("cglib@BookClass#addBook");
    }
}

BookProxy.java
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 lyh
 * @version 2013-4-16
 * @see BookProxy
 * @since
 */
public class BookProxy implements MethodInterceptor
{
    /**
     *  
     */
    private Object target;
    
    public Object getInstance(Object target)
    {
        this.target = target;
        
        Enhancer en = new Enhancer();
        
        en.setSuperclass(target.getClass());
        
        en.setCallback(this);
        
        return en.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
        throws Throwable
    {
        System.out.println("Before Advice");
        
        // target  obj
        Object result = proxy.invoke(target, args);
        
        System.out.println("After Advice");
        
        return result;
    }

}

Will.java
/**
 *  
 * @author lyh
 * @version 2013-4-16
 * @see Will
 * @since
 */
public class Will
{

    /**
     * Description: <br>
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        BookProxy proxy = new BookProxy();
        
        BookClass bc = (BookClass)proxy.getInstance(new BookClass());
        
        bc.addBook();
    }

}

좋은 웹페이지 즐겨찾기