지정된 주석 (예 : @Monitor)으로 모든 클래스의 모든 공용 메소드를 모니터링하고 싶습니다 (참고 : 주석은 클래스 수준입니다). 이것에 대해 가능한 포인트 컷은 무엇입니까? 참고 : @AspectJ 스타일의 Spring AOP를 사용하고 있습니다.
지정된 주석 (예 : @Monitor)으로 모든 클래스의 모든 공용 메소드를 모니터링하고 싶습니다 (참고 : 주석은 클래스 수준입니다). 이것에 대해 가능한 포인트 컷은 무엇입니까? 참고 : @AspectJ 스타일의 Spring AOP를 사용하고 있습니다.
답변:
유형 포인트 컷과 메소드 포인트 컷을 결합해야합니다.
이 pointcut은 @Monitor 주석으로 표시된 클래스 내에서 모든 공개 메소드를 찾기 위해 작동합니다.
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
처음 두 개를 결합한 마지막 포인트 컷을 조언하면 끝입니다!
질문에 설명 된대로 주석 사용
주석: @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
이 스프링이어야 Component
합니까?
Component
주석은 것은 위버 AspectJ의에 클래스를 포함 적용 Spring 컨테이너를 얘기하는 데 사용됩니다. 기본적으로, 봄은 본다 Controller
, Service
하지만, 다른 특정 주석 Aspect
.
@Component
주석에 대해 이야기 @interface
하고 Aspect
있었습니다. 왜 필요한가요?
@Component
봄은 AspectJ를 IOC의 / DI 측면 지향 시스템에 컴파일 있도록 주석을 수 있습니다. 나는 다르게 말하는 법을 모른다. docs.spring.io/spring/docs/3.2.x/spring-framework-reference/…
가장 간단한 방법은 다음과 같습니다.
@Around("execution(@MyHandling * com.exemple.YourService.*(..))")
public Object aroundServiceMethodAdvice(final ProceedingJoinPoint pjp)
throws Throwable {
// perform actions before
return pjp.proceed();
// perform actions after
}
'YourService'클래스에서 '@MyHandling'으로 주석이 달린 모든 메소드의 실행을 인터셉트합니다. 예외없이 모든 메소드를 가로 채려면 주석을 클래스에 직접 넣으십시오.
여기서 private / public 범위와 상관없이 spring-aop 은이 경우 프록시 클래스를 사용하지 않기 때문에 동일한 인스턴스 (일반적으로 개인 호출)의 메소드 호출에 aspect를 사용할 수 없습니다.
여기서는 @Around 조언을 사용하지만 기본적으로 @Before, @After 또는 조언과 동일한 구문입니다.
그건 그렇고, @MyHandling 주석은 다음과 같이 구성되어야합니다 :
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyHandling {
}
// perform actions after
우리가 전에 행의 값을 반환하고 있기 때문에 호출되지 얻을 않습니다.
Spring의 PerformanceMonitoringInterceptor를 사용하고 Beanpostprocessor를 사용하여 조언을 프로그래밍 방식으로 등록 할 수 있습니다.
@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;
}
}
}
봄부터 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 *);