为什么Spring的@Transactional无需代理即可工作?

时间:2018-09-01 18:20:30

标签: java spring hibernate jpa transactional

我对Spring的@Transactional在内部如何工作很感兴趣,但是到处都读到了代理的概念。代理应该代替真正的bean自动装配,并使用其他事务处理方法“装饰”基本方法。 该理论对我来说很清楚,很有意义,因此我尝试检查它如何起作用。 我创建了一个具有基本控制器和服务层的Spring Boot应用程序,并用@Transactional批注标记了一个方法。服务看起来像这样:

public class TestService implements ITestService {

@PersistenceContext
EntityManager entityManager;

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

控制器调用服务:

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);
}}

整个过程都可以正常工作,新实体仍保留在数据库中,但是我最关心的是输出:

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

似乎服务类是显式注入的,而不是代理类。不仅“ isProxy”返回false,而且类输出(“ com.example.demo.TestService@7fb48179”)也表明它不是代理。

您能帮我吗?为什么不注入代理,没有代理它如何工作?有什么办法可以“强制”将其代理,如果是的话-为什么默认情况下Spring不注入代理?

没有什么可添加的,这是一个非常简单的应用程序。应用程序属性也不是很花哨:

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

提前谢谢!

1 个答案:

答案 0 :(得分:6)

您的理解是正确的,但是您的测试存在缺陷:

当spring文档说“ proxy”时,他们指的是模式,而不是特定的实现。 Spring支持各种创建代理对象的策略。其中之一是您测试过的java.lang.reflect.Proxy,但默认情况下,spring使用了一种更高级的技术,该技术在运行时生成新的类定义,该类将服务的实际实现类子类化(并覆盖所有方法以应用事务建议) 。您可以通过检查testService.getClass()(它会引用该生成的类),或通过在调试器中停止执行,并检查targetService的字段,来查看实际情况。

toString()引用原始对象的原因是,代理通过委派给目标对象来实现toString(),目标对象使用其类名来构建String

相关问题