ฉันต้องการตรวจสอบวิธีการสาธารณะทั้งหมดของทุกชั้นเรียนพร้อมคำอธิบายประกอบที่ระบุ (พูด @Monitor) (หมายเหตุ: คำอธิบายประกอบอยู่ในระดับชั้นเรียน) สิ่งที่เป็นไปได้สำหรับสิ่งนี้คืออะไร? หมายเหตุ: ฉันใช้ @AspectJ style Spring AOP
ฉันต้องการตรวจสอบวิธีการสาธารณะทั้งหมดของทุกชั้นเรียนพร้อมคำอธิบายประกอบที่ระบุ (พูด @Monitor) (หมายเหตุ: คำอธิบายประกอบอยู่ในระดับชั้นเรียน) สิ่งที่เป็นไปได้สำหรับสิ่งนี้คืออะไร? หมายเหตุ: ฉันใช้ @AspectJ style Spring AOP
คำตอบ:
คุณควรรวม pointcut กับ method pointcut
คำสั่งชี้เหล่านี้จะทำงานเพื่อค้นหาวิธีการสาธารณะทั้งหมดภายในคลาสที่มีเครื่องหมายคำอธิบายประกอบ @Monitor:
@Pointcut("within(@org.rejeev.Monitor *)")
public void beanAnnotatedWithMonitor() {}
@Pointcut("execution(public * *(..))")
public void publicMethod() {}
@Pointcut("publicMethod() && beanAnnotatedWithMonitor()")
public void publicMethodInsideAClassMarkedWithAtMonitor() {}
แนะนำจุดสุดท้ายที่รวมสองข้อแรกและเสร็จสิ้น!
หากคุณสนใจฉันได้เขียนแผ่นโกงที่มีสไตล์ @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
?
Component
คำอธิบายประกอบที่ใช้ในการบอกภาชนะฤดูใบไม้ผลิที่จะใช้รวมถึงชั้นใน AspectJ สิ่งทอ โดยค่าเริ่มต้นฤดูใบไม้ผลิดูเฉพาะController
, Service
และคำอธิบายประกอบที่เฉพาะเจาะจงอื่น ๆ Aspect
แต่ไม่
@Component
คำอธิบายประกอบที่@interface
ไม่ใช่ไฟล์Aspect
. ทำไมจึงจำเป็น?
@Component
คำอธิบายประกอบที่ทำให้ฤดูใบไม้ผลิจะรวบรวมมันกับระบบที่มุ่งเน้นด้าน AspectJ IoC / DI ไม่รู้จะพูดต่างกันยังไง docs.spring.io/spring/docs/3.2.x/spring-framework-reference/…
อะไรแบบนั้น:
@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() {
มีลักษณะที่นี้สำหรับขั้นตอนตามคู่มือขั้นตอนเกี่ยวกับเรื่องนี้
คุณยังสามารถกำหนด pointcut เป็น
public pointcut publicMethodInsideAClassMarkedWithAtMonitor() : execution(public * (@Monitor *).*(..));
execution(public * @Monitor *.*(..))
งานที่เรียบง่ายกว่าเล็กน้อยเช่นกัน
วิธีที่ง่ายที่สุดน่าจะเป็น:
@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
จะไม่ได้เรียกว่าตั้งแต่ที่เรากำลังกลับมาคุ้มค่าในบรรทัดก่อน
คุณสามารถใช้ PerformanceMonitoringInterceptor ของ Spring และลงทะเบียนคำแนะนำทางโปรแกรมโดยใช้ 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;
}
}
}
จาก 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 *);