1.spring内部工作机制:
Spring的AbstractApplicationContext是ApplicationContext的抽象实现类;该类的refresh()方法定义了Spring容器在加载配置文件后的各项处理过程;
refresh函数流程:
1)初始化BeanFactory: 根据配置文件实例化BeanFactory,Spring将配置文件信息装入到Bean定义注册表(BeanDefinitionRegistry)中;
2)调用工厂后处理器:根据反射机制,从BeanDefinitionRegistry中找出Bean后工厂处理器(BeanFactoryPostProcessor),调用该接口完成属性编辑器注册表(PropertyEditorRegistry)的注册;主要是完成property文件的扫描注册;
3)注册Bean后处理器:根据反射机制从BeanDefinitionRegistry中找出所有BeanPostProcessor类型的Bean,并将它们注册到容器Bean后处理器的注册表中;
4)初始化消息源:初始化容器的国际化信息资源;
5)初始化应用上下文事件广播器;
6)初始化其他特殊的Bean;
7)注册事件监听器;
8)初始化所有单实例的Bean,初始化Bean后,将他们放入Spring容器的缓存中;
9)发布上下文刷新事件,事件广播器负责将事件广播到每个注册的事件监听器中;
2.IOC流水线:
1)ResourceLoader从存储介质中加载Spring配置信息;并使用Resource表示这个配置文件资源;
2)BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析文件;解析时将配置文件中的每一个<bean>解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
3)Spring容器扫描BeanDefinitionRegistry中的BeanDefinition,并对其进行加工处理;
4)Spring 容器从BeanDefinitionRegistry中取出加工后的BeanDefinition,并调用InstantiationStrategy着手进行Bean实例化工作;
5)在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,完成Bean的属性设置工作;
6)使用容器中注册的Bean后处理器对已完成属性设置工作的Bean进行后续加工,直接装配出一个准备就绪的Bean;
3.使用外部文件;
property配置文件:
driveClassName=com.mysql.jdbc.driver
url=jdbc:mysql://localhost:3306/sampledb
userName=root
password=1234
Spring配置文件:
//引入jdbc配置文件
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
p:location="classpath:com/newcore/jdbc.properties"
p:fileEncoding="utf-8"
</bean>
//使用<context: property-placeholder>引用配置文件;可以指定多个properties
<context:property-placeholder
lication="classpath:com/newcore/jdbc.properties"/>
//通过属性名调用值
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${driveClassName}"
p:url="${url}"
p:username="${userName}"
p:password="${password}" />
注解中使用配置文件:
@Value("${driveClassName}")
private String driveClassName;
除了在配置XML文件中使用property属性,还可以在属性文件中使用property,但必须在配置文件中引入多个properties文件;
4.容器事件
事件源:事件的产生者;任何一个EventObject都必须拥有一个事件源;
事件监听器注册表:一个事件监听器注册到组件或框架中,其实就是保存在监听器注册表里;当组件或框架中的事件源产生事件时就会将事件通知这些位于注册表的监听器;
事件广播器:事件和事件监听器沟通的桥梁,负责把事件通知给事件监听器;
spring事件类:
ApplicationEvent的唯一构造函数是ApplicationEvent(Object source),通过source指定事件源,他有两个子类:
ApplicationContextEvent:容器事件,拥有四个字类分别表示容器的启动、刷新、停止、关闭事件;
RequestHandleEvent:这是一个与Web应用相关的事件,当一个HTTP请求被处理后,产生该事件。只有在web.xml中定义了DispatcherServlet时才会产生该事件,拥有两个子类,分别代表Servlet和Portlet事件;
spring事件监听器接口:
ApplicationListener接口只定义了一个方法:onApplicationEvent(E event);该方法接受ApplicationEvent对象,在该方法中写事件响应处理逻辑;
SmartApplicationListener接口是spring3.0新增的,它定义了两个方法:
boolean supportsEventType(Class <? extends ApplicationEvent> eventType) 指定监听器支持哪些类型的容器事件,只会对该类型的事件做出响应;
boolean supportSourceType(Class<?> sourceType) 指定监听器仅对何种事件源做出响应;
spring事件广播器:
当发生容器事件时,容器主控程序将调用事件广播器将事件通知给注册表中的事件监听器,监听器分别对事件进行响应;
代码演示spring事件:
事件类:
public class MailSendEvent extends ApplicationContextEvent{
private static final long serialVersionUID = 1L;
private String from;
private String to;
public MailSendEvent(ApplicationContext source,String from,String to) {
super(source);
this.from=from;
this.to=to;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
}
事件监听类:
public class MailSendListener implements ApplicationListener<MailSendEvent>{
@Override
public void onApplicationEvent(MailSendEvent event) {
// TODO Auto-generated method stub
System.out.println(event.getFrom()+"向"+event.getTo()+"发送了一封邮件");
}
}
事件发布:
public class MailSender implements ApplicationContextAware {
@Autowired
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
// TODO Auto-generated method stub
this.ctx=arg0;
}
public void sendMail(String from,String to){
System.out.println("开始发送邮件....");
MailSendEvent event=new MailSendEvent(this.ctx, from, to);
ctx.publishEvent(event);
}
}
spring配置XMl:
<bean class="function.MailSendListener"></bean>
<bean id="mailSender" class="function.MailSender"></bean>
测试:
public class MailSendTest {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:configAll/beanall.xml");
MailSender mailSender=(MailSender)ctx.getBean("mailSender");
mailSender.sendMail("北京", "广州");
}
}