Spring CGLIB прокси перехватывает только публичные вызовы методов - PullRequest
0 голосов
/ 11 декабря 2018

В документации Spring говорится, что:

CGLIB-прокси перехватывает только публичные вызовы методов!Не вызывайте непубличные методы на таком прокси.Они не делегируются фактическому целевому объекту с областью действия.

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-other

Но после наблюдения я думаю, что либо мой эксперимент (код ниже) не подходит, либо это поведение изменилосьсо временем.

Я заметил, что обходятся только финальные или частные методы.

Вот эксперимент: (весенняя версия: 5.1.3)

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

@Autowired
private StudentService studentService;

public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
}

@Bean
StudentService studentService() {
    ProxyFactory proxyFactory = new ProxyFactory(new StudentService());
    proxyFactory.setProxyTargetClass(true);
    proxyFactory.addAdvice(new MethodInterceptor() {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("method " + invocation.getMethod() + " is called on " +
                    invocation.getThis() + " with args " + invocation.getArguments());
            Object ret = invocation.proceed();
            System.out.println("method " + invocation.getMethod() + " returns " + ret);
            return ret;
        }
    });
    return (StudentService) proxyFactory.getProxy();
}

@Override
public void run(String... args) throws Exception {
    studentService.doIt();
}

class StudentService {

    void doIt() {
        System.out.println("doIt");
    }
}

Вывод:

method void com.example.demo.DemoApplication$StudentService.doIt() is called on com.example.demo.DemoApplication$StudentService@127a7a2e with args [Ljava.lang.Object;@14008db3
doIt
method void com.example.demo.DemoApplication$StudentService.doIt() returns null

Также - экспериментально - CGLIB библиотека (без пружины, используя класс Enhancer) также позволяет использовать методы уровня пакета для проксирования.

ОБНОВЛЕНИЕ

У меня есть еще одно замечание (противоположное вышеприведенному).В типичном приложении jdbc:

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private ExampleService exampleService;
    @Autowired
    private XExampleService xExampleService;
    @Autowired
    private XXExampleService xxExampleService;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(exampleService.getClass());
        System.out.println(xExampleService.getClass());
        System.out.println(xxExampleService.getClass());
    }


    @Service
    class ExampleService {

        void tranx() {

        }
    }

    @Service
    class XExampleService {

        @org.springframework.transaction.annotation.Transactional
        void tranx() {

        }
    }

    @Service
    class XXExampleService {

        @Transactional
        public void tranx() {

        }
    }
}

Вывод:

class com.example.demo.DemoApplication$ExampleService
class com.example.demo.DemoApplication$XExampleService
class com.example.demo.DemoApplication$XXExampleService$$EnhancerBySpringCGLIB$$2b1603e8

Что означает, что в случае пружинного создания прокси в моем поведении - как в TransactionInterceptor -Прокси-сервер CGLIB создан только для общедоступного метода.

UPDATE2

Мне кажется, я обнаружил, что происходит только такое поведение метода accept public.Это происходит в AnnotationTransactionAttributeSource, который используется PointCut (TransactionAttributeSourcePointcut).

Из кода:

/**
 * Create a custom AnnotationTransactionAttributeSource, supporting
 * public methods that carry the {@code Transactional} annotation
 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
 * @param publicMethodsOnly whether to support public methods that carry
 * the {@code Transactional} annotation only (typically for use
 * with proxy-based AOP), or protected/private methods as well
 * (typically used with AspectJ class weaving)
 */
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {

1 Ответ

0 голосов
/ 11 декабря 2018

Возможный ответ: поскольку прокси на основе Java не могут работать с методами package-private (поскольку классы реализации Java не могут назначать более слабые права доступа для методов, реализуемых интерфейсом).

Так что это может помешать команде Spring работать назакрытые для пакета методы, даже если CGLib может использовать их по доверенности.

...