? ? ? 為了理解@EvenListener注解的底層原理,我們可以自己實現一個類似的注解模擬實現。
1.定義@MyListener注解
@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface MyListener {}
2.注解使用
@Componentstatic class SmsService {private static final Logger log = LoggerFactory.getLogger(SmsService.class);@MyListenerpublic void listener(MyEvent event) {log.debug("發送短信");}}
3.注解解析
public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestMyListener.class);SmsService smsService = context.getBean(SmsService.class);for(Method method : SmsService.class.getMethods()){if(method.isAnnotationPresent(MyListener.class)){ApplicationListener listener = new ApplicationListener<MyEvent>() {@Overridepublic void onApplicationEvent(MyEvent event) {try {method.invoke(smsService, event);}catch (Exception e){e.printStackTrace();}}};context.addApplicationListener(listener);}}context.getBean(MyService.class).doBusiness();context.close();}
?1)獲取監聽器類
?2)通過反射拿到方法
? ? ? ?判斷方法上的注解是否是我們自定義的注解,如果是,創建ApplicationListener對象(這里使用了泛型去指定事件類型,如果不這樣做可能會接收到別的事件而報錯,比如說容器關閉事件),重寫里面的監聽事件的方法,通過反射調用加了@MyListener注解的方法。
?3)把監聽器加入容器里面。
打印結果:
@MyListener注解實現了事件監聽機制。
?4.改進點
? ? ? ?上面我們固定解析了監聽類為SmsService類,現實情況是其它類上也可能加了@MyListener注解,我們可以做得更通用一些。
? ? ? ?(1)再寫一個監聽類EmailService。
@Componentstatic class EmailService {private static final Logger log = LoggerFactory.getLogger(EmailService.class);@MyListenerpublic void listener(MyEvent event) {log.debug("發送郵件");}}
? ? ? ? ?2)遍歷所有滿足條件的bean
public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestMyListener.class);for (String beanName : context.getBeanDefinitionNames()){Object bean = context.getBean(beanName);for(Method method : bean.getClass().getMethods()){if(method.isAnnotationPresent(MyListener.class)){ApplicationListener listener = new ApplicationListener<MyEvent>() {@Overridepublic void onApplicationEvent(MyEvent event) {try {method.invoke(bean, event);}catch (Exception e){e.printStackTrace();}}};context.addApplicationListener(listener);}}}context.getBean(MyService.class).doBusiness();context.close();}
? ? ? ? ? ? 3)測試結果
? ? ? ?容器監聽了所有實現@MyListener注解的方法。