您的位置:首页 > 编程语言 > Java开发

Spring3.2.6中事件驱动模型实现原理深入源码分析

2016-03-28 19:56 1131 查看

Spring3.2.6中事件驱动模型实现原理深入源码分析

本次学习,是在新入公司熟悉项目时候开始的。因为是做页游的项目,所以涉及到gameServer做会将游戏中的业务操作日志交给logServer处理。在本次项目中是采用spring自带的事件驱动模型(Event-Listener)来完成的,所以就花时间深入spring和jdk源码好好分析了其实现原理,收获颇多,故在此记录,留做以后复习查看。

什么叫事件驱动模型?

要了解什么是事件驱动模型,首先要知道下面这样几个概念,我以JDK中GUI的按钮点击做说明。


事件(Event): 用户点击按钮(Button),就会产生事件(Event)。这里就是点击事件(ClickEvent)。

事件源(EventSource):发生事件的根源(场所)就是事件源。这里按钮组件就是事件源。

事件监听器(EventListener):监听特定的事件并处理的程序。这里监听器就是点击事件的处理者。

事件分发者(EventDispatcher):将发生的事件通知相对应的事件处理者的程序。这里就是通知监听器处理事件的程序。

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;

/**
* @Description: JDK中GUI按钮的点击事件演示
* @author Yang Gao
* @date 2016-3-28 上午9:48:42
*
*/
public class EventListenerTest {

public static void main(String[] args) {
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
//当前屏幕中心点的X坐标
final int CONTENT_X = d.width/2;
//当前屏幕中心点的Y坐标
final int CONTENT_Y = d.height/2;

//Windos窗口组件
JFrame f = new JFrame("测试窗口");
//窗口组件大小
f.setSize(300, 200);
//窗口组件位置
f.setLocation((CONTENT_X - f.getWidth()/2), (CONTENT_Y - f.getHeight()/2));
//设置大小不可改变
f.setResizable(false);
//设置可见性为可见
f.setVisible(true);
//设置默认关闭调用事件
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//按钮组件,事件源
JButton btn = new JButton("点击我哟!");
//设置按钮组件的大小
btn.setSize(150, 50);
//面板添加组件
f.add(btn);
//对事件源添加事件监听器
btn.addActionListener(new MyListener());
}

}

/**
* @Description: 自定义clickListenert类
* @author Yang Gao
* @date 2016-3-28 上午10:17:16
*
*/
class MyListener implements ActionListener{

@Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton)e.getSource();
JOptionPane.showMessageDialog(null,"我是事件监听器的处理程序,我处理的是:【" + btn.getText() + "】");
}

}


在上面的code中btn.addActionListener(new MyListener());至于jdk是如何将用户产生的click事件通知给MyListener,也就是事件发布者这个角色,这里不详细叙述,有兴趣的童鞋可以考虑跟进jdk源码来找到答案。

Spring是如何实现?



1.先看看所有事件Event类都要继承的父类EventObject(JDK)代码。

package java.util;

/**
* <p>
* The root class from which all event state objects shall be derived.
* <p>
* All Events are constructed with a reference to the object, the "source",
* that is logically deemed to be the object upon which the Event in question
* initially occurred upon.
*
* @since JDK1.1
*/

public class EventObject implements java.io.Serializable {

private static final long serialVersionUID = 5516075349620653480L;

/**
* The object on which the Event initially occurred.
*/
protected transient Object  source;

/**
* Constructs a prototypical Event.
*
* @param    source    The object on which the Event initially occurred.
* @exception  IllegalArgumentException  if source is null.
*/
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");

this.source = source;
}

/**
* The object on which the Event initially occurred.
*
* @return   The object on which the Event initially occurred.
*/
public Object getSource() {
return source;
}

/**
* Returns a String representation of this EventObject.
*
* @return  A a String representation of this EventObject.
*/
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}


再看看Spring中继承EventObject的类,ApplicationEvent的具体代码

/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.context;

import java.util.EventObject;

/**
* Class to be extended by all application events. Abstract as it
* doesn't make sense for generic events to be published directly.
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public abstract class ApplicationEvent extends EventObject {

/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 7099057708183571937L;

/** System time when the event happened */
private final long timestamp;

/**
* Create a new ApplicationEvent.
* @param source the component that published the event (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}

/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}

}


2.接下来,我们看看所有事件监听器Listener类都要实现的EventListener(JDK)接口。

/*
* Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/

package java.util;

/**
* A tagging interface that all event listener interfaces must extend.
* @since JDK1.1
*/
public interface EventListener {
}


那么Spring中实现了这个接口的是接口ApplicationListener< E extends ApplicationEvent > ,很明显使用的泛型,约定了其事件类型,看看具体代码。

package org.springframework.context;

import java.util.EventListener;

/**
* Interface to be implemented by application event listeners.
* Based on the standard {@code java.util.EventListener} interface
* for the Observer design pattern.
*
* <p>As of Spring 3.0, an ApplicationListener can generically declare the event type
* that it is interested in. When registered with a Spring ApplicationContext, events
* will be filtered accordingly, with the listener getting invoked for matching event
* objects only.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @param <E> the specific ApplicationEvent subclass to listen to
* @see org.springframework.context.event.ApplicationEventMulticaster
*/
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);

}


从上面可以看出,当泛型约定的事件发生时候,会调用其onApplicationEvent的实现方法处理。我们再看看spring中实现这一接口的子接口:SmartApplicationListener的具体代码。

package org.springframework.context.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;

/**
* Extended variant of the standard {@link ApplicationListener} interface,
* exposing further metadata such as the supported event type.
*
* @author Juergen Hoeller
* @since 3.0
*/
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {

/**
* Determine whether this listener actually supports the given event type.
*/
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);

/**
* Determine whether this listener actually supports the given source type.
*/
boolean supportsSourceType(Class<?> sourceType);

}


从上面的代码上可以看出,这个子接口添加了更为具体的类型判断,supportsEventType表示仅支持对应的事件类型,supportsSourceType表示仅支持对应的事件类型(这里就对应EventObject类中被transient瞬态修饰符的变量Object source)。

3.最后我们再看看最核心的东东,就是事件分发器(EventDispatcher)。Spring中使用接口ApplicationEventPublisher和接口ApplicationEventMulticaster来共同完成,首先我们来看一下两个接口定义的通用方法有哪些?

package org.springframework.context;
public interface ApplicationEventPublisher {
/**
* Notify all listeners registered with this application of an application
* event. Events may be framework events (such as RequestHandledEvent)
* or application-specific events.
* @param event the event to publish
* @see org.springframework.web.context.support.RequestHandledEvent
*/
void publishEvent(ApplicationEvent event);
}


package org.springframework.context.event;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public interface ApplicationEventMulticaster {

/**
* Add a listener to be notified of all events.
* @param listener the listener to add
*/
void addApplicationListener(ApplicationListener listener);

/**
* Add a listener bean to be notified of all events.
* @param listenerBeanName the name of the listener bean to add
*/
void addApplicationListenerBean(String listenerBeanName);

/**
* Remove a listener from the notification list.
* @param listener the listener to remove
*/
void removeApplicationListener(ApplicationListener listener);

/**
* Remove a listener bean from the notification list.
* @param listenerBeanName the name of the listener bean to add
*/
void removeApplicationListenerBean(String listenerBeanName);

/**
* Remove all listeners registered with this multicaster.
* <p>After a remove call, the multicaster will perform no action
* on event notification until new listeners are being registered.
*/
void removeAllListeners();

/**
* Multicast the given application event to appropriate listeners.
* @param event the event to multicast
*/
void multicastEvent(ApplicationEvent event);

}


从上面可以很清楚的看出,其中ApplicationEventPublisher 接口主要负责将事件发布,ApplicationEventMulticaster 接口主要负责事件通知(回调)。Spring中ApplicationContext接口实现了ApplicationEventPublisher 接口,具体实现类是AbstractApplicationContext,让我们看看源代码中对publishEvent实现的具体代码。

/**
* Publish the given event to all listeners.
* <p>Note: Listeners get initialized after the MessageSource, to be able
* to access it within listener implementations. Thus, MessageSource
* implementations cannot publish events.
* @param event the event to publish (may be application-specific or a
* standard framework event)
*/
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}
/**
* Return the internal ApplicationEventMulticaster used by the context.
* @return the internal ApplicationEventMulticaster (never {@code null})
* @throws IllegalStateException if the context has not been initialized yet
*/
private ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
if (this.applicationEventMulticaster == null) {
throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
"call 'refresh' before multicasting events via the context: " + this);
}
return this.applicationEventMulticaster;
}


大家应该发现了,就和我画的图一样,具体实现的是接口ApplicationEventMulticaster 。那么ApplicationEventMulticaster 接口的具体实现代码是什么呢?我们接着跟进,看看实现ApplicationEventMulticaster 接口中multicastEvent方法的具体类SimpleApplicationEventMulticaster的源代码。

package org.springframework.context.event;
import java.util.concurrent.Executor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

private Executor taskExecutor;

/**
* Create a new SimpleApplicationEventMulticaster.
*/
public SimpleApplicationEventMulticaster() {
}

/**
* Create a new SimpleApplicationEventMulticaster for the given BeanFactory.
*/
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}

/**
* Set the TaskExecutor to execute application listeners with.
* <p>Default is a SyncTaskExecutor, executing the listeners synchronously
* in the calling thread.
* <p>Consider specifying an asynchronous TaskExecutor here to not block the
* caller until all listeners have been executed. However, note that asynchronous
* execution will not participate in the caller's thread context (class loader,
* transaction association) unless the TaskExecutor explicitly supports this.
* @see org.springframework.core.task.SyncTaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
*/
public void setTaskExecutor(Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}

/**
* Return the current TaskExecutor for this multicaster.
*/
protected Executor getTaskExecutor() {
return this.taskExecutor;
}

@SuppressWarnings("unchecked")
public void multicastEvent(final ApplicationEvent event) {
for (final ApplicationListener listener : getApplicationListeners(event)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
public void run() {
listener.onApplicationEvent(event);
}
});
}
else {
listener.onApplicationEvent(event);
}
}
}

}


问题的关键到了,就是这个方法getApplicationListeners(final ApplicationEvent event),从方法的定义上就不难看出,这个方法是根据事件得到其所有监听器的集合。让我们继续跟进AbstractApplicationEventMulticaster类中的getApplicationListeners这个方法查看里面的奥秘。

/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
// 事件字节码(这里我们就是zhangsanEvent和WangwuEvent两个事件)
Class<? extends ApplicationEvent> eventType = event.getClass();
// 事件源信息的字节码(这里就是我们定义的两个事件的区别:eventName构造方法里面的source)
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
// ListenerCacheKey 保存上面的两个字节码信息
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Map<ListenerCacheKey, ListenerRetriever> retrieverCache将匹配过的事件与监听器对应关系保存在内种中作为缓存
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);// 这里是从内存的缓存中查找
if (retriever != null) {
return retriever.getApplicationListeners();
}
else {
// 第一次没有找到,就自己new一个ListenerRetriever来保存返回数据
retriever = new ListenerRetriever(true);
LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
Set<ApplicationListener> listeners;
Set<String> listenerBeans;
/**
* defaultRetriever默认监听器
* 在applicationContext容器初始化的时候就已经保存了
* 所有实现ApplicationListener或SmartApplicationListener接口listeners
* /
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
//遍历所有实现了ApplicationListener或SmartApplicationListener接口listeners
for (ApplicationListener listener : listeners) {
//supportsEvent(根据eventType和source,从listeners中筛选出符合条件的listener)
if (supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListeners.add(listener);
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
return allListeners;
}
}


在上面代码中有一个狠重要的方法supportsEvent,这个方法我说过是SmartApplicationListener接口定义的。这里如果用户自定义listener是直接实现该接口,那么这里就会调用用户自己的现实类;否则就会调用spring默认的,具体我们看抽象类AbstractApplicationEventMulticaster中supportsEvent方法的源代码说话。

/**
* Determine whether the given listener supports the given event.
* <p>The default implementation detects the {@link SmartApplicationListener}
* interface. In case of a standard {@link ApplicationListener}, a
* {@link GenericApplicationListenerAdapter} will be used to introspect
* the generically declared type of the target listener.
* @param listener the target listener to check
* @param eventType the event type to check against
* @param sourceType the source type to check against
* @return whether the given listener should be included in the
* candidates for the given event type
*/
protected boolean supportsEvent(
ApplicationListener listener, Class<? extends ApplicationEvent> eventType, Class sourceType) {
/**
* 从这行代码可以看出来,如果传进来的listener实现SmartApplicationListener的类,
* 那么就会调用其实现类的supportsEventType和supportsSourceType方法;
* 否则就会调用GenericApplicationListenerAdapter的supportsEventType和supportsSourceType方法
* /
SmartApplicationListener smartListener = (listener instanceof SmartApplicationListener ?
(SmartApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}


好,我们接着跟进查看Spring自己实现SmartApplicationListener接口的类GenericApplicationListenerAdapter,它的源代码。

package org.springframework.context.event;

import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;

public class GenericApplicationListenerAdapter implements SmartApplicationListener {

private final ApplicationListener delegate;

public GenericApplicationListenerAdapter(ApplicationListener delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = delegate;
}

@SuppressWarnings("unchecked")
public void onApplicationEvent(ApplicationEvent event) {
this.delegate.onApplicationEvent(event);
}
// 这里是仅支持事件调用方法的实现
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
//这里是获取listener中泛型定义的ApplicationEvent中指定delegate的字节码信息
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
// 判断是否是ApplicationEvent类
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
// 获取指定类继承的父类
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
if (targetClass != this.delegate.getClass()) {
// 这里是获取listener中泛型定义的ApplicationEvent中指定targetClass的字节码信息
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
}
}
/**
* isAssignableFrom用来判断一个类Class1和另一个类Class2是否相同
* 或者一个类class1是另一个类class2的超类或接口
* 注意调用顺序是class1.isAssignableFrom(class2)
*/
// null 表示没有泛型为任意类型
return (typeArg == null || typeArg.isAssignableFrom(eventType));
}
// 这里是仅支持事件源信息调用方法的实现
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}

public int getOrder() {
return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE);
}

}


好了,到了这里大家基本也都知道这份分发器原理了,这里说的主要是通过supportsEventType和supportsSourceType这两个方法,来判断什么样的ApplicationEvent用什么样的ApplicationListener来处理了。

Spring两种事件监听方式的实现示例?

1.首先,我自定义一个我们自己的事件父类IEvent

import org.springframework.context.ApplicationEvent;

/**
* @Description: 自定义事件父类,根据事件名称区别
* @author Yang Gao
* @date 2016-3-25 下午4:36:20
*
*/
public class IEvent extends ApplicationEvent {

private static final long serialVersionUID = -1130255953722074726L;

private String eventName;

public IEvent(String eventName) {
super(eventName);
this.eventName = eventName;
}

public String getEventName() {
return eventName;
}

}


2.然后在再定义两个不同的事件类,ZhangsanEvent和WangwuEvent

package com.gy.event;
/**
* @author Yang Gao
* @date 2016-3-25 下午4:44:57
*
*/
public class ZhangsanEvent extends IEvent {

private static final long serialVersionUID = 4328148476272415442L;

public ZhangsanEvent(String source) {
super(source);
}
}


package com.gy.event;
/**
* @author Yang Gao
* @date 2016-3-25 下午4:44:57
*
*/
public class WangwuEvent extends IEvent {

private static final long serialVersionUID = 4328148476272415442L;

public WangwuEvent(String source) {
super(source);
}
}


好了,我们来看一下具体的继承关系。



3.然后我们在定义自己的Listenter,这里我使用Spring的两种实现方式

package com.gy.listener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;
import com.gy.event.ZhangsanEvent;
/**
* @Description: 使用实现间接实现ApplicationListener的子接口SmartApplicationListener方式
* @author Yang Gao
* @date 2016-3-25 下午4:42:26
*
*/
public class ZhangsanListener implements SmartApplicationListener {

@Override
public void onApplicationEvent(ApplicationEvent event) {
ZhangsanEvent _event = (ZhangsanEvent)event;
System.out.println("ZhangsanListener Handle Event Name is " + _event.getEventName());

}

@Override
public int getOrder() {
return 0;
}

/*
* 决定监听器处理支持的事件类型
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ZhangsanEvent.class.isAssignableFrom(eventType);
}

/*
* 决定监听器处理支持的事件源类型
*/
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return Object.class.isAssignableFrom(sourceType);
}
}


package com.gy.listener;

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import com.gy.event.WangwuEvent;

/**
* @Description: 使用直接实现ApplicationListener方式,泛型指定监听的具体事件类型
* @author Yang Gao
* @date 2016-3-25 下午4:43:56
*
*/
public class WangwuListener implements ApplicationListener<WangwuEvent> {

@Override
public void onApplicationEvent(WangwuEvent event) {
System.out.println("WangwuListener Handle Event Name is " + event.getEventName());
}

}


4.然后咱在弄一个测试类SpringEventListenerTest

package com.gy.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import com.gy.event.WangwuEvent;
import com.gy.event.ZhangsanEvent;

/**
* @Description: 测试类
* @author Yang Gao
* @date 2016-3-25 下午4:35:30
*
*/

public class SpringEventListenerTest {

public static void main(String[] args) {
ApplicationContext springContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ZhangsanEvent zsEvent = new ZhangsanEvent("张三");
WangwuEvent wwEvent = new WangwuEvent("王五");
springContext.publishEvent(zsEvent);
springContext.publishEvent(wwEvent);

}

}


5.最后简单的applicationContext.xml配置文件,当然至于spring3.2.6的jar包,大家都自己动手去网上下载啦,我就不粘了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util">

<bean id="zhangsanListener" class="com.gy.listener.ZhangsanListener"/>
<bean id="wangwuListener" class="com.gy.listener.WangwuListener"/>

</beans>


6.好了,run一下,就结束了,让我们来看下结果。



补充

总之,这次学习,由于时间比较充足,所以也特意花时间来写博客记录下来供以后复习用。当然,收获也是挺多的,包括在写博客回顾一遍也有收获。另外,这在提醒自己,以后有时间了要去看看Spring加载ApplicaitonContext的全过程,这样也会加深自己对Ioc和Aop的理解,也能更进一步的学习JDK的反射(Reflect)机制和事件驱动模型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: