9

Recently i found spring documentation page that says:

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).

If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used.

But it doesn't seem to be the case in my application. I wanted to write a small benchmark to compare the performance of both types of proxying.

There are two similar classes. Both have one method annotated with the @Transactional annotation. One class implements the interface and the other does not:

@Service public class Cglib { @Transactional public void method() {} } 
public interface Dynamic { void method(); } 
@Service public class DynamicImpl implements Dynamic { @Override @Transactional public void method() {} } 

And based on the documentation for the first class, a CGLIB proxy should be created, and for the second, a JDK dynamic proxy.

But in my case CGLIB was used for both classes:

@Component @RequiredArgsConstructor public class Runner implements ApplicationRunner { private final Cglib cglib; private final Dynamic dynamic; @Override public void run(ApplicationArguments args) { System.out.println(cglib.getClass()); System.out.println(dynamic.getClass()); } } 
class com.example.demo.proxy.cglib.Cglib$$EnhancerBySpringCGLIB$$767ff22 class com.example.demo.proxy.dynamic.DynamicImpl$$EnhancerBySpringCGLIB$$20a564d6 

There are no additional configurations in the application. Only @SpringBootApplication class generated via spring initializr

Am I doing something wrong? The code was run on Spring Boot 2.7.2 and JDK 17.

1
  • 2
    The documentation is for plain Spring not for Spring Boot. The latter automatically forces/enables always class based proxies. Commented Aug 4, 2022 at 6:46

1 Answer 1

11

That is due to spring-boot autoconfiguation:

@Configuration(proxyBeanMethods = false) @ConditionalOnBean(TransactionManager.class) @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class) public static class EnableTransactionManagementConfiguration { @Configuration(proxyBeanMethods = false) @EnableTransactionManagement(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false") public static class JdkDynamicAutoProxyConfiguration { } @Configuration(proxyBeanMethods = false) @EnableTransactionManagement(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) public static class CglibAutoProxyConfiguration { } } 

it turns @EnableTransactionManagement(proxyTargetClass = true) (Indicate whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false)) on when the configuration property spring.aop.proxy-target-class is not set (matchIfMissing = true)

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, it looks like the spring boot configuration includes this behavior. Found a github issue that describes the reason for such a solution. It would be great to know how to turn it off.
@vszholobov in general specifying spring.aop.proxy-target-class=false or disabling TransactionAutoConfiguration autoconfiguration and writing own configuration should help, however there are some related discussions on that topic: github.com/spring-projects/spring-boot/issues/12194
Specifying spring.aop.proxy-target-class=false solved the problem. Now the JDK dynamic proxy is used for the second class

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.