spring通过自定义注解+@aspect切面+@component扫描三者协同实现@mytransactional增强:注解需@retention(runtime)且@target含method;切面用@annotation()切点匹配并执行环绕逻辑;bean需在组件扫描路径内。

Spring 通过 自定义注解 + AOP(切面)+ 注解驱动的 Bean 后置处理 三者协同,实现对如 @MyTransactional 这类自定义注解的扫描与运行时增强。核心不是“Spring 主动扫描注解”,而是你主动告诉 Spring:哪些类/方法上有这个注解,需要被谁处理。
1. 定义自定义注解并声明作用范围
注解本身只是元数据,需明确它能标注在哪(类?方法?)、是否保留到运行时:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyTransactional {
String value() default "";
boolean readOnly() default false;
}
关键点:
-
@Target决定能加在方法或类上(AOP 通常拦截方法,所以至少含METHOD) -
@Retention(RUNTIME)是必须的——只有运行时保留,AOP 的Aspect才能通过反射拿到它
2. 编写切面(Aspect),用切点(Pointcut)匹配带注解的方法
切面是真正执行增强逻辑的地方。用 @Around 或 @Before 等通知,配合 @Pointcut 表达式定位目标方法:
@Aspect
@Component // 让 Spring 管理这个切面
public class MyTransactionalAspect {
@Pointcut("@annotation(com.example.MyTransactional)")
public void myTxPointcut() {}
@Around("myTxPointcut()")
public Object handleMyTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
MyTransactional ann = joinPoint.getSignature()
.getMethod()
.getAnnotation(MyTransactional.class);
System.out.println("进入自定义事务:" + ann.readOnly());
try {
Object result = joinPoint.proceed(); // 执行原方法
System.out.println("提交自定义事务");
return result;
} catch (Exception e) {
System.out.println("回滚自定义事务");
throw e;
}
}
}
说明:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
@annotation(com.example.MyTransactional)是标准切点表达式,匹配任意被该注解标记的方法 - 切面类加
@Component(或配置为 Bean),确保被 Spring 容器加载 - 若使用 XML 配置,还需
<aspectj-autoproxy></aspectj-autoproxy>;若用 Java 配置,确保启用了@EnableAspectJAutoProxy
3. 确保组件扫描覆盖切面和目标类
Spring Boot 默认扫描主启动类所在包及其子包。如果你的 @MyTransactional 注解用在 com.example.service,而切面在 com.example.aop,只要它们在同一个根包下,就自动生效。
若结构分散,需显式配置扫描路径:
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.service", "com.example.aop"})
@EnableAspectJAutoProxy
public class Application { ... }
4. (可选)进阶:结合 BeanPostProcessor 提前检查或注册
如果需要在 Bean 创建后、初始化前,检查其是否含 @MyTransactional 并做预处理(比如注册到某个事务管理器),可实现 BeanPostProcessor:
@Component
public class MyTransactionalBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class> clazz = bean.getClass();
if (clazz.isAnnotationPresent(MyTransactional.class)) {
System.out.println("发现类级 @MyTransactional:" + beanName);
}
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(MyTransactional.class)) {
System.out.println("发现方法级 @MyTransactional:" + method);
}
}
return bean;
}
}
注意:这不是替代 AOP 的方式,而是补充手段,适用于元数据收集、日志、校验等场景。
不复杂但容易忽略:注解必须 @Retention(RUNTIME),切面必须被 Spring 管理,切点表达式要写对——这三点齐备,Spring 就能准确识别并拦截你的 @MyTransactional。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










