【发布时间】:2018-12-11 05:08:43
【问题描述】:
Spring 文档指出:
CGLIB 代理只拦截公共方法调用!不要打电话 这种代理上的非公共方法。他们没有被委派给 实际作用域的目标对象。
但经过观察,我认为要么我的实验(下面的代码)不好,要么这种行为随着时间而改变。
我观察到只有最终或私有方法被绕过。
这里是实验:(春季版: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) {
【问题讨论】: