【问题标题】:Spring CGLIB proxies intercept only public method callsSpring CGLIB 代理仅拦截公共方法调用
【发布时间】:2018-12-11 05:08:43
【问题描述】:

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 库(没有 spring,使用 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

这意味着,如果 spring 在我的行为中创建代理 - 如在 TransactionInterceptor 中 - 仅为公共方法创建 CGLIB 代理。

更新2

我想我发现了这种接受公共方法的行为只发生在哪里。 它发生在 PointCut (TransactionAttributeSourcePointcut) 使用的 AnnotationTransactionAttributeSource

来自代码:

/**
 * 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) {

【问题讨论】:

    标签: java spring cglib


    【解决方案1】:

    可能的答案是因为基于 Java 的代理不能与 package-private 方法一起使用(因为 Java 实现类不能为接口实现的方法分配较弱的访问权限)。

    因此,即使 CGLib 可以代理它们,这也可能会阻止 Spring 团队对包私有方法进行操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-11
      相关资源
      最近更新 更多