简体   繁体   English

为什么Spring的@Transactional在没有代理的情况下工作?

[英]Why Spring's @Transactional works without proxy?

I got interested in how Spring's @Transactional works internally, but everywhere I read about it there's a concept of proxy. 我对Spring的@Transactional如何在内部工作感兴趣,但在我读到它的每个地方都有一个代理概念。 Proxies are supposed to be autowired in place of real bean and "decorate" base method with additional transaction handling methods. 代理应该是自动装配代替真正的bean,并使用额外的事务处理方法“装饰”基本方法。 The theory is quite clear to me and makes perfect sense so I tried to check how it works in action. 这个理论对我来说非常清楚,并且非常有意义,因此我尝试检查它的运作方式。 I created a Spring Boot application with a basic controller and service layers and marked one method with @Transactional annotation. 我创建了一个带有基本控制器和服务层的Spring Boot应用程序,并使用@Transactional注释标记了一个方法。 Service looks like this: 服务看起来像这样:

public class TestService implements ITestService {

@PersistenceContext
EntityManager entityManager;

@Transactional
public void doSomething() {
    System.out.println("Service...");
    entityManager.persist(new TestEntity("XYZ"));
}}

Controller calls the service: 控制器调用服务:

public class TestController {

@Autowired
ITestService testService;

@PostMapping("/doSomething")
public ResponseEntity addHero() {
    testService.doSomething();
    System.out.println(Proxy.isProxyClass(testService.getClass()));
    System.out.println(testService);
    return new ResponseEntity(HttpStatus.OK);
}}

The whole thing works, new entity is persisted to the DB but the whole point of my concern is the output: 整个过程都有效,新实体会持久保存到DB,但我关注的重点是输出:

Service...
false
com.example.demo.TestService@7fb48179

It seems that the service class was injected explicitly instead of proxy class. 似乎服务类是显式注入而不是代理类。 Not only "isProxy" returns false, but also the class output ("com.example.demo.TestService@7fb48179") suggests its not a proxy. 不仅“isProxy”返回false,而且类输出(“com.example.demo.TestService@7fb48179”)表明它不是代理。

Could you please help me out with that? 你可以帮帮我吗? Why wasn't the proxy injected, and how does it even work without proxy? 为什么不注入代理,如果没有代理,它甚至如何工作? Is there any way I can "force" it to be proxied, and if so - why the proxy is not injected by default by Spring ? 有什么方法可以“强迫”它被代理,如果是这样 - 为什么Spring没有默认注入代理?

There's not much to be added, this is a really simple app. 没有太多要添加,这是一个非常简单的应用程序。 Application properties are nothing fancy either : 应用程序属性也不花哨:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=superSecretPassword
spring.datasource.url=jdbc:mysql://localhost:3306/heroes?serverTimezone=UTC
spring.jpa.hibernate.ddl-auto=create-drop

Thank you in advance! 先感谢您!

Your understanding is correct, but your test is flawed: 您的理解是正确的,但您的测试存在缺陷:

When the spring docs say "proxy", they are referring to the pattern, not a particular implementation. 当spring文档说“代理”时,它们指的是模式,而不是特定的实现。 Spring supports various strategies for creating proxy objects. Spring支持各种创建代理对象的策略。 One of these is the java.lang.reflect.Proxy you tested for, but by default spring uses a more advanced technique that generates a new class definition at runtime that subclasses the actual implementation class of the service (and overrides all methods to apply transaction advice). 其中一个是你测试过的java.lang.reflect.Proxy ,但是默认情况下spring使用了一种更高级的技术,它在运行时生成一个新的类定义,它定义了服务的实际实现类(并覆盖所有应用事务的方法)咨询)。 You can see this in action by checking testService.getClass() , which will refer to that generated class, or by halting execution in a debugger, and inspecting the fields of targetService . 您可以通过检查testService.getClass()来查看此操作,它将引用该生成的类,或者在调试器中暂停执行,并检查targetService的字段。

The reason that toString() refers to the original object is that the proxy implements toString() by delegating to its target object, which uses its class name to build the String . toString()引用原始对象的原因是代理通过委托其目标对象来实现toString() ,目标对象使用其类名来构建String

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM