我对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
提前谢谢!
答案 0 :(得分:6)
您的理解是正确的,但是您的测试存在缺陷:
当spring文档说“ proxy”时,他们指的是模式,而不是特定的实现。 Spring支持各种创建代理对象的策略。其中之一是您测试过的java.lang.reflect.Proxy
,但默认情况下,spring使用了一种更高级的技术,该技术在运行时生成新的类定义,该类将服务的实际实现类子类化(并覆盖所有方法以应用事务建议) 。您可以通过检查testService.getClass()
(它会引用该生成的类),或通过在调试器中停止执行,并检查targetService
的字段,来查看实际情况。
toString()
引用原始对象的原因是,代理通过委派给目标对象来实现toString()
,目标对象使用其类名来构建String
。