Spring AOP self-invocation及其他问题汇总

spring reference中描述:

. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.

……

Finally, it must be noted that AspectJ does not have this self-invocation issue because it is not a proxybased AOP framework.

……

Method visibility and cache annotations
When using proxies, you should apply the cache annotations only to methods with public visibility. If you do annotate protected, private or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit the configured caching settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods as it changes the bytecode itself.

Tip
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Cache* annotation, as opposed to annotating interfaces. You certainly can place the @Cache* annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-targetclass="true") or the weaving-based aspect ( mode="aspectj"), then the caching settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a caching proxy, which would be decidedly bad.
Note
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.


Method visibility and @Transactional
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

You can place the @Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class. However, the mere presence of the @Transactional annotation is not enough to activate the transactional behavior. The @Transactional annotation is simply metadata that can be consumed by some runtime infrastructure that is @Transactional-aware and that can use the metadata to configure the appropriate beans with transactional behavior. In the preceding example, the <tx:annotation-driven/> element switches on the transactional behavior.
Tip
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-target-class="true") or the weaving-based aspect ( mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.
Note
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.
Consider the use of AspectJ mode (see mode attribute in table below) if you expect self-invocations to be wrapped with transactions as well. In this case, there will not be a proxy in the first place; instead, the target class will be weaved (that is, its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

### 关于 Spring Adapter 的使用方法和常见问题 #### 什么是 Spring Adapter? Spring Adapter 是 Spring 框架中的一个重要概念,它主要用于适配不同的技术或框架到 Spring 生态系统中。Adapter 设计模式的核心思想是让不兼容的类能够协同工作[^4]。 --- #### 如何使用 Spring Adapter? 1. **HTTP 请求适配器 (WebClient 和 RestTemplate)** Spring 提供了 `RestTemplate` 和更现代的 `WebClient` 来处理 HTTP 请求。这些工具可以通过自定义配置来适应不同场景的需求。 ```java import org.springframework.web.client.RestTemplate; public class HttpClientExample { private final RestTemplate restTemplate = new RestTemplate(); public String fetchData(String url) { return restTemplate.getForObject(url, String.class); } } ``` 如果需要切换到响应式编程模型,则可以使用 WebClient: ```java import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; public class ReactiveHttpClientExample { private final WebClient webClient = WebClient.create(); public Mono<String> fetchData(String url) { return webClient.get() .uri(url) .retrieve() .bodyToMono(String.class); } } ``` 2. **消息队列适配器 (RabbitMQ、Kafka 等)** Spring 提供了多种消息中间件的支持,比如 RabbitMQ 和 Kafka。通过引入相应的 Starter 依赖并编写简单的配置即可完成集成。 对于 RabbitMQ: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> ``` 配置文件示例: ```yaml spring: rabbitmq: host: localhost port: 5672 username: guest password: guest ``` 3. **数据库访问适配器 (JdbcTemplate、Hibernate)** 数据库操作也是 Spring Adapter 的重要应用场景之一。例如,`JdbcTemplate` 可以简化 JDBC 的复杂度;而 Hibernate 则提供了 ORM 支持。 使用 JdbcTemplate 查询数据: ```java import org.springframework.jdbc.core.JdbcTemplate; public class DatabaseAccessExample { private final JdbcTemplate jdbcTemplate; public DatabaseAccessExample(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public List<String> getUserNames() { return jdbcTemplate.queryForList("SELECT name FROM users", String.class); } } ``` 4. **安全模块适配器 (Spring Security with Keycloak)** 结合之前的引用[^3],如果希望在 Spring Boot 应用中集成了基于 OAuth2 的身份验证服务(如 Keycloak),则可以直接利用现有的 Starter 包进行快速开发。 --- #### 常见问题及其解决方案 1. **事务管理失败** 当尝试启用声明式事务时发现未生效,可能是因为缺少代理机制支持。确保目标 Bean 被正确扫描以及方法调用发生在外部实例而非内部 self-invocation 上[^1]。 2. **AOP 切面无法拦截指定 Join Point** 若遇到切点表达式匹配不到预期的方法,请仔细检查切入点语法是否准确无误,并确认被织入的目标对象确实处于容器托管之下[^2]。 3. **第三方组件版本冲突** 在实际项目构建过程中可能会因为多个依赖间存在相互排斥的关系而导致运行时报错。此时建议借助 Maven Dependency Tree 工具分析具体原因并对齐所需范围内的所有子项版本号。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值