Spring AOP "within" 不适用于方法
Spring AOP "within" doesn't work with method
下面是我的自定义注释。
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Transactional(value = TransactionalCode.MANAGER, readOnly = true)
public @interface FinanceReadTx {
}
我想用“MyAnnotation”做点什么,所以我声明了 @Around
和下面的方法。
@Aspect
@Component
public class TransactionalInterceptor implements Ordered {
@Around("within(@org.springframework.transaction.annotation.Transactional *) || " +
"within(@(@org.springframework.transaction.annotation.Transactional *) *)")
public Object proceed(ProceedingJoinPoint pjp) throws Throwable {
try {
setDbType(pjp);
Object result = pjp.proceed();
DataSourceContextHolder.clearDataSourceType();
return result;
} finally {
// restore state
DataSourceContextHolder.clearDataSourceType();
}
}
....
}
以下服务由其他 classes“自动装配”。所以我觉得不是AOP代理的问题。
@Service
public class UnconfirmedReportService {
private static final int PREVIEW_SIZE = 8;
@Autowired
private UnconfirmedReportRepository unconfirmedReportRepository;
...
@FinanceHikariReadTx
public List<UnconfirmedExcelDownloadView> getExcelData(UnconfirmedSearchCondition condition) {
List<UnconfirmedExcelDownloadView> excelData = newArrayList();
excelData.addAll(newArrayList(getPurchaseReportDetailExcel(condition)));
return excelData;
}
...
}
下面的代码调用上面的服务
@Slf4j
@Component
public class UnconfirmedDashboardDetailExcelReader extends SellerExcelReaderTemplate<UnconfirmedExcelDownloadView, UnconfirmedSearchCondition> {
@Autowired
private UnconfirmedReportService unconfirmedReportservice;
@Override public List<UnconfirmedExcelDownloadView> read(String conditionJson) {
UnconfirmedSearchCondition condition = transformCondition(conditionJson);
List<UnconfirmedExcelDownloadView> viewList = unconfirmedReportservice.getExcelData(condition);
return viewList;
}
...
}
如果 @MyAnnotation
被注解为 class,则调用 proceed(),但如果方法带有上述代码的注解,则它不起作用。我希望它只使用方法。
我尝试解决这个问题?
您目前正在做的事情与我在 中解释的类似,即在 类.
上匹配(元)注释
现在您想知道为什么它不匹配方法。我解释说。基本上,@within()
匹配带注释的 类 中的任何内容,而 @annotation()
匹配带注释的方法。问题是,@annotation()
需要一个准确的类型名称。
但是还有另一种方法可以直接在 execution()
签名中表达带注释的方法。在这里,您还可以选择以与将其用于带注释的 类 类似的方式指定元注释。让我们比较一下两者:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MetaAnnotationInterceptor {
@Before(
"execution(* *(..)) && (" +
"within(@de.scrum_master.app.MetaAnnotation *) || " +
"within(@(@de.scrum_master.app.MetaAnnotation *) *) || " +
"within(@(@(@de.scrum_master.app.MetaAnnotation *) *) *)" +
")"
)
public void annotatedClasses(JoinPoint thisJoinPoint){
System.out.println(thisJoinPoint);
}
@Before(
"execution(@de.scrum_master.app.MetaAnnotation * *(..)) || " +
"execution(@(@de.scrum_master.app.MetaAnnotation *) * *(..)) || " +
"execution(@(@(@de.scrum_master.app.MetaAnnotation *) *) * *(..)) "
)
public void annotatedMethods(JoinPoint thisJoinPoint){
System.out.println(thisJoinPoint);
}
}
后者就是您要找的。只需将 de.scrum_master.app.MetaAnnotation
替换为 org.springframework.transaction.annotation.Transactional
,它应该适用于您的用例。确保不要弄乱 ()
、@
和 *
的编号和嵌套顺序,否则您很快就会遇到切入点语法错误。
如果您更喜欢使用一种或两种建议方法,您可以创建一个包含两个切入点的大杂乱字符串,或者定义两个单独的 @Pointcut
s 并将它们组合在建议中,将它们与 ||
.
下面是我的自定义注释。
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Transactional(value = TransactionalCode.MANAGER, readOnly = true)
public @interface FinanceReadTx {
}
我想用“MyAnnotation”做点什么,所以我声明了 @Around
和下面的方法。
@Aspect
@Component
public class TransactionalInterceptor implements Ordered {
@Around("within(@org.springframework.transaction.annotation.Transactional *) || " +
"within(@(@org.springframework.transaction.annotation.Transactional *) *)")
public Object proceed(ProceedingJoinPoint pjp) throws Throwable {
try {
setDbType(pjp);
Object result = pjp.proceed();
DataSourceContextHolder.clearDataSourceType();
return result;
} finally {
// restore state
DataSourceContextHolder.clearDataSourceType();
}
}
....
}
以下服务由其他 classes“自动装配”。所以我觉得不是AOP代理的问题。
@Service
public class UnconfirmedReportService {
private static final int PREVIEW_SIZE = 8;
@Autowired
private UnconfirmedReportRepository unconfirmedReportRepository;
...
@FinanceHikariReadTx
public List<UnconfirmedExcelDownloadView> getExcelData(UnconfirmedSearchCondition condition) {
List<UnconfirmedExcelDownloadView> excelData = newArrayList();
excelData.addAll(newArrayList(getPurchaseReportDetailExcel(condition)));
return excelData;
}
...
}
下面的代码调用上面的服务
@Slf4j
@Component
public class UnconfirmedDashboardDetailExcelReader extends SellerExcelReaderTemplate<UnconfirmedExcelDownloadView, UnconfirmedSearchCondition> {
@Autowired
private UnconfirmedReportService unconfirmedReportservice;
@Override public List<UnconfirmedExcelDownloadView> read(String conditionJson) {
UnconfirmedSearchCondition condition = transformCondition(conditionJson);
List<UnconfirmedExcelDownloadView> viewList = unconfirmedReportservice.getExcelData(condition);
return viewList;
}
...
}
如果 @MyAnnotation
被注解为 class,则调用 proceed(),但如果方法带有上述代码的注解,则它不起作用。我希望它只使用方法。
我尝试解决这个问题?
您目前正在做的事情与我在
现在您想知道为什么它不匹配方法。我解释说@within()
匹配带注释的 类 中的任何内容,而 @annotation()
匹配带注释的方法。问题是,@annotation()
需要一个准确的类型名称。
但是还有另一种方法可以直接在 execution()
签名中表达带注释的方法。在这里,您还可以选择以与将其用于带注释的 类 类似的方式指定元注释。让我们比较一下两者:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MetaAnnotationInterceptor {
@Before(
"execution(* *(..)) && (" +
"within(@de.scrum_master.app.MetaAnnotation *) || " +
"within(@(@de.scrum_master.app.MetaAnnotation *) *) || " +
"within(@(@(@de.scrum_master.app.MetaAnnotation *) *) *)" +
")"
)
public void annotatedClasses(JoinPoint thisJoinPoint){
System.out.println(thisJoinPoint);
}
@Before(
"execution(@de.scrum_master.app.MetaAnnotation * *(..)) || " +
"execution(@(@de.scrum_master.app.MetaAnnotation *) * *(..)) || " +
"execution(@(@(@de.scrum_master.app.MetaAnnotation *) *) * *(..)) "
)
public void annotatedMethods(JoinPoint thisJoinPoint){
System.out.println(thisJoinPoint);
}
}
后者就是您要找的。只需将 de.scrum_master.app.MetaAnnotation
替换为 org.springframework.transaction.annotation.Transactional
,它应该适用于您的用例。确保不要弄乱 ()
、@
和 *
的编号和嵌套顺序,否则您很快就会遇到切入点语法错误。
如果您更喜欢使用一种或两种建议方法,您可以创建一个包含两个切入点的大杂乱字符串,或者定义两个单独的 @Pointcut
s 并将它们组合在建议中,将它们与 ||
.