精华内容
下载资源
问答
  • 主要介绍了Spring ApplicationListener监听器用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 主要介绍了SpringMVC事件监听ApplicationListener实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 基于LUA的wireshark插件,利用listener搭建一个对esp协议包的包序号连续性检验的提示器
  • 监听器(Listener)的注册方法和 Servlet 一样,有两种方式:代码注册或者注解注册。接下来通过本文给大家介绍Spring Boot的listener(监听器)简单使用,需要的朋友可以参考下
  • 主要介绍了Java servlet、filter、listener、interceptor之间的区别和联系的相关资料,需要的朋友可以参考下
  • winform使用TcpClient/TcpListener类结合网络流建立多个客户机连接服务器程序,实现网络聊天通信的软件。程序比较完整,可以直接使用。
  • TcpListener服务器

    2016-09-20 09:12:23
    异步实现通讯,资源值10分
  • 详解JavaWeb中的 Listener

    2020-09-01 12:48:25
    JavaWeb里面的listener是通过观察者设计模式进行实现的。下面通过本文给大家详细介绍javaweb中的listener,感兴趣的朋友一起看看吧
  • TcpListener异步通信

    2017-06-16 11:50:16
    C#实现简易的tcp异步通信,可多客户端
  • 配置ORACLE的listener.ora、tnsnames.ora
  • 主要介绍了js HTML DOM EventListener功能与用法,结合实例形式分析了js HTML DOM EventListener事件监听相关用法及操作注意事项,需要的朋友可以参考下
  • 在开发中为控件添加Listener是非常常见的工作,最简单的添加Listener方式可以这样
  • TcpListener类与TcpClient类的使用
  • supervisor-event-listener Supervisor事件通知, 支持邮件, Slack, WebHook 简介 Supervisor是*nix环境下的进程管理工具, 可以把前台进程转换为守护进程, 当进程异常退出时自动重启. supervisor-event-listener监听...
  • 看看注释:由应用事件监听器实现的接口,基于观察者设计模式。 方法是处理应用事件。 /** 由应用事件监听器实现的接口,基于观察者设计模式 ... * Based on the standard {@code java.util.EventListener} int...

    看看注释:由应用事件监听器实现的接口,基于观察者设计模式。

    方法是处理应用事件。 

    /**
        由应用事件监听器实现的接口,基于观察者设计模式
     * 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);
    
    }

    一.ApplicationListener

    1.演示案例

        1)、写一个监听器(ApplicationListener实现类)来监听某个事件(ApplicationEvent及其子类
                  @EventListener;
                  原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener;
         2)、把监听器加入到容器;

    @Component
    public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
    
    	//当容器中发布此事件以后,方法触发
    	@Override
    	public void onApplicationEvent(ApplicationEvent event) {
    		// TODO Auto-generated method stub
    		System.out.println("收到事件:"+event);
    	}
    
    }
    

    3)单元测试:发布一个事件:    applicationContext.publishEvent();

    	@Test
    	public void test01(){
    		AnnotationConfigApplicationContext applicationContext  = new AnnotationConfigApplicationContext(ExtConfig.class);
    		
    		//发布事件;
    		applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) {
    		});
    		
    		applicationContext.close();
    	}

        4)、只要容器中有相关事件(ApplicationEvent)的发布,我们就能监听到这个事件;
                      ContextRefreshedEvent(ApplicationEvent的子类):容器刷新完成(所有bean都完全创建)会发布这个事件;
                      ContextClosedEvent(ApplicationEvent的子类):关闭容器会发布这个事件;

    以及监听到我们在单元测试,自定义发出的ApplicationEvent事件。

    2.事件发布监听原理

    在自定义监听器打断点

    看执行链

    容器的refresh方法:finishRefresh

    执行链一个个看,publishEvent(new ContextRefreshedEvent(this)); 发布了一个ContextRefreshedEvent

    说明容器刷新完成会发布ContextRefreshedEvent事件

    ContextRefreshedEvent是ApplicationEvent子类。

    publishEvent(Object event, ResolvableType eventType)来看看发布流程

    分两步

    • getApplicationEventMulticaster() 得到事件多播器
    • multicastEvent(applicationEvent, eventType) 传播事件

    multicastEvent方法中,得到listeners,然后遍历执行 invokeListener。

    这里如果execuror不为空,会采用线程异步执行invokeListener。

    invokeListener调用了doInvokeListener,最后直接调用listener的 onApplicationEvent方法

     

    这次ApplicationEvent事件是容器finishRefresh时发布的。 将这个断点放过,下一个ApplicationEvent事件是单元测试自定义发布的事件,可以看到发布流程是一样的执行链。

    再放过断点,最后还有一个ApplicationEvent事件,可以看到是关闭容器时发布的:

    单元测试调用 applicationContext.close();

    总结:

    1)、ContextRefreshedEvent事件:
           1)、容器创建对象:refresh();
           2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
       2)、自己发布事件;
       3)、容器关闭会发布ContextClosedEvent;

    【事件发布流程】:
           3)、publishEvent(new ContextRefreshedEvent(this));
                   1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
                   2)、multicastEvent派发事件:
                   3)、获取到所有的ApplicationListener;
                       for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
                       1)、如果有Executor,可以支持使用Executor进行异步派发;
                           Executor executor = getTaskExecutor();
                       2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);
                        拿到listener回调onApplicationEvent方法;

    3.事件多播器

    看看ApplicationEventMulticaster的由来,在容器的refresh方法中,有一步初始化容器事件多播器

    判断工厂中是否缓存了 applicationEventMulticaster 或者 有它的beanDefinition,如果有从工厂中获取或创建,

    如果没有则new 一个  SimpleApplicationEventMulticaster,并且注册到spring

    4.容器中的Listener

    在发布事件时,会得到事件对应的监听器,遍历调用监听方法。

    那listener从何处来?只要listener注入了容器,就可以通过BeanFactory得到。

    getApplicationListeners方法往进点,也可以看到从beanFactory中中获取。

    在容器refresh方法中有一个registerListeners,注册监听器,进去看看

    但看代码,并不是产生Listener的实例并注册到容器,而是得到Listener的bean名称,并让他们和多播器ApplicationEventMulticaster产生关联,把他们添加到多播器中。

    那Listener是何时创建并注册到容器中呢?可以写一个BeanPostProcessor 来测试一下。

    判断如果是Listener初始化时,就把beanName打印出来。

    @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof ApplicationListener)
                System.out.println("当前初始化的bean是"+beanName);
            return bean;
        }
    
    }

    打断点,看看执行流程:

    listener 是在refresh的finishBeanFactoryInitialization 创建的

     

    补充:

    在容器refresh的注册beanPostProcessor  registerBeanPostProcessors方法时,最后一步是注册一个ApplicationListenerDetector。

    ApplicationListenerDetector的初始化后置处理方法是判断bean是否实现 监听器接口,如果是,给ApplicatioContext的多播器添加上。

    二.@EventListener

    监听器有更方便的用法。

    1.演示案例

    写一个Userservice,在方法上标注@EventListener,属性是监听的事件Class。 

    如果监听到此事件Class,则会执行被注解的方法。

    @Service
    public class UserService {
    
    	@EventListener(classes={ApplicationEvent.class})
    	public void listen(ApplicationEvent event){
    		System.out.println("UserService。。监听到的事件:"+event);
    	}
    
    	@EventListener(classes = {Tom.class, Jerry.class})
    	public void tom(Object event){
    		System.out.println("tom---------------"+event);
    		if (event instanceof Tom){
    			System.out.println("tom");
    		}
    		if (event instanceof Jerry)
    			System.out.println("jerry");
    	}
    }

    事件类Tom继承ApplicationEvent

    public class Tom extends ApplicationEvent {
        /**
         * Create a new ApplicationEvent.
         *
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public Tom(Object source) {
            super(source);
        }
    }

    事件类Jerry

    public class Jerry {
    }
    

     单元测试

    	@Test
    	public void test01(){
    		AnnotationConfigApplicationContext applicationContext  = new AnnotationConfigApplicationContext(ExtConfig.class);
    		
    
        	//发布事件;
    		applicationContext.publishEvent(new ApplicationEvent(new String("我发布的时间")) {
    		});
    
    		applicationContext.publishEvent(new Jerry());
    		applicationContext.publishEvent(new Tom(new String("hi tom")));
    		
    		applicationContext.close();
    	}

     applicationContext.publishEvent是个重载方法,参数是ApplicationEvent 和Object都可以

    	@Override
    	public void publishEvent(ApplicationEvent event) {
    		publishEvent(event, null);
    	}
    
    	@Override
    	public void publishEvent(Object event) {
    		publishEvent(event, null);
    	}

     发布的ApplicationEvent事件,只有监听ApplicationEvent.class的方法能收到。

    发布的Tom事件,监听Tom 和 ApplicationEvent 的方法都能收到。

    发布的Jerry事件,只有监听Jerry的方法能收到。

    2.原理

    EventListenr注释了EventListenerMethodProcessor

    EventListenerMethodProcessor实现了SmartInitializingSingleton 接口

    SmartInitializingSingleton接口

    关键在SmartInitializingSingleton接口,看注释,当所有单实例创建完成后,调用afterSingletonsInstantiated方法。

    如何保证容器中所有的单实例创建完成后,会执行实现SmartInitializingSingleton接口实例的afterSingletonsInstantiated方法?

    答案在容器refresh方法的最后一步,finishBeanFactoryInitialization方法中的beanFactory.preInstantiateSingletons() (创建剩余的单实例);

    先遍历beanNames,去创建实例,创建完成后又遍历beanNames,判断实例是否实现SmartInitializingSingleton接口,实现则执行实例的afterSingletonsInstantiated方法

     

    回到EventListenerMethodProcessor

    在EventListenerMethodProcessor的afterSingletonsInstantiated方法打断点

    内容是遍历容器所有beanNames,因为我们在UserService类上加了@EventListener注解,所以把beanName遍历到userService看如何执行的。

    通过beanName尝试找到 bean对应的Class, AutoProxyUtils.determineTargetClass(this.applicationContext.getBeanFactory(), beanName);

    执行到processBean

    this.nonAnnotatedClasses.contains(targetType) :判断targetType 代表的Class 是否标注了注解。

    annotatedMethods = MethodIntrospector.selectMethods : 得到targetType 中被注解的方法, UserService类有Listen和tom方法被注解

    如果当前beanName代表的类targetype上没有注解,就加入到nonAnnotatedClasses,图中遍历的是自定义的Blue类,没有注解。

    每个带@EventListener方法就会创建一个ApplicationListener对象

    接着上面,得到所有遍历注解的方法后, 遍历

    factory.supportsMethod(method) :看 EventListenerFactory 是否支持这个方法

    ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse)

    如果支持就用 EventListenerFactory 创建一个 ApplicationListener ,如果创建出来是 ApplicationListenerMethodAdapter适配器,就再初始化一下,总之得到一个ApplicationListener

    ApplicationListenerMethodAdapter是 ApplicationListener的子类。

    this.applicationContext.addApplicationListener(applicationListener): 把创建的ApplicationListener加入到了 容器中!

    如何加入容器? 其实是加到了多播器中 applicationEventMulticaster

     

    总结下:方法如果注解了@EventListener,就会对用创建一个ApplicationListener 或者是ApplicationListenerAdpter加入到applicationEventMulticaster中。UserService有两个方法都标了注解,就创建了两个监听器。

     

    发布事件如何找到对应的监听方法

    虽然创建了监听器,之前也讲过可以通过 事件寻找到订阅它的监听器,但在发布事件时是如何调用到UserService的方法的,毕竟执行方法还是在UserService,并不是在ApplicationListener,而且看断点信息创建的ApplicationListener并不是一个代理对象拥有对应的UserService的方法。

    把断点打到UseService的两个监听方法上

    看执行流程,最前面几步还是 发布事件---从多播器找监听器---执行监听方法 onApplicationEvent

    从onApplicationEvent方法开始不同,如果我们自定义实现 ApplicationListener 接口,则从这一步会直接执行我们自定义的方法。

    但现在用的@EventListener注解,看断点目前执行到的是 ApplicationListenerMethodAdapter,一个监听适配器,在为监听注解方法创建 监听器时 创建的就是这个 监听适配器。 

    执行监听方法,ApplicationListenerMethodAdapter.onApplicationEvent 调用的是 processEvent(event);

    重点来了,在 processEvent让断点进来。

    Object[] args = resolveArguments(event):解析事件对象,得到事件的负载核和一些信息

    shouldHandle判断是否应该处理。

    doInvoke 通过事件信息得到了 事件对应的标注@EventListener 的userService实例.

    原来是通过beanName寻找在容器中的 实例,因为创建ApplicationListener时保存了 对应方法类的信息。通过userService的beanName找到了userService实例。

    this.bridgedMethod.invoke(bean, args);通过反射调用了 userService中的监听方法。

     

     

    三.总结

    • 自定义实现ApplicationListener接口的流程:发布事件时,通过此事件找到 多播器、找订阅它的监听器,然后执行监听方法。
    • 如果用@EventListener注解,则发布事件时找到是监听适配器(ApplicationListenerAdpter),监听适配器是监听器的子类,在创建ApplicationListenerAdpter时,其中保存了注解@EventListene的bean的信息,然后通过监听适配器从容器中找到对应bean,再执行bean中的监听方法。
    展开全文
  • listener-tnsname

    2017-09-09 15:25:02
    listener-tnsnamelistener-tnsnamelistener-tnsnamelistener-tnsnamelistener-tnsnamelistener-tnsnamelistener-tnsnamelistener-tnsname
  • Aynchronous TCPListener 异步 server和client学习资源。可以借鉴
  • C# TcpListener/TcpClient Demo
  • 文章目录 概述 Spring-kafka生产者源码流程 Spring-kafka消费者源码流程(`@EnableKafka`和`@KafkaListener` ) Flow KafkaListenerAnnotationBeanPostProcessor 概述 【依赖】 <dependency> <groupId>org....


    在这里插入图片描述


    概述

    【依赖】

    	<dependency>
    			<groupId>org.springframework.kafka</groupId>
    			<artifactId>spring-kafka</artifactId>
    	</dependency>
    

    【配置】

    #kafka
    spring.kafka.bootstrap-servers=10.11.114.247:9092
    spring.kafka.producer.acks=1
    spring.kafka.producer.retries=3
    spring.kafka.producer.batch-size=16384
    spring.kafka.producer.buffer-memory=33554432
    spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
    spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
    
    
    spring.kafka.consumer.group-id=zfprocessor_group
    spring.kafka.consumer.enable-auto-commit=false
    spring.kafka.consumer.auto-offset-reset=earliest
    spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
    spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
    spring.kafka.consumer.properties.spring.json.trusted.packages=com.artisan.common.entity.messages
    spring.kafka.consumer.max-poll-records=500
    spring.kafka.consumer.fetch-min-size=10
    spring.kafka.consumer.fetch-max-wait=10000ms
    
    spring.kafka.listener.missing-topics-fatal=false
    spring.kafka.listener.type=batch
    spring.kafka.listener.ack-mode=manual
    
    
    logging.level.org.springframework.kafka=ERROR
    logging.level.org.apache.kafka=ERROR
    

    Spring-kafka生产者源码流程

    ListenableFuture<SendResult<Object, Object>> result = kafkaTemplate.send(TOPICA.TOPIC, messageMock);
    

    主要的源码流程如下

    在这里插入图片描述


    Spring-kafka消费者源码流程(@EnableKafka@KafkaListener

    消费的话,比较复杂

     @KafkaListener(topics = TOPICA.TOPIC ,groupId = CONSUMER_GROUP_PREFIX + TOPICA.TOPIC)
        public void onMessage(MessageMock messageMock){
            logger.info("【接受到消息][线程:{} 消息内容:{}]", Thread.currentThread().getName(), messageMock);
        }
    

    划重点,主要关注

    在这里插入图片描述


    Flow

    在这里插入图片描述

    作为引子,我们继续来梳理下源码

    在这里插入图片描述

    继续

    在这里插入图片描述
    继续

    在这里插入图片描述
    KafkaBootstrapConfiguration的主要功能是创建两个bean

    KafkaListenerAnnotationBeanPostProcessor

    实现了如下接口

    implements BeanPostProcessor, Ordered, BeanFactoryAware, SmartInitializingSingleton
    

    主要功能就是监听@KafkaListener注解 。 bean的后置处理器 需要重写 postProcessAfterInitialization

    @Override
    	public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
    		if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
    		   // 获取对应的class
    			Class<?> targetClass = AopUtils.getTargetClass(bean);
    			// 查找类是否有@KafkaListener注解
    			Collection<KafkaListener> classLevelListeners = findListenerAnnotations(targetClass);
    			final boolean hasClassLevelListeners = classLevelListeners.size() > 0;
    			final List<Method> multiMethods = new ArrayList<>();
    			// 查找类中方法上是否有对应的@KafkaListener注解,
    			Map<Method, Set<KafkaListener>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
    					(MethodIntrospector.MetadataLookup<Set<KafkaListener>>) method -> {
    						Set<KafkaListener> listenerMethods = findListenerAnnotations(method);
    						return (!listenerMethods.isEmpty() ? listenerMethods : null);
    					});
    			if (hasClassLevelListeners) {
    				Set<Method> methodsWithHandler = MethodIntrospector.selectMethods(targetClass,
    						(ReflectionUtils.MethodFilter) method ->
    								AnnotationUtils.findAnnotation(method, KafkaHandler.class) != null);
    				multiMethods.addAll(methodsWithHandler);
    			}
    			if (annotatedMethods.isEmpty()) {
    				this.nonAnnotatedClasses.add(bean.getClass());
    				this.logger.trace(() -> "No @KafkaListener annotations found on bean type: " + bean.getClass());
    			}
    			else {
    				// Non-empty set of methods
    				for (Map.Entry<Method, Set<KafkaListener>> entry : annotatedMethods.entrySet()) {
    					Method method = entry.getKey();
    					for (KafkaListener listener : entry.getValue()) {
    						// 处理@KafkaListener注解   重点看 
    						processKafkaListener(listener, method, bean, beanName);
    					}
    				}
    				this.logger.debug(() -> annotatedMethods.size() + " @KafkaListener methods processed on bean '"
    							+ beanName + "': " + annotatedMethods);
    			}
    			if (hasClassLevelListeners) {
    				processMultiMethodListeners(classLevelListeners, multiMethods, bean, beanName);
    			}
    		}
    		return bean;
    	}
    
    

    重点方法

    	protected void processKafkaListener(KafkaListener kafkaListener, Method method, Object bean, String beanName) {
    		Method methodToUse = checkProxy(method, bean);
    		MethodKafkaListenerEndpoint<K, V> endpoint = new MethodKafkaListenerEndpoint<>();
    		endpoint.setMethod(methodToUse);
    		processListener(endpoint, kafkaListener, bean, methodToUse, beanName);
    	}
    

    继续 processListener

    protected void processListener(MethodKafkaListenerEndpoint<?, ?> endpoint, KafkaListener kafkaListener,
    			Object bean, Object adminTarget, String beanName) {
    
    		String beanRef = kafkaListener.beanRef();
    		if (StringUtils.hasText(beanRef)) {
    			this.listenerScope.addListener(beanRef, bean);
    		}
    		// 构建 endpoint
    		endpoint.setBean(bean);
    		endpoint.setMessageHandlerMethodFactory(this.messageHandlerMethodFactory);
    		endpoint.setId(getEndpointId(kafkaListener));
    		endpoint.setGroupId(getEndpointGroupId(kafkaListener, endpoint.getId()));
    		endpoint.setTopicPartitions(resolveTopicPartitions(kafkaListener));
    		endpoint.setTopics(resolveTopics(kafkaListener));
    		endpoint.setTopicPattern(resolvePattern(kafkaListener));
    		endpoint.setClientIdPrefix(resolveExpressionAsString(kafkaListener.clientIdPrefix(), "clientIdPrefix"));
    		String group = kafkaListener.containerGroup();
    		if (StringUtils.hasText(group)) {
    			Object resolvedGroup = resolveExpression(group);
    			if (resolvedGroup instanceof String) {
    				endpoint.setGroup((String) resolvedGroup);
    			}
    		}
    		String concurrency = kafkaListener.concurrency();
    		if (StringUtils.hasText(concurrency)) {
    			endpoint.setConcurrency(resolveExpressionAsInteger(concurrency, "concurrency"));
    		}
    		String autoStartup = kafkaListener.autoStartup();
    		if (StringUtils.hasText(autoStartup)) {
    			endpoint.setAutoStartup(resolveExpressionAsBoolean(autoStartup, "autoStartup"));
    		}
    		resolveKafkaProperties(endpoint, kafkaListener.properties());
    		endpoint.setSplitIterables(kafkaListener.splitIterables());
    
    		KafkaListenerContainerFactory<?> factory = null;
    		String containerFactoryBeanName = resolve(kafkaListener.containerFactory());
    		if (StringUtils.hasText(containerFactoryBeanName)) {
    			Assert.state(this.beanFactory != null, "BeanFactory must be set to obtain container factory by bean name");
    			try {
    				factory = this.beanFactory.getBean(containerFactoryBeanName, KafkaListenerContainerFactory.class);
    			}
    			catch (NoSuchBeanDefinitionException ex) {
    				throw new BeanInitializationException("Could not register Kafka listener endpoint on [" + adminTarget
    						+ "] for bean " + beanName + ", no " + KafkaListenerContainerFactory.class.getSimpleName()
    						+ " with id '" + containerFactoryBeanName + "' was found in the application context", ex);
    			}
    		}
    
    		endpoint.setBeanFactory(this.beanFactory);
    		String errorHandlerBeanName = resolveExpressionAsString(kafkaListener.errorHandler(), "errorHandler");
    		if (StringUtils.hasText(errorHandlerBeanName)) {
    			endpoint.setErrorHandler(this.beanFactory.getBean(errorHandlerBeanName, KafkaListenerErrorHandler.class));
    		}
    		// 将endpoint注册到registrar
    		this.registrar.registerEndpoint(endpoint, factory);
    		if (StringUtils.hasText(beanRef)) {
    			this.listenerScope.removeListener(beanRef);
    		}
    	}
    

    继续看 registerEndpoint

    	public void registerEndpoint(KafkaListenerEndpoint endpoint, KafkaListenerContainerFactory<?> factory) {
    		Assert.notNull(endpoint, "Endpoint must be set");
    		Assert.hasText(endpoint.getId(), "Endpoint id must be set");
    		// Factory may be null, we defer the resolution right before actually creating the container
    		// 把endpoint封装为KafkaListenerEndpointDescriptor
    		KafkaListenerEndpointDescriptor descriptor = new KafkaListenerEndpointDescriptor(endpoint, factory);
    		synchronized (this.endpointDescriptors) {
    			if (this.startImmediately) { // Register and start immediately
    				this.endpointRegistry.registerListenerContainer(descriptor.endpoint,
    						resolveContainerFactory(descriptor), true);
    			}
    			else {
    			   // 将descriptor添加到endpointDescriptors
    				this.endpointDescriptors.add(descriptor);
    			}
    		}
    	}
    
    

    总的来看: 得到一个含有KafkaListener基本信息的Endpoint,将Endpoint被封装到KafkaListenerEndpointDescriptor,KafkaListenerEndpointDescriptor被添加到KafkaListenerEndpointRegistrar.endpointDescriptors中,至此这部分的流程结束了,感觉没有下文呀。

    在这里插入图片描述


    KafkaListenerEndpointRegistrar.endpointDescriptors 这个List中的数据怎么用呢?

    public class KafkaListenerEndpointRegistrar implements BeanFactoryAware, InitializingBean {}
    
    

    KafkaListenerEndpointRegistrar 实现了 InitializingBean 接口,重写 afterPropertiesSet,该方法会在bean实例化完成后执行

    	@Override
    	public void afterPropertiesSet() {
    		registerAllEndpoints();
    	}
    

    继续 registerAllEndpoints();

    	protected void registerAllEndpoints() {
    		synchronized (this.endpointDescriptors) {
    		// 遍历KafkaListenerEndpointDescriptor 
    			for (KafkaListenerEndpointDescriptor descriptor : this.endpointDescriptors) {
    			   	// 注册 
    				this.endpointRegistry.registerListenerContainer(
    						descriptor.endpoint, resolveContainerFactory(descriptor));
    			}
    			this.startImmediately = true;  // trigger immediate startup
    		}
    	}
    

    继续

    	public void registerListenerContainer(KafkaListenerEndpoint endpoint, KafkaListenerContainerFactory<?> factory) {
    		registerListenerContainer(endpoint, factory, false);
    	}
    
    

    go

    public void registerListenerContainer(KafkaListenerEndpoint endpoint, KafkaListenerContainerFactory<?> factory,
    			boolean startImmediately) {
    
    		Assert.notNull(endpoint, "Endpoint must not be null");
    		Assert.notNull(factory, "Factory must not be null");
    
    		String id = endpoint.getId();
    		Assert.hasText(id, "Endpoint id must not be empty");
    		synchronized (this.listenerContainers) {
    			Assert.state(!this.listenerContainers.containsKey(id),
    					"Another endpoint is already registered with id '" + id + "'");   
    	      // 创建Endpoint对应的MessageListenerContainer,将创建好的MessageListenerContainer放入listenerContainers
    			MessageListenerContainer container = createListenerContainer(endpoint, factory);
    			this.listenerContainers.put(id, container);
    			// 如果KafkaListener注解中有对应的group信息,则将container添加到对应的group中
    			if (StringUtils.hasText(endpoint.getGroup()) && this.applicationContext != null) {
    				List<MessageListenerContainer> containerGroup;
    				if (this.applicationContext.containsBean(endpoint.getGroup())) {
    					containerGroup = this.applicationContext.getBean(endpoint.getGroup(), List.class);
    				}
    				else {
    					containerGroup = new ArrayList<MessageListenerContainer>();
    					this.applicationContext.getBeanFactory().registerSingleton(endpoint.getGroup(), containerGroup);
    				}
    				containerGroup.add(container);
    			}
    			if (startImmediately) {
    				startIfNecessary(container);
    			}
    		}
    	}
    
    

    在这里插入图片描述

    展开全文
  • Oracle_LISTENER监听文件参数详解及Lsnrctl命令综述
  • ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听...

    ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。

    Spring提供的内置事件:

    • ContextRefreshedEvent

    • ContextStartedEvent

    • ContextStoppedEvent

    • ContextClosedEvent

    如何使用

    监听容器的刷新与关闭事件

    自定义一个ApplicationListener:

    package com.morris.spring.listener;
    
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    
    public class ContextRefreshedListenerimplements ApplicationListener<ContextRefreshedEvent> {
    
    	@Override
    	public void onApplicationEvent(ContextRefreshedEvent event) {
    		System.out.println("context refresh");
    	}
    }
    

    注入到容器中:

    package com.morris.spring.demo.annotation;
    
    import com.morris.spring.listener.ContextRefreshedApplicationListener;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class ContextRefreshedApplicationListenerDemo {
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    		applicationContext.register(ContextRefreshedListener.class);
    		applicationContext.refresh();
    	}
    }
    

    自定义监听事件

    自定义的监听事件需要继承ApplicationEvent:

    package com.morris.spring.event;
    
    import org.springframework.context.ApplicationEvent;
    
    public class CustomEvent extends ApplicationEvent {
    
    	private static final long serialVersionUID = 1L;
    
    	public CustomEvent(Object source) {
    		super(source);
    	}
    }
    

    监听的时候使用ApplicationEvent的子类CustomEvent:

    package com.morris.spring.listener;
    
    import com.morris.spring.event.CustomEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    
    public class CustomEventListener implements ApplicationListener<CustomEvent> {
    
    	@Override
    	public void onApplicationEvent(CustomEvent event) {
    		System.out.println("custom event: " + event.getSource());
    	}
    }
    

    可以使用AnnotationConfigApplicationContext发布事件:

    package com.morris.spring.demo.annotation;
    
    import com.morris.spring.event.CustomEvent;
    import com.morris.spring.listener.CustomEventListener;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class CustomEventListenerDemo {
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
    		applicationContext.register(CustomEventListener.class);
    		applicationContext.refresh();
    
    		applicationContext.publishEvent(new CustomEvent("自定义事件"));
    	}
    }
    

    可以向bean中注入一个ApplicationEventPublisher来发布事件:

    package com.morris.spring.service;
    
    import com.morris.spring.event.CustomEvent;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationEventPublisher;
    
    public class CustomEventService {
    
    	@Autowired
    	private ApplicationEventPublisher applicationEventPublisher;
    
    	public void publishEvent() {
    		applicationEventPublisher.publishEvent(new CustomEvent("自定义事件"));
    	}
    }
    

    可以通过实现ApplicationEventPublisherAware接口注入ApplicationEventPublisher来发布事件:

    package com.morris.spring.service;
    
    import com.morris.spring.event.CustomEvent;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationEventPublisherAware;
    
    public class CustomEventService2 implements ApplicationEventPublisherAware {
    
    	private ApplicationEventPublisher applicationEventPublisher;
    
    	public void publishEvent() {
    		applicationEventPublisher.publishEvent(new CustomEvent("自定义事件"));
    	}
    
    	@Override
    	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    		this.applicationEventPublisher = applicationEventPublisher;
    	}
    }
    

    由于ApplicationContext实现了ApplicationEventPublisher接口,也可以直接注入ApplicationContext来发布事件。

    使用@EventListener监听事件

    由于实现ApplicationListener接口有很大的侵入性,可以使用@EventListener注解随时随地监听事件,这样一个Service中可以监听多个事件:

    package com.morris.spring.listener;
    
    import com.morris.spring.event.CustomEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.context.event.EventListener;
    
    public class CustomEventListener2 {
    
    	@EventListener
    	public void listenContextRefreshedEvent(ContextRefreshedEvent event) {
    		System.out.println("context refresh");
    	}
    
    	@EventListener
    	public void listenCustomEvent(CustomEvent event) {
    		System.out.println("custom event: " + event.getSource());
    	}
    
    }
    

    还可以指定监听的事件类型:

    package com.morris.spring.listener;
    
    import com.morris.spring.event.CustomEvent;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.context.event.EventListener;
    
    public class CustomEventListener3 {
    
    	@EventListener({ContextRefreshedEvent.class, CustomEvent.class})
    	public void listenEvent(ApplicationEvent event) {
    		System.out.println(event);
    	}
    }
    
    

    异步发送消息

    消息的发送默认都是同步的,如果要异步发送消息,首先要在配置类上开启异步功能@EnableAsync:

    package com.morris.spring.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @Configuration
    @EnableAsync // 开启异步
    public class EventListenerConfig {
    }
    

    在监听的方法上加上@Async:

    package com.morris.spring.listener;
    
    import com.morris.spring.event.CustomEvent;
    import org.springframework.context.ApplicationEvent;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.context.event.EventListener;
    import org.springframework.scheduling.annotation.Async;
    
    public class AsyncCustomEventListener {
    	@EventListener({ContextRefreshedEvent.class, CustomEvent.class})
    	@Async // 异步
    	public void listenEvent(ApplicationEvent event) {
    		System.out.println(Thread.currentThread().getName());
    		System.out.println(event);
    	}
    }
    

    也可以自定义执行异步消息的线程池(默认就是SimpleAsyncTaskExecutor):

    @Bean
    public TaskExecutor executor() {
    	return new SimpleAsyncTaskExecutor("eventListen-");
    }
    

    ApplicationListener原理分析

    发布消息

    发布消息入口:

    // org.springframework.context.support.AbstractApplicationContext#publishEvent(org.springframework.context.ApplicationEvent)
    public void publishEvent(ApplicationEvent event) {
        publishEvent(event, null);
    }
    
    protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    ...
            /**
             * @see SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
             */
            // 发布消息
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }
    ... ...
    }
    

    然后调用SimpleApplicationEventMulticaster来进行广播消息:

    // org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        // 如果有线程池,将会异步执行
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
    
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                doInvokeListener(listener, event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            // ApplicationListener.调用onApplicationEvent
            doInvokeListener(listener, event);
        }
    }
    
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }
    

    何时注入SimpleApplicationEventMulticaster

    从上面的源码可以发现spring是通过SimpleApplicationEventMulticaster事件多播器来发布消息的,那么这个类是何时注入的呢?

    // org.springframework.context.support.AbstractApplicationContext#initApplicationEventMulticaster
    protected void initApplicationEventMulticaster() {
    	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    	if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
    		this.applicationEventMulticaster =
    				beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    		if (logger.isTraceEnabled()) {
    			logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    		}
    	}
    	else {
    		// 直接new,然后放入到spring一级缓存中
    		this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    		beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    		if (logger.isTraceEnabled()) {
    			logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
    					"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
    		}
    	}
    }
    

    何时注入ApplicationListener

    spring在发布消息时,会从SimpleApplicationEventMulticaster中拿出所有的ApplicationListener,那么这些ApplicationListener何时被注入的呢?

    // org.springframework.context.support.AbstractApplicationContext#registerListeners
    protected void registerListeners() {
    	// Register statically specified listeners first.
    	for (ApplicationListener<?> listener : getApplicationListeners()) {
    		getApplicationEventMulticaster().addApplicationListener(listener);
    	}
    
    	// Do not initialize FactoryBeans here: We need to leave all regular beans
    	// uninitialized to let post-processors apply to them!
    	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    	for (String listenerBeanName : listenerBeanNames) {
    		// 添加到SimpleApplicationEventMulticaster中
    		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    	}
    
    	// Publish early application events now that we finally have a multicaster...
    	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    	this.earlyApplicationEvents = null;
    	if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
    		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
    			getApplicationEventMulticaster().multicastEvent(earlyEvent);
    		}
    	}
    }
    

    EventListenerMethodProcessor何时被注入

    @EventListener的原理

    @EventListener的功能是通过EventListenerMethodProcessor来实现的,在注解扫描时被注AnnotationConfigUtils#registerAnnotationConfigProcessors()。

    EventListenerMethodProcessor主要实现了两个接口:SmartInitializingSingleton和BeanFactoryPostProcessor

    先来看看BeanFactoryPostProcessor的postProcessBeanFactory(),这个方法主要是保存beanFactory和eventListenerFactories,后面的方法将会使用到:

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 保存beanFactory
        this.beanFactory = beanFactory;
    
        /**
         * EventListenerFactory[DefaultEventListenerFactory]在何处被注入?
         * @see AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
         */
        Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
        List<EventListenerFactory> factories = new ArrayList<>(beans.values());
        AnnotationAwareOrderComparator.sort(factories);
        // 保存eventListenerFactories
        this.eventListenerFactories = factories;
    }
    

    再来看看SmartInitializingSingleton的afterSingletonsInstantiated()方法,这个方法会在所有的bean初始化完后执行。

    public void afterSingletonsInstantiated() {
        ConfigurableListableBeanFactory beanFactory = this.beanFactory;
        Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
        String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
        for (String beanName : beanNames) {
            if (!ScopedProxyUtils.isScopedTarget(beanName)) {
                Class<?> type = null;
                try {
                    type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                if (type != null) {
                    if (ScopedObject.class.isAssignableFrom(type)) {
                        try {
                            Class<?> targetClass = AutoProxyUtils.determineTargetClass(
                                    beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
                            if (targetClass != null) {
                                type = targetClass;
                            }
                        }
                        catch (Throwable ex) {
                            // An invalid scoped proxy arrangement - let's ignore it.
                            if (logger.isDebugEnabled()) {
                                logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
                            }
                        }
                    }
                    try {
                        processBean(beanName, type);
                    }
                    catch (Throwable ex) {
                        throw new BeanInitializationException("Failed to process @EventListener " +
                                "annotation on bean with name '" + beanName + "'", ex);
                    }
                }
            }
        }
    }
    
    private void processBean(final String beanName, final Class<?> targetType) {
        if (!this.nonAnnotatedClasses.contains(targetType) &&
                !targetType.getName().startsWith("java") &&
                !isSpringContainerClass(targetType)) {
    
            Map<Method, EventListener> annotatedMethods = null;
            try {
                annotatedMethods = MethodIntrospector.selectMethods(targetType,
                        (MethodIntrospector.MetadataLookup<EventListener>) method ->
                                AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
            }
            catch (Throwable ex) {
                // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
                }
            }
    
            if (CollectionUtils.isEmpty(annotatedMethods)) {
                this.nonAnnotatedClasses.add(targetType);
                if (logger.isTraceEnabled()) {
                    logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
                }
            }
            else {
                // Non-empty set of methods
                ConfigurableApplicationContext context = this.applicationContext;
                Assert.state(context != null, "No ApplicationContext set");
                List<EventListenerFactory> factories = this.eventListenerFactories;
                Assert.state(factories != null, "EventListenerFactory List not initialized");
                for (Method method : annotatedMethods.keySet()) {
                    for (EventListenerFactory factory : factories) {
                        if (factory.supportsMethod(method)) {
                            Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
                            // 使用factory创建一个ApplicationListener
                            ApplicationListener<?> applicationListener =
                                    factory.createApplicationListener(beanName, targetType, methodToUse);
                            if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                                ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                            }
                            // 添加至容器中
                            context.addApplicationListener(applicationListener);
                            break;
                        }
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                            beanName + "': " + annotatedMethods);
                }
            }
        }
    }
    
    展开全文
  • 使用netca配置listener

    千次阅读 2019-09-06 14:11:14
    概述 netca的功能是配置网络相关服务,...数据库安装完成后,发现没有配置listener。 $ lsnrctl status LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 06-SEP-2019 06:10:41 Copyright (c) 1991, 2016, ...

    概述

    netca的功能是配置网络相关服务,其中最重要的就是监听和网络服务名称配置(tnsnames.ora)

    数据库安装完成后,发现没有配置listener。

    $ lsnrctl status
    
    LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 06-SEP-2019 06:10:41
    
    Copyright (c) 1991, 2016, Oracle.  All rights reserved.
    
    Connecting to (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
    TNS-12541: TNS:no listener
     TNS-12560: TNS:protocol adapter error
      TNS-00511: No listener
       Linux Error: 111: Connection refused
    
    

    虽然不影响OS认证,但网络登录就不行了。例如:

    # OS authentication OK
    $ sqlplus / as sysdba
    
    SQL*Plus: Release 12.2.0.1.0 Production on Fri Sep 6 06:11:29 2019
    
    Copyright (c) 1982, 2016, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
    
    SQL> exit
    Disconnected from Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
    
    # easy connect FAILED
    $ sqlplus sys/Welcome1@127.0.0.1:1521/orcl as sysdba
    
    SQL*Plus: Release 12.2.0.1.0 Production on Fri Sep 6 06:12:04 2019
    
    Copyright (c) 1982, 2016, Oracle.  All rights reserved.
    
    ERROR:
    ORA-12541: TNS:no listener
    
    
    Enter user-name:
    
    
    

    监听(listener)的配置

    图形方式

    以下用netca GUI配置:
    在这里插入图片描述
    在这里插入图片描述
    默认名称为LISTENER:
    在这里插入图片描述
    协议为TCP:
    在这里插入图片描述
    默认端口为1521:
    在这里插入图片描述
    在上面这步,如果报端口已使用,有可能是主机解析配置不正确:
    在这里插入图片描述

    例如以下是主机解析文件,出错时的配置被注释了,改为最后那行就通过了:

    $ cat /etc/hosts
    #127.0.0.1      ol7-vagrant     ol7-vagrant
    10.0.2.15       ol7-vagrant
    
    

    在这里插入图片描述

    完成:
    在这里插入图片描述
    以下为安装日志:

    [oracle@ol7-vagrant admin]$ netca
    
    Oracle Net Services Configuration:
    Configuring Listener:LISTENER
    Listener configuration complete.
    Oracle Net Listener Startup:
        Running Listener Control:
          /u01/app/oracle/product/12.2.0.1/dbhome_1/bin/lsnrctl start LISTENER
        Listener Control complete.
        Listener started successfully.
    Oracle Net Services configuration successful. The exit code is 0
    
    

    配置完后监听自动启动:

    $ lsnrctl status
    
    LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 06-SEP-2019 06:30:20
    
    Copyright (c) 1991, 2016, Oracle.  All rights reserved.
    
    Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=ol7-vagrant)(PORT=1521)))
    STATUS of the LISTENER
    ------------------------
    Alias                     LISTENER
    Version                   TNSLSNR for Linux: Version 12.2.0.1.0 - Production
    Start Date                06-SEP-2019 06:26:03
    Uptime                    0 days 0 hr. 4 min. 16 sec
    Trace Level               off
    Security                  ON: Local OS Authentication
    SNMP                      OFF
    Listener Parameter File   /u01/app/oracle/product/12.2.0.1/dbhome_1/network/admin/listener.ora
    Listener Log File         /u01/app/oracle/diag/tnslsnr/ol7-vagrant/listener/alert/log.xml
    Listening Endpoints Summary...
      (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=ol7-vagrant)(PORT=1521)))
      (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
    Services Summary...
    Service "91dd388726f468cde0530100007f7576" has 1 instance(s).
      Instance "orcl", status READY, has 1 handler(s) for this service...
    Service "orcl" has 1 instance(s).
      Instance "orcl", status READY, has 1 handler(s) for this service...
    Service "orclXDB" has 1 instance(s).
      Instance "orcl", status READY, has 1 handler(s) for this service...
    Service "orclpdb" has 1 instance(s).
      Instance "orcl", status READY, has 1 handler(s) for this service...
    The command completed successfully
    
    

    配置文件如下:

    $ cd $ORACLE_HOME/network/admin
    
    $ ls
    listener.ora  samples  shrept.lst
    [oracle@ol7-vagrant admin]$ cat listener.ora
    # listener.ora Network Configuration File: /u01/app/oracle/product/12.2.0.1/dbhome_1/network/admin/listener.ora
    # Generated by Oracle configuration tools.
    
    LISTENER =
      (DESCRIPTION_LIST =
        (DESCRIPTION =
          (ADDRESS = (PROTOCOL = TCP)(HOST = ol7-vagrant)(PORT = 1521))
          (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
        )
      )
    
    

    此时easy connect成功了:

    sqlplus sys/Welcome1@127.0.0.1:1521/orcl as sysdba
    
    

    静默方式

    $ netca -help
    Usage: netca [-silent] {<command> <options>}
    
    Perform network configuration by specifying the following arguments:
        [-silent]
            -responsefile <Response file name>]
            [-local {Perform configuration on only local node}]
        -instype <typical|custom>
            [-listener <Listener name (only for custom install)>]
            [-lisport <TCP/IP port number>]
            [-lps <Starting TCP/IP port number (only for typical install)>]
            [-lpe <Ending TCP/IP port number (only for typical install)>]
            [-netnum <Network resource number (only for RAC)>]
            [-nostartlsnr {Do not start listener}]
        [-crsupgrade {Upgrade default listener from lower version database home to Grid Infrastructure home (only for RAC)}]
        [-inscomp <Comma separated list of installed components>]
        [-insprtcl <Comma separated list of installed protocols>]
        [-orahome <Oracle home>]
        [-orahnam <Oracle home name>]
        [-log <Log file name>]
        [-h|-help {Print usage}]
        [-listenerparameters {Comma separated list of the form parameter=value to specify the desired parameters for the selected listener}]
    

    首先用netca GUI删除之前建立的监听。

    $ netca
    
    Oracle Net Services Configuration:
    Stopping Oracle Net Listener:
        Running Listener Control:
          /u01/app/oracle/product/12.2.0.1/dbhome_1/bin/lsnrctl stop LISTENER
        Listener Control complete.
        Listener stopped successfully.
        Deleted listener: LISTENER
    Oracle Net Services configuration successful. The exit code is 0
    
    

    然后找一个示例响应文件:

    $ cd $ORACLE_HOME
    $ find . -name *.rsp
    ./install/response/db_2019-09-05_05-26-52AM.rsp
    ./inventory/response/oracle.server_EE.rsp
    ./inventory/response/db_install.rsp
    ./assistants/dbca/dbca.rsp
    ./assistants/netca/netca.rsp
    ./network/install/netca_typ.rsp
    ./network/install/netca_clt.rsp
    ./rdbms/admin/cdb_cloud/rsp/netca.rsp
    ./rdbms/admin/cdb_cloud/rsp/db.rsp
    

    静默方式安装:

    $ netca -silent -responsefile $ORACLE_HOME/network/install/netca_typ.rsp
    
    Parsing command line arguments:
        Parameter "silent" = true
        Parameter "responsefile" = /u01/app/oracle/product/12.2.0.1/dbhome_1/network/install/netca_typ.rsp
    Done parsing command line arguments.
    Oracle Net Services Configuration:
    Profile configuration complete.
    Oracle Net Listener Startup:
        Running Listener Control:
          /u01/app/oracle/product/12.2.0.1/dbhome_1/bin/lsnrctl start LISTENER
        Listener Control complete.
        Listener started successfully.
    Listener configuration complete.
    Oracle Net Services configuration successful. The exit code is 0
    
    

    监听启动后,需稍微一等,数据库就会注册上来,然后就可以sqlplus连接了。

    网络服务名配置(tnsnames.ora)

    netca还可以配置网络服务名,是用于客户端的解析,为listener.ora是用于服务器端的。
    在这里插入图片描述
    实际就是配置tnsnames.ora中的条目,就不赘述了。
    以下为生成的配置文件:

    $ cd $ORACLE_HOME/network/admin
    $ cat tnsnames.ora
    # tnsnames.ora Network Configuration File: /u01/app/oracle/product/12.2.0.1/dbhome_1/network/admin/tnsnames.ora
    # Generated by Oracle configuration tools.
    
    ORCL =
      (DESCRIPTION =
        (ADDRESS_LIST =
          (ADDRESS = (PROTOCOL = TCP)(HOST = ol7-vagrant)(PORT = 1521))
        )
        (CONNECT_DATA =
          (SERVICE_NAME = orcl)
        )
      )
    
    

    定义了网络服务后。连接串可以简化:

    # 之前
    $ sqlplus sys/Welcome1@127.0.0.1:1521/orcl as sysdba
    # 之后
    $ sqlplus sys/Welcome1@orcl as sysdba
    

    参考

    1. https://oracle-base.com/articles/misc/oracle-network-configuration
    2. https://sort.veritas.com/public/documents/ccser/5.2/windowsandunix/productguides/html/ccer_install/ch03s06.htm
    展开全文
  • 详细的解释了servlet filter listener 额知识,本文档适合初学者阅读
  • @EventListener注解使用及源码解析

    万次阅读 多人点赞 2019-07-29 15:54:20
    一、简介 @EventListener是一种事件驱动编程在spring4.2的时候开始有的,早期可以实现ApplicationListener接口, 想了解下ApplicationListener的可以参考下这篇文章...内部实现原...
  • 文章目录@EventListener的初始化工作@EventListener的转换 之前的“SpringFramework事件与监听机制”系列文章已经从接口层面上介绍了事件、监听器和发布器。然使用@EventListener也能达到ApplicationLister接口的...
  • 在看@EventListener之前需要先知道 继承EventListener方式在底层是怎么实现了,可以参见前一篇博客Spring源码-事件监听机制(实现EventListener接口)。 先梳理一下,首先Ioc容器启动的时候,ApplicationContext的...
  • MQListener Demo

    2016-08-17 12:15:00
    MQListener Demo
  • spring的各种 Listener

    千次阅读 2018-09-06 16:48:57
    引言:listener顾名思义就是监听的意思,作用就是监听程序中的一些变化,并根据其做出一些相应的响应。通俗的语言就是在session,request,application三个对象创建消亡或者往其中进行修改增加删除属性时自动执行...
  • 针对Oracle的TNS listener的攻击原理及方法介绍。。。
  • JMS与Spring之二(用message listener container异步收发消息)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 444,921
精华内容 177,968
关键字:

listener