programing

인터페이스 또는 TARGET_CLASS: 어떤 프록시 모드를 선택해야 합니까?

codeshow 2023. 8. 15. 11:49
반응형

인터페이스 또는 TARGET_CLASS: 어떤 프록시 모드를 선택해야 합니까?

저는 제 물건을 저장하는 방법을 찾고 있는데 프록시를 사용하는 것이 가장 좋은 방법인 것 같습니다.인터넷에서 주석 두 개를 찾았는데 어떤 것을 사용해야 합니까?

@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)

또는

@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )

를 사용하는 보다 프록시를 이 가장 좋은 방법이라는 것이 사실입니까?@Component @Scope("session") 는사용을 사용합니다.@SessionAttributes?

각 주석이 직접 선택하기 위해 수행하는 작업을 이해해야 합니다.여기 자바독을 보세요.계속해서 자세한 설명을 참조하십시오.

첫번째

@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)

생성

대상 개체의 클래스에 의해 노출된 모든 인터페이스를 구현하는 JDK 동적 프록시

즉, 프록시는 대상 개체의 클래스가 구현하는 인터페이스의 하위 유형이지만 대상 개체의 클래스 자체의 하위 클래스는 아닙니다.

근본적으로 봄은 다음과 같은 일을 합니다.

public class Example {
    public static void main(String[] args) throws Exception {
        Foo target = new Foo();
        InvocationHandler proxyHandler = ... // some proxy specific logic, likely referencing the `target`

        // works fine
        Printable proxy = (Printable) Proxy.newProxyInstance(Example.class.getClassLoader(),
                target.getClass().getInterfaces(), proxyHandler);

        // not possible, ClassCastException
        Foo foo = (Foo) proxy; 
    }

    public static class Foo implements Printable {
        @Override
        public void print() {
        }
    }

    public interface Printable {
        void print();
    }
}

반된프록유아닙다니형이가 아닙니다.Foo따라서 그런 종류의 표적에는 주입할 수 없습니다.예를 들어, 스프링은 다음과 같은 필드에 주입하지 못합니다.

@Autowired
private Foo foo;

하지만 성공적으로 프록시를 같은 분야에 주입할 것입니다.

@Autowired
private Printable printable;

는 프시대호은에 됩니다.InvocationHandler(일반적으로 사용 사례별 논리를 수행한 다음 대상 개체에 위임).


두 번째 주석

@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )

생성

클래스 기반 프록시(CGLIB 사용).

인터페이스 외에도 CGLIB Spring을 사용하여 클래스가 대상 클래스의 하위 클래스인 프록시를 만들 수 있습니다.본질적으로, 다음과 같은 일을 합니다.

Foo target = new Foo();
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setInterfaces(target.getClass().getInterfaces());
enhancer.setSuperclass(target.getClass());
net.sf.cglib.proxy.MethodInterceptor interceptor = ... // some proxy specific logic, likely referencing the `target`
enhancer.setCallback(interceptor);

// works fine
Foo proxy = (Foo) enhancer.create();

는 CGLIB의 를 만듭니다.Foo인스턴스화합니다(" ▁ofor▁and(▁the포"의 생성자를 의미함).Foo프록시에 대한 모든 호출은 제공된 콜백(일반적으로 일부 사용 사례별 논리를 수행한 다음 대상 개체로 위임)에 의해 가로채게 됩니다.

가 확장되었기 Foo스프링은 프록시를 다음과 같은 필드(또는 생성자/메소드 매개 변수)에 주입할 수 있습니다.

@Autowired
private Foo injectMe;

이 모든 것을 말하자면, 만약 당신이 인터페이스로 프로그래밍하고 있다면,ScopedProxyMode.INTERFACES충분할 것입니다.그렇지 않은 경우 다음을 사용합니다.ScopedProxyMode.TARGET_CLASS.


사용에 관해서는 세션 범위 콩의 대안이 아닙니다.세션 속성은 객체일 뿐 빈이 아닙니다.그들은 콩이 가질 수 있는 완전한 라이프사이클, 주사 기능, 대리 행동을 가지고 있지 않습니다.

전체 빈을 세션에 저장하려면 @Scope를 사용하고, 그렇지 않으면 @SessionAttributes를 사용합니다.@Scope를 사용하는 경우 클래스가 일부 인터페이스를 구현하는 경우 TARGET_CLASS를 사용하지 않는 경우 INTERFACS 프록시 모드를 사용합니다.

일반적으로 서비스는 JDK 프록시(인터페이스 모드)를 사용할 수 있는 인터페이스를 구현합니다.그러나 그렇지 않은 경우에는 CGLIB 프록시를 만드는 TARGET_CLASS를 사용합니다.

가능하면 INTERFACE를 사용하고 빈이 인터페이스를 구현하지 않을 경우 TARGET을 최후의 수단으로 사용해야 합니다.

위 댓글에 제공된 블로그 게시물을 보다가 인터페이스 기반 프록시의 단점을 지적하는 댓글을 발견했습니다.

사용자 Flemming Jønsson은 게시물에 다음과 같이 게시했습니다.

인터페이스 기반 프록시 사용에 주의하십시오.

Spring Security 또는 Spring Transactions를 사용하는 경우 인터페이스 기반 프록시를 사용할 때 이상한 현상이 발생할 수 있습니다.

예를 들어, 빈 T가 있고 해당 빈에 주석이 달린 트랜잭션 메소드 a()와 b()가 있는 경우.다른 콩에서 직접 a() 또는 b()로 호출하면 구성된 대로 올바르게 작동합니다.그러나 a()가 b()를 호출하는 내부 통화를 도입하면 b의 트랜잭션 메타데이터는 영향을 받지 않습니다.그 이유는 인터페이스 기반 프록시를 사용할 때 내부 통화가 프록시를 통과하지 않으므로 트랜잭션 가로채기가 새 트랜잭션을 시작할 기회가 없기 때문입니다.

보안도 마찬가지입니다.메서드 a()에 USER 역할만 필요하지만 ADMIN 역할이 필요한 b()를 호출하는 경우 a에서 b로의 내부 호출이 경고 없이 모든 USER에 대해 수행됩니다.위와 동일한 이유로 내부 통화는 프록시를 통과하지 않으므로 보안 인터셉터는 a()에서 b()로 거는 통화에 대해 조치를 취할 기회가 없습니다.

이러한 문제를 해결하려면 targetClass를 사용합니다.

언급URL : https://stackoverflow.com/questions/21759684/interfaces-or-target-class-which-proxymode-should-i-choose

반응형