事件:定义事件类型和事件源,需要继承ApplicationEvent。
事件监听器:用来监听某一类的事件,并且执行具体业务逻辑,需要实现ApplicationListener 接口或者需要用@ListenerEvent(T)注解。好比观察者模式中的观察者。
事件多播器:负责广播通知所有监听器,所有的事件监听器都注册在了事件多播器中。好比观察者模式中的被观察者。Spring容器默认生成的是同步事件多播器。可以自定义事件多播器,定义为异步方式。
创建 AnnotationConfigApplicationContext 的过程中,会执行refresh()中的initApplicationEventMulticaster()方法。该方法先获取bean工厂,然后判断工厂是否包含了beanName 为 applicationEventMulticaster的bean。如果包含了,则获取该bean,赋值给applicationEventMulticaster 属性。如果没有,则创建一个 SimpleApplicationEventMulticaster 对象,并且赋值给 applicationEventMulticaster 。实现了源码如下:
监听器的注册有两种,通过实现 ApplicationListener接口或者添加@EventListener注解。
注册的逻辑实现在refresh()中的registerListeners()方法里面。第一步,先获取当前ApplicationContext中已经添加的 applicationListeners(SpringMVC源码中有用到),遍历添加到多播器中。第二步,获取实现了ApplicationListener接口的listenerBeanNames集合,添加至多播器中。第三步,判断是否有早期事件,如果有则发起广播。
思考一下,上面的代码中第二步为啥添加的是listenerBeanName?
如果监听器是懒加载的话(即有@Lazy 注解)。那么在这个时候创建监听器显然是不对的,这个时候不能创建监听器。所以添加监听器到多播器的具体逻辑放在初始化具体的监听器之后。通过 BeanPostProcessor 的接口实现。具体的实现类是 ApplicationListenerDetector 。这个类是在 refreah()中prepareBeanFactory()方法中添加的。代码如下:
在创建 AnnotationConfigApplicationContext 的构造方法中,会执行org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 方法。这个方法中会添加两个 beanDefs, 代码如下:
EventListenerMethodProcessor:事件监听器的BeanFactory后置处理器,在前期会创建 DefaultEventListenerFactory ,后期在创建好Bean之后,根据 EventListener 属性,调用DefaultEventListenerFactory创建具体的 ApplicationListenerMethodAdapter 。
DefaultEventListenerFactory:监听器的创建工厂,用来创建 ApplicationListenerMethodAdapter 。
EventListenerMethodProcessor 的类继承图如下:
在refreash的invokeBeanFactoryPostProcessors()中会调用 org.springframework.context.event.EventListenerMethodProcessor#postProcessBeanFactory方法,获取EventListenerFactory 类型的 Bean。代码如下:
在 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 方法中,创建完所有的单例Bean 之后,会遍历所有Bean是否实现了 SmartInitializingSingleton 接口。如果实现接口会执行该 Bean 的 afterSingletonsInstantiated() 方法。代码如下:
org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated 中会调用私有方法 processBean()进行 ApplicationEventAdatper 的创建。代码如下:
可以通过调用 org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType) 方法进行事件的调用。代码如下:
SimpleApplicationEventMulticaster 中的 multicasEvent,invokeListener,doInvokeListener 三个方法代码如下:
SpringMVC中就是通过Spring的事件机制进行九大组件的初始化。
监听器定义在FrameworkServlet类中,作为内部类。代码如下:
监听器的添加在org.springframework.web.servlet.FrameworkServlet#configureAndRefreshWebApplicationContext 中进行。通过SourceFilteringListener进行包装。添加代码如下:
在refresh中的registerListeners方法进行添加,代码如下:
在refresh中的finishRefresh()方法中,会调用publishEvnet(new ContextRefreshedEvent(this))发布事件。进行多播器广播,代码如下
最终会调到FrameworkServlet.this.onApplicationEvent(event)。
本地端口监听
import java.io.IOExceptionimport java.net.ServerSocket
import java.net.Socket
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
public class SocketServer
{
private ServerSocket serverSocket
private ExecutorService executorService// 线程池
private final int POOL_SIZE = 600// 单个CPU线程池大小
public SocketServer() throws IOException
{
serverSocket = new ServerSocket(9888)//监听的端口号
// Runtime的availableProcessor()方法返回当前系统的CPU数目.
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE)
System.out.println("服务器启动")
}
public void service()
{
while (true)
{
Socket socket = null
try
{
// 接收客户连接,只要客户进行了连接,就会触发accept()从而建立连接
socket = serverSocket.accept()
executorService.execute(new Handlers(socket))
//这里就是放业务逻辑的地方例如获取数据等等
} catch (Exception e)
{
e.printStackTrace()
System.out.println("socket Exception:" + e)
}
}
}
public static void main(String[] args) throws IOException
{
//Thread thread = new Thread(new PringtThread())
//thread.start()
new SocketServer().service()
}
}
端口扫描代码
import java.io.IOException
import java.net.Socketpublic class SearchPort implements Runnable
{
public static void main(String[] args)
{
SearchPort searchPort = new SearchPort()
Thread thread = new Thread(searchPort)
thread.start()
}
@Override
public void run()
{
searchPort("192.168.1.2", 0, 9999)
}
public void searchPort(String ip,int begin, int end) {
// 1-65535
Socket s = null
for (int i = begin i < end i++) {
boolean flag = false
try {
s = new Socket(ip, i)
flag = s.isConnected()
} catch (IOException e) {
// TODO Auto-generated catch block
// e.printStackTrace()
}
if (flag) {
System.out.println("port " + i + " is open")
try {
s.close()
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace()
}
} else {
// System.out.println("port " + i + " is close")
}
}
//System.out.println("seach port :" + begin + " to " + end + " ok..")
}
}
第一个端口监听的采用了线程池的技术,当大数据来的时候也不怕(某大型企业的部分源码),第二个例子是端口扫描器,采用了多线程扫描,代码直接复制就可以用的,从10点50分打代码11点半,不容易,望楼主采纳,有什么问题可以问我
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)