Je souhaite surveiller toutes les méthodes publiques de toutes les classes avec une annotation spécifiée (par exemple, @Monitor) (note: l'annotation est au niveau de la classe). Quel pourrait être un point possible pour cela? Remarque: J'utilise le style Spring AOP de @AspectJ.
Vous devez combiner un type pointcut avec une méthode.
Ces raccourcis feront le travail pour trouver toutes les méthodes publiques dans une classe marquée avec une annotation @Monitor:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
Conseil le dernier point de coupe qui combine les deux premiers et vous avez terminé!
Si vous êtes intéressé, j'ai écrit un aide-mémoire avec le style @AspectJ ici avec un exemple de document ici.
Utiliser des annotations, comme décrit dans la question.
Annotation: @Monitor
Annotation sur la classe, app/PagesController.Java
:
package app;
@Controller
@Monitor
public class PagesController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Annotation sur la méthode, app/PagesController.Java
:
package app;
@Controller
public class PagesController {
@Monitor
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Annotation personnalisée, app/Monitor.Java
:
package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}
Aspect pour l'annotation, 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());
}
}
Activer AspectJ, servlet-context.xml
:
<aop:aspectj-autoproxy />
Inclure les bibliothèques AspectJ, pom.xml
:
<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
Quelque chose comme ca:
@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}
Notez que vous ne devez avoir aucun autre conseil sur la même classe avant celui-ci, car les annotations seront perdues après le remplacement du proxy.
Utilisation
@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
Vous pouvez également définir le pointcut comme
public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
cela devrait suffire à marquer votre méthode d'aspect comme ceci:
@After("@annotation(com.marcot.CommitTransaction)")
public void after() {
jetez un oeil à this pour un guide étape par étape à ce sujet.
Le moyen le plus simple semble être:
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
Il interceptera l'exécution de toutes les méthodes spécifiquement annotées avec '@MyHandling' dans la classe 'YourService'. Pour intercepter toutes les méthodes sans exception, il suffit de placer l'annotation directement sur la classe.
N'importe le domaine privé/public ici, mais gardez à l'esprit que spring-aop ne peut pas utiliser l'aspect pour les appels de méthode dans la même instance (généralement privée), car il n'utilise pas la classe proxy dans ce cas.
Nous utilisons ici les conseils @Around, mais la syntaxe est la même avec @Avant, @After ou tout autre conseil.
En passant, l'annotation @MyHandling doit être configurée comme suit:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
Du printemps 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 *);
Vous pouvez utiliser PerformanceMonitoringInterceptor de Spring et enregistrer par programmation les conseils à l'aide d'un processeur de haricot.
@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;
}
}
}