读Spring源码的一些杂乱思绪(三)

继续看Spring的源码
AbstractApplicationContext类中registerListeners()方法用来注册监听器。

/**
     * Add beans that implement ApplicationListener as listeners.
     * Doesn't affect other listeners, which can be added without being beans.
     */
    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) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

先拿到所有的监听器,然后加到一个集合里getApplicationEventMulticaster()。
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);这句的意思是获取到所有的实现了ApplicationListener这个接口的类并且把他们封装成一个String[]数组,之后也加入到监听器的集合里,此集合为getApplicationEventMulticaster();

if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }

这里

/**
     * Invoke the given listener with the given event.
     * @param listener the ApplicationListener to invoke
     * @param event the current event to propagate
     * @since 4.1
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                listener.onApplicationEvent(event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            try {
                listener.onApplicationEvent(event);
            }
            catch (ClassCastException ex) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                LogFactory.getLog(getClass()).debug("Non-matching event type for listener: " + listener, ex);
            }
        }
    }

每个监听器run一个线程调用listener.onApplicationEvent(event);方法。
实际上就是实现了ApplicationListener接口的所有实现类注册到applicationListenerBeans容器中,往spring容器中注册发布ApplicationEvent,监听器方法将会被触发。
下面我举个例子:
MyEvent

package com.mylisten;

import org.springframework.context.ApplicationEvent;

public class MyEvent extends ApplicationEvent {

    public String param1;

    public String param2;

    public MyEvent(Object source,String param1,String param2) {
        //必须调用父类构造方法
        super(source);
        this.param1 = param1;
        this.param2 = param2;
    }

    public Object getSource() {
        return super.getSource();
    }

    public String getParam1() {
        return param1;
    }

    public void setParam1(String param1) {
        this.param1 = param1;
    }

    public String getParam2() {
        return param2;
    }

    public void setParam2(String param2) {
        this.param2 = param2;
    }

}

MyListen

package com.mylisten;

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

//观察者模式去监听ApplicationEvent事件
public class MyListen implements ApplicationListener {

    public void onApplicationEvent(ApplicationEvent arg0) {

        if(arg0 instanceof MyEvent) {
            MyEvent event = (MyEvent)arg0;

            System.out.println(this.getClass().getName() + event.getParam1());
            System.out.println(this.getClass().getName() + event.getParam2());
            System.out.println(this.getClass().getName() + event.getSource());

        }
    }

}

MyListen2

package com.mylisten;

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

//观察者模式去监听ApplicationEvent事件
public class MyListen2 implements ApplicationListener {

    public void onApplicationEvent(ApplicationEvent arg0) {

        if(arg0 instanceof MyEvent) {
            MyEvent event = (MyEvent)arg0;

            System.out.println(this.getClass().getName() + event.getParam1());
            System.out.println(this.getClass().getName() + event.getParam2());
            System.out.println(this.getClass().getName() + event.getSource());

        }
    }

}

在XML文件中添加

<bean id="myListen" class="com.mylisten.MyListen"></bean>
<bean id="myListen2" class="com.mylisten.MyListen2"></bean>

MyListenTest

package com.mylisten;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Created by wtz on 2017/9/19.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring-mvc.xml","classpath:spring-mybatis.xml"})
public class MyListenTest implements ApplicationContextAware{

    @Autowired
    public ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Test
    public void testListen(){
        MyEvent myEvent = new MyEvent("source","param1","param2");
        applicationContext.publishEvent(myEvent);
    }
}

这里写图片描述

这里用到了观察者模式。
applicationContext.publishEvent(myEvent);我们把MyEvent广播给所有的观察者。主题subject——MyEvent,观察者observer——MyListen,Mylisten2,他们收到ApplicationEvent事件后会触发onApplicationEvent方法。
我们可以用这个来做很多扩展,因为这个监听在spring的整个生命周期都存在。

/**
     * Apply before-instantiation post-processors, resolving whether there is a
     * before-instantiation shortcut for the specified bean.
     * @param beanName the name of the bean
     * @param mbd the bean definition for the bean
     * @return the shortcut-determined bean instance, or {@code null} if none
     */
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

这个方法是关于AOP的,其实AOP的实现也是自定义标签,通过URI去找对应的Handler,之后加载所有的XML,之后init之后初始化所有的解析器,根据多态去parse解析,这里是把所有的动态代理类注册进来之后做相应处理。

在spring的xml里面我们会经常会看到

<!-- 数据库连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
        <property name="minPoolSize" value="${c3p0.minPoolSize}"/>
        <property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/>
        <property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/>
        <property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/>
    </bean>

    <!-- 配置SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 注入数据库连接池 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 扫描model包 使用别名 -->
        <property name="typeAliasesPackage" value="com.chat.model"/>
        <!-- 扫描sql配置文件:mapper需要的xml文件 -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

这种ref的写法,还有@Autowired,@Resource这种,其实这些都是ioc的依赖注入,而源码中populateBean(beanName, mbd, instanceWrapper),这个方法是利用反射进行ioc依赖注入。
其中AutowiredAnnotationBeanPostProcessor是对@Autowire注解依赖注入支持。
而CommonAnnotationBeanPostProcessor是对@Resource注解依赖注入的支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值