program tip

동적 프록시 클래스는 무엇이며 왜 사용합니까?

radiobox 2020. 11. 12. 08:04
반응형

동적 프록시 클래스는 무엇이며 왜 사용합니까?


동적 프록시를 사용하는 사용 사례는 무엇입니까?

바이트 코드 생성 및 반영과 어떤 관련이 있습니까?

추천하는 책이 있습니까?


리소스를 적극 권장 합니다 .

먼저 프록시 패턴 사용 사례를 이해해야합니다. 프록시의 주요 목적은 대상 개체의 기능을 향상시키는 것이 아니라 대상 개체에 대한 액세스를 제어하는 ​​것입니다. 액세스 제어에는 동기화, 인증, 원격 액세스 (RPC), 지연 인스턴스화 (Hibernate, Mybatis), AOP (트랜잭션)가 포함됩니다.

정적 프록시와 달리 동적 프록시는 런타임에 Java 리플렉션이 필요한 바이트 코드를 생성합니다. 동적 접근 방식을 사용하면 프록시 클래스를 만들 필요가 없으므로 더 편리합니다.


동적 프록시 클래스 의 클래스 인 것을 구현하는 클래스의 인스턴스의 인터페이스 중 하나를 통해 메소드 호출 부호화와 동일한 인터페이스를 통해 다른 객체에 전달되도록 실행 예에서 지정된 인터페이스 목록. 프록시 클래스를 사전 생성하지 않고도 인터페이스 목록에 대한 형식이 안전한 프록시 개체를 만드는 데 사용할 수 있습니다. 동적 프록시 클래스는 인터페이스 API를 제공하는 객체에 대한 유형이 안전한 반사 호출 호출을 제공해야하는 애플리케이션 또는 라이브러리에 유용합니다.

동적 프록시 클래스


방금 동적 프록시에 대한 흥미로운 용도를 생각해 냈습니다.

다른 종속 서비스와 결합 된 중요하지 않은 서비스에 문제가 발생했으며 해당 종속 서비스를 사용할 수 없게되었을 때 내결함성이있는 방법을 모색하고 싶었습니다.

그래서 두 대리자를 받는 LoadSheddingProxy작성했습니다. 하나는 '일반'서비스 (JNDI 조회 후)를위한 원격 impl입니다. 다른 개체는 '더미'부하 차단 impl입니다. 시간 초과를 포착하고 재 시도하기 전에 특정 시간 동안 더미로 전환하는 각 메서드 호출을 둘러싼 간단한 논리가 있습니다. 사용 방법은 다음과 같습니다.

// This is part of your ServiceLocator class
public static MyServiceInterface getMyService() throws Exception
{
    MyServiceInterface loadShedder = new MyServiceInterface() {
        public Thingy[] getThingys(Stuff[] whatever) throws Exception {
            return new Thingy[0];
        }
        //... etc - basically a dummy version of your service goes here
    }           
    Context ctx = JndiUtil.getJNDIContext(MY_CLUSTER);
    try {
        MyServiceInterface impl = ((MyServiceHome) PortableRemoteObject.narrow(
                ctx.lookup(MyServiceHome.JNDI_NAME), 
                MyServiceHome.class)).create();
        // Here's where the proxy comes in
        return (MyService) Proxy.newProxyInstance(
            MyServiceHome.class.getClassLoader(),
        new Class[] { MyServiceInterface.class },
        new LoadSheddingProxy(MyServiceHome.JNDI_NAME, impl, loadShedder, 60000));  // 10 minute retry
    } catch (RemoteException e) {    // If we can't even look up the service we can fail by shedding load too
        logger.warn("Shedding load");
        return loadShedder;
    } finally {
        if (ctx != null) {
        ctx.close();
        }
    }
}

그리고 여기에 프록시가 있습니다.

public class LoadSheddingProxy implements InvocationHandler {

static final Logger logger = ApplicationLogger.getLogger(LoadSheddingProxy.class);

Object primaryImpl, loadDumpingImpl;
long retry;
String serviceName;
// map is static because we may have many instances of a proxy around repeatedly looked-up remote objects
static final Map<String, Long> servicesLastTimedOut = new HashMap<String, Long>();

public LoadSheddingProxy(String serviceName, Object primaryImpl, Object loadDumpingImpl, long retry)
{
    this.serviceName = serviceName;
    this.primaryImpl = primaryImpl;
    this.loadDumpingImpl = loadDumpingImpl;
    this.retry = retry;
}

public Object invoke(Object obj, Method m, Object[] args) throws Throwable
{
    try
    {
        if (!servicesLastTimedOut.containsKey(serviceName) || timeToRetry()) {
            Object ret = m.invoke(primaryImpl, args);
            servicesLastTimedOut.remove(serviceName);
            return ret;
        } 
        return m.invoke(loadDumpingImpl, args);
    }
    catch (InvocationTargetException e)
    {
        Throwable targetException = e.getTargetException();

        // DETECT TIMEOUT HERE SOMEHOW - not sure this is the way to do it???
        if (targetException instanceof RemoteException) {
            servicesLastTimedOut.put(serviceName, Long.valueOf(System.currentTimeMillis()));
        }
        throw targetException;
    }                    
}

private boolean timeToRetry() {
    long lastFailedAt = servicesLastTimedOut.get(serviceName).longValue();
    return (System.currentTimeMillis() - lastFailedAt) > retry;
}
}

이 클래스를 java.lang.reflect.Proxy사용하면 .NET Framework에서 메서드 호출을 처리하여 인터페이스를 동적으로 구현할 수 있습니다 InvocationHandler. Java의 리플렉션 기능의 일부로 간주되지만 바이트 코드 생성과는 관련이 없습니다.

Sun has a tutorial about the use of the Proxy class. Google helps, too.


One use case is hibernate - it gives you objects implementing your model classes interface but under getters and setters there resides db related code. I.e. you use them as if they are just simple POJO, but actually there is much going on under cover.

For example - you just call a getter of lazily loaded property, but really the property (probably whole big object structure) gets fetched from the database.

You should check cglib library for more info.

참고URL : https://stackoverflow.com/questions/933993/what-are-dynamic-proxy-classes-and-why-would-i-use-one

반응형