Springモニターlistener原理-手書きモニター(二)
9282 ワード
インターフェースベースのモニターによる原理
インターフェース定義
@ComponentScan({"com.zhu.demo.customer"})
@Configuration
public class CustomerListenerConfig {
}
public interface MyApplicationEvent {
}
public interface MyApplicationListener {
/**
*
* @param event
*/
void onEvent(MyApplicationEvent event);
/**
*
* @param eventType
* @return
*/
boolean supportsEventType(Class> eventType);
}
インターフェース実装public class AEvent implements MyApplicationEvent {
//
}
public class BEvent implements MyApplicationEvent {
//
}
@Component
public class AListener implements MyApplicationListener {
@Override
public void onEvent(MyApplicationEvent event) {
System.out.println(event.getClass());
}
/**
* ,
* @param eventType
* @return
*/
@Override
public boolean supportsEventType(Class> eventType) {
//
Class annotationClass = (Class) ((ParameterizedType) this.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
// .class.isAssignableFrom( .class)
return annotationClass.isAssignableFrom(eventType);
}
}
supportsEventType
は、これらのイベントを傍受する必要があると判断するコア方法である.判断の方法はモニター上の一般的なタイプがイベントタイプと一致するかどうかを取得します.もし一致すれば、私たちは傍受が必要な事件です.イベントリリース
@Component("myApplicationEventPublisher")
public class MyApplicationEventPublisher {
/**
*
*/
@Autowired
private List applicationListeners ;
public void pushEvent(MyApplicationEvent event){
for (MyApplicationListener applicationListener : applicationListeners) {
//
if (applicationListener.supportsEventType(event.getClass())){
applicationListener.onEvent(event);
}
}
}
public List getApplicationListeners() {
return applicationListeners;
}
public void setApplicationListeners(List applicationListeners) {
this.applicationListeners = applicationListeners;
}
}
リリースイベントを実行public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CustomerListenerConfig.class);
MyApplicationEventPublisher myApplicationEventPublisher = (MyApplicationEventPublisher) applicationContext.getBean("myApplicationEventPublisher");
MyApplicationEvent Aevent = new AEvent();
MyApplicationEvent Bevent = new BEvent();
myApplicationEventPublisher.pushEvent(Aevent);
myApplicationEventPublisher.pushEvent(Bevent);
}
}
結果class com.zhu.demo.customer.inter.impl.AEvent
私たちはAEventだけを傍聴したので、AEventだけプリントしました.これでインターフェースのモニターに基づいて実現しました.コードのポイントはsupportsEventType方法です.私たちがモニターが必要なタイプを判断するために使用します.後の文章はspringモニターのソースコードを分析する時にも似たようなロジックを見ます.注解によるモニターの実装原理
@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyEventListener {
}
注釈表示方法を使用する@ComponentScan({"com.zhu.demo.customer"})
@Configuration
public class CustomerListenerConfig {
@MyEventListener
public void test(AEvent aEvent){
System.out.println(" " + aEvent.getClass());
}
}
皆さんは疑問があるかもしれませんが、MyEventListenerの表示を注釈されたモニターは一つの方法でしかないです.MyAppliation Listenerインターフェースを実現していません.MyAppliation Event Publisherが発表したイベントを監聴してもいいですか?それともMyAppliation Event Publisherのイベントをどうやって監聴できますか?ここでは設計モードを紹介します.アダプターモードです.
public class MyApplicationListenerMethodAdapter implements MyApplicationListener {
/**
* bean
*/
private final String beanName;
/**
* MyEventListener
*/
private final Method method;
/**
* method
*/
@Nullable
private ApplicationContext applicationContext;
public MyApplicationListenerMethodAdapter(String beanName, Method method, @Nullable ApplicationContext applicationContext) {
this.beanName = beanName;
this.method = method;
this.applicationContext = applicationContext;
}
protected void doInvoke(Object... args) {
Object bean = applicationContext.getBean(beanName);
// Detect package-protected NullBean instance through equals(null) check
if (bean.equals(null)) {
return;
}
ReflectionUtils.makeAccessible(this.method);
try {
// MyEventListener
this.method.invoke(bean, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
*
* @param event
*/
@Override
public void onEvent(MyApplicationEvent event) {
doInvoke(new Object[] {event});
}
/**
*
* @param eventType
* @return
*/
@Override
public boolean supportsEventType(Class> eventType) {
Class>[] getTypeParameters = method.getParameterTypes();
if (getTypeParameters[0].isAssignableFrom(eventType)) {
return true;
}
return false;
}
}
アダプター類はすでにありますが、どのようにMyEventListenerに注釈表示された方法をスキャンして解析しますか?私たちはspringで提供される拡張点SmartInitializingSingletonを使用します.SmartInitializingSingletonのインターフェースを実現した後、すべての単例beanが初期化された後、SpringのIOC容器はこのインターフェースのafterSingletons Instantiated()方法をリセットします.私たちはこの拡張点でMyEventListenerに表示されるすべての方法を見つけることができます.
@Component
public class MyEventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware {
@Nullable
private ConfigurableApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// spring
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
@Override
public void afterSingletonsInstantiated() {
// beanFactory ,beanFactory spring
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// beanFactory
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
Class> type = beanFactory.getType(beanName);
// MyEventListener
Map annotatedMethods = null;
annotatedMethods = MethodIntrospector.selectMethods(type,
(MethodIntrospector.MetadataLookup) method ->
AnnotatedElementUtils.findMergedAnnotation(method, MyEventListener.class));
//
if (CollectionUtils.isEmpty(annotatedMethods)) {
continue;
}
//
MyApplicationEventPublisher myApplicationEventPublisher = (MyApplicationEventPublisher)beanFactory.getBean("myApplicationEventPublisher");
for (Method method : annotatedMethods.keySet()) {
// MyEventListener , beanName method、spring 。
MyApplicationListenerMethodAdapter myApplicationListenerMethodAdapter = new MyApplicationListenerMethodAdapter(beanName, method, applicationContext);
//
myApplicationEventPublisher.getApplicationListeners().add(myApplicationListenerMethodAdapter);
}
}
}
}
実行 public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CustomerListenerConfig.class);
MyApplicationEventPublisher myApplicationEventPublisher = (MyApplicationEventPublisher) applicationContext.getBean("myApplicationEventPublisher");
MyApplicationEvent Aevent = new AEvent();
MyApplicationEvent Bevent = new BEvent();
myApplicationEventPublisher.pushEvent(Aevent);
myApplicationEventPublisher.pushEvent(Bevent);
}
実行結果は以下の通りです.class com.zhu.demo.customer.inter.impl.AEvent
class com.zhu.demo.customer.inter.impl.AEvent
これで私たちが定義したモニターはもう実現しました.後の文章はspringの実現を分析します.