Belirtilen açıklama ile tüm Sınıfların tüm genel yöntemlerini izlemek istiyorum (@ Monitor diyelim) (not: Ek açıklama sınıf düzeyindedir). Bunun için olası bir nokta ne olabilir? Not: @AspectJ tarzı Yay AOP kullanıyorum.
Belirtilen açıklama ile tüm Sınıfların tüm genel yöntemlerini izlemek istiyorum (@ Monitor diyelim) (not: Ek açıklama sınıf düzeyindedir). Bunun için olası bir nokta ne olabilir? Not: @AspectJ tarzı Yay AOP kullanıyorum.
Yanıtlar:
Yazım noktasını bir yöntem nokta kesimi ile birleştirmelisiniz.
Bu nokta kesimleri, @Monitor ek açıklamasıyla işaretlenmiş bir sınıf içindeki tüm genel yöntemleri bulmak için çalışacaktır:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
İlk ikisini birleştiren son noktayı tavsiye edin ve bitirdiniz!
Eğer ilgileniyorsanız, buraya @AspectJ stiliyle bir hile sayfası yazdım ve burada karşılık gelen bir örnek belge .
Soruda açıklandığı gibi ek açıklamaları kullanma.
Ek Açıklama: @Monitor
Sınıftaki ek açıklama app/PagesController.java:
package app;
@Controller
@Monitor
public class PagesController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Yöntemle ilgili ek açıklama app/PagesController.java:
package app;
@Controller
public class PagesController {
@Monitor
@RequestMapping(value = "/", method = RequestMethod.GET)
public @ResponseBody String home() {
return "w00t!";
}
}
Özel açıklama, app/Monitor.java:
package app;
@Component
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor {
}
Ek açıklama yönü 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 etkinleştirme servlet-context.xml:
<aop:aspectj-autoproxy />
AspectJ kitaplıklarını dahil et pom.xml:
<artifactId>spring-aop</artifactId>
<artifactId>aspectjrt</artifactId>
<artifactId>aspectjweaver</artifactId>
<artifactId>cglib</artifactId>
MonitorBahar olmak zorunda Component?
ComponentEk açıklama şey dokumacı AspectJ sınıfı dahil uygulamak için Bahar kabı anlatmak için kullanılır. Varsayılan olarak, Bahar sadece bakar Controller, Serviceancak, ve diğer özel ek açıklamaları Aspect.
@Componentüzerinde açıklama @interfacedeğil Aspect. Buna neden ihtiyaç var?
@ComponentYay AspectJ'yi IoC / DI yönü yönelimli sistemi ile derlenir nedenle açıklama yapar. Nasıl farklı söyleyeceğimi bilmiyorum. docs.spring.io/spring/docs/3.2.x/spring-framework-reference/…
Bunun gibi bir şey:
@Before("execution(* com.yourpackage..*.*(..))")
public void monitor(JoinPoint jp) {
if (jp.getTarget().getClass().isAnnotationPresent(Monitor.class)) {
// perform the monitoring actions
}
}
Bu sınıftan önce aynı sınıfla ilgili başka bir tavsiyeniz olmamasına dikkat edin , çünkü ek açıklamalar proxy uygulandıktan sonra kaybolacaktır.
kullanım
@Before("execution(* (@YourAnnotationAtClassLevel *).*(..))")
public void beforeYourAnnotation(JoinPoint proceedingJoinPoint) throws Throwable {
}
En basit yol şöyle görünüyor:
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
'YourService' sınıfında '@MyHandling' ile özellikle açıklanmış tüm yöntemlerin yürütülmesini durdurur. İstisnasız tüm yöntemleri kesmek için, açıklamayı doğrudan sınıfa koyun.
Buradaki özel / genel kapsam ne olursa olsun, ancak spring-aop'un aynı örnekteki (tipik olarak özel olanlar) yöntem çağrıları için açı kullanamayacağını unutmayın, çünkü bu durumda proxy sınıfını kullanmaz.
Burada @Around tavsiye kullanıyoruz, ancak temelde @Before, @After veya herhangi bir tavsiye ile aynı sözdizimi.
Bu arada, @MyHandling ek açıklaması şu şekilde yapılandırılmalıdır:
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions afterönce satırdaki değeri döndürdüğümüz için asla aranmayacak.
Spring'in PerformanceMonitoringInterceptor'ını kullanabilir ve bir beanpostprocessor kullanarak tavsiyeleri programlı olarak kaydedebilirsiniz.
@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;
}
}
}
İlkbahardan itibaren 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 *);