我的以前對於框架的學習,就停留在配置,使用階段。說實話過段時間就會忘得蕩然無存。也不知道框架的運行邏輯,就是知道添加個註解,就能夠用了。java
因爲實習,時間比較多,也感恩遇到個好老師,教並給我時間看源碼,雖然沒有作過多少業務,可是感受比作業務更有意義。慢慢的去跟代碼, 對Springspring
運行流程大體有個解。現分享給你們,不足之處,但願各位補充,相互學習。緩存
可能咱們不多在乎,ClassPathXmlApplicationContext這個類,其實這個類作了不少的事情,它纔是咱們瞭解Spring框架的窗戶。 框架
ClassPathXmlApplicationContext c=new ClassPathXmlApplicationContext("ApplicationContext.xml");ide
當咱們執行上面的語句的時候,
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
實際上走的是這個構造函數,這個構造函數作了兩個事情,一是setConfigLocations()方法初始化一些配置。一是reFresh()函數,該函數進行了Bean的註冊,事件廣播等。
refresh()函數十分重要,具體幹了什麼,請看下面的源碼註釋:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 註冊Bean.
invokeBeanFactoryPostProcessors(beanFactory);
// 登記攔截bean建立的處理器
registerBeanPostProcessors(beanFactory);
initMessageSource();
// 建立了一個廣播事件的類
initApplicationEventMulticaster();
onRefresh();
// 註冊事件監聽者
registerListeners();
// 實例化那些被配置成單例的Bean
finishBeanFactoryInitialization(beanFactory);
// 結束刷新,實際上就是廣播事件等操做
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
先對Spring框架的事件機制簡單的作個擴展,常規來看事件涉及以下幾方:
1)事件自己(生產者)
2)消費事件者
3)事件管理(訂閱中心)
1.Spring事件自己從ApplicationEvent派生,事件消費者爲ApplicationListener<T extends ApplicationEvent>,事件管理中心爲ApplicationEventMulticaster
它負責管理監聽者等。
2.Spring當廣播一個事件時,它首先去查找該事件的監聽者,而後再去遍歷監聽者調用其onApplicationEvent(Application evnet)接口,將事件傳給監聽者。
最後當咱們調用getBean()的時候,實際上通過refresh()的bean註冊,已經被緩存到map裏面,直接出map裏面取出實例化便可。
上面的工程目錄結構爲com.springImpl.annotion放的spring的註解類。com.springImple.core放得實現Spring框架的核心類。com.springImpl.test放的是測試類。函數
1)註解類:post
假設如今我這個框架仍是比較搓,就一個註解,學習
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//爲了書寫簡單 這裏只做用於屬性 也就是域 成員變量
public @interface Resources {
}
2)事件類:測試
如今這個事件就是一個約定,實際啥也沒有 ui
public class ApplicationEvent {
}
3)監聽者類
public interface ApplicationListener<T extends ApplicationEvent> {
void onApplicationEvent(T event);
}
4)事件訂閱中心類
public interface ApplicationEventMulticaster {
void publishEvent(ApplicationEvent event);
}
5)解析配置文件的類
public class ConfigResolver extends ApplicationEvent implements ApplicationEventMulticaster{
private String configXml="spring.xml";
static HashMap<String ,Object> BeanFactory;//這裏就是模仿beanFactory 將全部的bean用beanid與對應實例用map保存起來
static HashMap<String ,ApplicationListener> RegistryListener;//這裏保存那些是監聽者的bean
static {
BeanFactory=new HashMap<>();
RegistryListener=new HashMap<>();
}
public ConfigResolver(String config){
configXml=config==null?configXml:config;//默認就是spring.xml
setConfigLocations(configXml);
refresh();
}
public Object getBean(String beanId){
return BeanFactory.get(beanId);
}
private void setConfigLocations(String configXml){
//什麼都不作 固然能夠作一些環境的檢查 將配置的提取用一個類去處理等等 我這偷個懶
}
private void refresh(){
//註冊bean
invokeBeanFactoryPostProcessors(BeanFactory);
//登記監聽者
registerListeners();
//j結束刷新 表面程序已經啓動 能夠廣播這個刷新完畢事件了 廣播事件
finishRefresh();
}
private void finishRefresh(){
publishEvent(this);
}
/**
* 從beanfactory找到那些是監聽者類型的bean
*/
private void registerListeners(){
Iterator<String> it=BeanFactory.keySet().iterator();
while(it.hasNext()){
String key=it.next();
if(BeanFactory.get(key) instanceof ApplicationListener){
RegistryListener.put(key,(ApplicationListener)BeanFactory.get(key));
it.remove();
}
}
}
/**
* 將配置文件中的bean所有實例化到map裏面
* @param beanFactory
*/
private void invokeBeanFactoryPostProcessors(HashMap beanFactory){
InputStream in= null;
try {
in = ConfigResolver.class.getResourceAsStream(configXml)==null?
new FileInputStream(configXml):ConfigResolver.class.getResourceAsStream(configXml);//兼容資源路徑 與 絕對路徑
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
DocumentBuilder db=DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document dc=db.parse(in);
NodeList nl=dc.getElementsByTagName("bean");
for(int i=0;i<nl.getLength();i++){
NamedNodeMap attrs= nl.item(i).getAttributes();
HashMap<String,String> beanMap=new HashMap<>();//對應一個bean標籤
for(int j=0;j<attrs.getLength();j++){
String beanNodeName=attrs.item(j).getNodeName();
String beanNodeValue=null;
if(beanNodeName!=null) {
beanNodeValue = attrs.item(j).getNodeValue();
}
if(beanNodeValue!=null){
beanMap.put(beanNodeName,beanNodeValue);
}
}
String beanId=beanMap.get("id");
String beanClass=beanMap.get("class");
if(beanClass==null||beanId==null){
continue;
}
try {
Class cls=Class.forName(beanClass);
Object beanObject=cls.newInstance();
Field[] fds=beanObject.getClass().getDeclaredFields();
for(Field fd:fds){
fd.setAccessible(true);//獲取訪問私有變量權限
Resources rs=fd.getAnnotation(Resources.class);
if(rs!=null){
fd.set(beanObject,fd.getType().newInstance());//實例化帶有Resource註解的成員
}
}
beanFactory.put(beanId,beanObject);//將bean放到map
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 廣播事件
* @param event
*/
@Override
public void publishEvent(ApplicationEvent event) {
Iterator<String> it=RegistryListener.keySet().iterator();
while(it.hasNext()){
RegistryListener.get(it.next()).onApplicationEvent(event);
}
}
}
6)看一下測試類:
//監聽程序啓動的類 監聽者
public class ApplicationStartLister implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("SpringImpl App start");
}
}
//假設這裏有個眼瞎的人 他用註解注注入了個眼睛Ege類
public class Blind {
@Resources
private Ege ege;
public Ege getEge(){
return ege;
}
}
//眼睛Ege類
public class Ege {
public String see(){
return "the world is so beautiful.";
}
}
//主程序
public class DoMain {
public static void main(String []args){
ConfigResolver cfg=new ConfigResolver("E:\\__Java\\__idea_proj\\SpringImpl\\src\\resources\\spring.xml");
Blind b= (Blind) cfg.getBean("mybean");
System.out.println("tell me how is the world :"+b.getEge().see());
}
}
//配置文件
7)運行結果
到此完畢,一個簡單的模仿spring框架完畢。