Я хочу отслеживать все общедоступные методы всех классов с указанной аннотацией (например, @Monitor) (примечание: аннотация находится на уровне класса). Что может быть для этого возможным? Примечание. Я использую Spring AOP в стиле @AspectJ.
@AspectJ pointcut для всех методов класса с определенной аннотацией
Ответы (10)
Вы должны комбинировать тип pointcut с методом pointcut.
Эти pointcuts выполнят работу по поиску всех общедоступных методов внутри класса, отмеченного аннотацией @Monitor:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
Посоветуйте последний pointcut, который сочетает в себе первые два, и готово!
Если вам интересно, я написал шпаргалку со стилем @AspectJ здесь с соответствующим пример документа здесь.
Используя аннотации, как описано в вопросе.
Аннотация: @Monitor
Аннотация к классу, app/PagesController.java
:
package app;
@Controller
@Monitor
public class PagesController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Аннотация к методу, app/PagesController.java
:
package app;
@Controller
public class PagesController {
@Monitor
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Пользовательская аннотация, app/Monitor.java
:
package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}
Аспект аннотации, app/MonitorAspect.java
:
package app;
@Component
@Aspect
public class MonitorAspect {
@Before(value = "@within(app.Monitor) || @annotation(app.Monitor)")
public void before(JoinPoint joinPoint) throws Throwable {
LogFactory.getLog(MonitorAspect.class).info("monitor.before, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
}
@After(value = "@within(app.Monitor) || @annotation(app.Monitor)")
public void after(JoinPoint joinPoint) throws Throwable {
LogFactory.getLog(MonitorAspect.class).info("monitor.after, class: " + joinPoint.getSignature().getDeclaringType().getSimpleName() + ", method: " + joinPoint.getSignature().getName());
}
}
Включите AspectJ, servlet-context.xml
:
<aop:aspectj-autoproxy />
Включите библиотеки AspectJ, pom.xml
:
<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
Monitor
должна быть Spring Component
?
- person mwhs; 22.11.2013
Component
используется, чтобы указать контейнеру Spring применить включение класса в объект AspectJ weaver. По умолчанию Spring просматривает только Controller
, Service
и другие конкретные аннотации, но не Aspect
.
- person Alex; 23.11.2013
@Component
к @interface
, а не к Aspect
. Зачем это нужно?
- person mwhs; 23.11.2013
@Component
позволяет Spring компилировать его с аспектно-ориентированной системой AspectJ IoC / DI. Я не знаю, как это сказать по-другому. docs.spring.io/spring/ документы / 3.2.x / spring-framework-reference /
- person Alex; 25.11.2013
Что-то такое:
@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}
Обратите внимание, что у вас не должно быть никаких других советов по тому же классу перед этим, потому что аннотации будут потеряны после проксирования.
Использовать
@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
этого должно быть достаточно, чтобы пометить ваш метод аспекта следующим образом:
@After("@annotation(com.marcot.CommitTransaction)")
public void after() {
взгляните на this для пошаговое руководство по этому поводу.
Вы также можете определить pointcut как
public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
execution(public * @Monitor *.*(..))
тоже работает.
- person xmedeko; 19.12.2014
Кажется, самый простой способ:
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
Он перехватит выполнение всех методов, специально помеченных @MyHandling в классе YourService. Чтобы перехватить все методы без исключения, просто поместите аннотацию прямо в класс.
Независимо от частной / общедоступной области, но имейте в виду, что spring-aop не может использовать аспект для вызовов методов в одном и том же экземпляре (обычно частные), потому что в этом случае он не использует прокси-класс.
Здесь мы используем совет @Around, но в основном это тот же синтаксис, что и @Before, @After или любой другой совет.
Кстати, аннотацию @MyHandling нужно настроить так:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions after
никогда не будет вызван, поскольку мы возвращали значение в строке раньше.
- person josephpconley; 21.04.2017
Из Spring's AnnotationTransactionAspect
:
/**
* Matches the execution of any public method in a type with the Transactional
* annotation, or any subtype of a type with the Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
Вы можете использовать Spring PerformanceMonitoringInterceptor и программно зарегистрировать совет с помощью постпроцессора beanpost.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Monitorable
{
}
public class PerformanceMonitorBeanPostProcessor extends ProxyConfig implements BeanPostProcessor, BeanClassLoaderAware, Ordered,
InitializingBean
{
private Class<? extends Annotation> annotationType = Monitorable.class;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private Advisor advisor;
public void setBeanClassLoader(ClassLoader classLoader)
{
this.beanClassLoader = classLoader;
}
public int getOrder()
{
return LOWEST_PRECEDENCE;
}
public void afterPropertiesSet()
{
Pointcut pointcut = new AnnotationMatchingPointcut(this.annotationType, true);
Advice advice = getInterceptor();
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}
private Advice getInterceptor()
{
return new PerformanceMonitoringInterceptor();
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
{
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
{
if(bean instanceof AopInfrastructureBean)
{
return bean;
}
Class<?> targetClass = AopUtils.getTargetClass(bean);
if(AopUtils.canApply(this.advisor, targetClass))
{
if(bean instanceof Advised)
{
((Advised)bean).addAdvisor(this.advisor);
return bean;
}
else
{
ProxyFactory proxyFactory = new ProxyFactory(bean);
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else
{
return bean;
}
}
}
Я поделюсь с вами кодом, который может быть полезен, он предназначен для создания аннотации, которую можно использовать либо в классе, либо в методе.
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Documented
public @interface AnnotationLogger {
/**
* It is the parameter is to show arguments in the method or the class.
*/
boolean showArguments() default false;
}
@Aspect
@Component
public class AnnotationLoggerAspect {
@Autowired
private Logger logger;
private static final String METHOD_NAME = "METHOD NAME: {} ";
private static final String ARGUMENTS = "ARGS: {} ";
@Before(value = "@within(com.org.example.annotations.AnnotationLogger) || @annotation(com.org.example.annotations.AnnotationLogger)")
public void logAdviceExecutionBefore(JoinPoint joinPoint){
CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
AnnotationLogger annotationLogger = getAnnotationLogger(joinPoint);
if(annotationLogger!= null) {
StringBuilder annotationLoggerFormat = new StringBuilder();
List<Object> annotationLoggerArguments = new ArrayList<>();
annotationLoggerFormat.append(METHOD_NAME);
annotationLoggerArguments.add(codeSignature.getName());
if (annotationLogger.showArguments()) {
annotationLoggerFormat.append(ARGUMENTS);
List<?> argumentList = Arrays.asList(joinPoint.getArgs());
annotationLoggerArguments.add(argumentList.toString());
}
logger.error(annotationLoggerFormat.toString(), annotationLoggerArguments.toArray());
}
}
private AnnotationLogger getAnnotationLogger(JoinPoint joinPoint) {
AnnotationLogger annotationLogger = null;
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = joinPoint.getTarget().getClass().
getMethod(signature.getMethod().getName(), signature.getMethod().getParameterTypes());
if (method.isAnnotationPresent(AnnotationLogger.class)){
annotationLogger = method.getAnnotation(AnnotationLoggerAspect.class);
}else if (joinPoint.getTarget().getClass().isAnnotationPresent(AnnotationLoggerAspect.class)){
annotationLogger = joinPoint.getTarget().getClass().getAnnotation(AnnotationLoggerAspect.class);
}
return annotationLogger;
}catch(Exception e) {
return annotationLogger;
}
}
}