@TOC# Spring系列
記錄在程式走的每一步___auth:huf
最近在復習Spring核心原理; 順手記錄;
Spring關健實作 簡化版
以下實作均為簡化版本;有助于幫助記憶; 該版本代碼有部分缺陷 例如:相互依賴…本章節不會記錄相互依賴是怎么解決的; 之后會有專門的章節講解其細節;主要描述Spring大致是怎么實作的 BeanDefinition 與 BeanPostProcessor 又是什么; 之后會一步一步引導讀者理解Spring原理.并且記住.
以下代碼有詳細注釋: 關健代碼已經全部展示; (原始碼下載): 該篇章極為重要;如果想很好的理解后續Spring底層原理 一定要理解透徹該篇章;
package huf_spring;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* 模擬SPring啟動主類:
* ps: Spring中使用了大量反射; 進行類注解 屬性 進行 功能性的區分;
* 1:主類主要做了以下幾件事
* 1): 獲取到組態檔;從組態檔中;獲取到掃描路徑(類的掃描路徑);然后得到檔案; 然后對其目錄進行挨個掃描 得到相對應的class;
* 2): 在初始化每個Bean的時候 會執行Aware回呼 進行屬性的注入;
* 3): 在Aware回呼之后 進入 BeanPostProcesscor List. 開始回圈呼叫 該實作類的前置方法:postProcessBeforeInitialization
* 4): 實體化物件的創建; 這時候是真實物件; 但是一旦進入了postProcessAfterInitialization 方法;
* (控制方案 可以有 事務 等等注解進行控制) 如果有 就會轉變為代理物件; 如果沒有 就回傳創建的真實物件;
* 5): InitializingBean 是初始化介面 使用該介面 把該介面放到容器中去; 不能保證它的執行順序就是排在第一位;注意;
*
* auth:huf
*/
public class HufApplicationContext {
//beanDefinitionMap 存放的是所有掃描到的Bean 的class資訊
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
//singletonObjects 單例池 存放著所有掃描到的 <單例> 物件 且是非懶加載物件 也就是@Lazy 標注的物件;如果使用組態檔可以在組態檔中設定
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();
//beanPostProcessorList 存放著所有處理器的List 該處理器 會在實體化前后進行回圈呼叫. 從而達到初始化前 初始化 初始化后的效果;
//也是AOP切面的主要實作途徑;
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<BeanPostProcessor>();
//test main方法 new出該物件 注入Class檔案 第一個大步驟
public HufApplicationContext(Class configClazz) {
//掃描 傳入為AppConfig.class;
scam(configClazz);
/**
* 實體化非懶加載單例bean:
* 1. 實體化
* 2. 屬性填充
* 3. Aware回呼
* 4. 初始化
* 5. 添加到單例池
*/
instanceSingletonBean();
}
//一
private void scam(Class configClazz) {
//獲取到掃描類上的注解 獲取到要掃描的類 目錄路徑
ComponentScan componentScanAnnotation = (ComponentScan) configClazz.getAnnotation(ComponentScan.class);
//獲取到 "com.huf.service"
String compomentScanPath = componentScanAnnotation.value();
//第一個大步驟 2)
List<Class> classList = getBeanClasses(compomentScanPath);
if(null!=classList && classList.size()>0){
for (Class clazz : classList) {
//判斷是否被注解; 注解也有很多; 這里僅模仿流程
if (clazz.isAnnotationPresent(Service.class)) {
//被掃描注解注視到 或者是組態檔配置到. 那么 就開始封裝 BeanDefinition; 自行到BeanDefinition 查看該類用處;
BeanDefinition beanDefinition = new BeanDefinition();
//保存Class
beanDefinition.setBeanClass(clazz);
Service service = (Service) clazz.getAnnotation(Service.class);
//獲取該Service 名字 實際上 Spring有自動掃描 自動生成名字的一套方案 在以前XML檔案定義的形式 有id 可以定義Bean的名字.
String beanName = service.value();
//判斷類是否實作了BeanPostProcessor介面 假設實作;
if(BeanPostProcessor.class.isAssignableFrom(clazz)){
try {
//獲取該實作類BeanPostProcessor
BeanPostProcessor instance = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
//在初始化程序中 它僅僅是把相關實體保存到記憶體List中 在此處并無呼叫;請注意;
beanPostProcessorList.add(instance);
} catch (Exception e) {
e.printStackTrace();
}
}
// 決議scope
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scope = (Scope) clazz.getAnnotation(Scope.class);
String scopeValue = scope.value();
if (ScopeEnum.singleton.name().equals(scopeValue)) {
beanDefinition.setScope(ScopeEnum.singleton);
} else {
beanDefinition.setScope(ScopeEnum.prototype);
}
} else {
beanDefinition.setScope(ScopeEnum.singleton);
}
//保存BeanDefinition 使用的Map集合 后續用于創建物件;
beanDefinitionMap.put(beanName,beanDefinition);
}
}
System.out.println("");
}
}
//二 獲取該目錄下面的所有Class 該步驟執行完后 回傳主流程 開始執行instanceSingletonBean
private List<Class> getBeanClasses(String compomentScanPath) {
//創建List 用于回傳
List<Class> beanClasses = new ArrayList<Class>();
//拿到主類的ClassLoader 用于獲取URL路徑
ClassLoader classLoader = HufApplicationContext.class.getClassLoader();
//"com.huf.service" 替換為 "com/huf/service"
compomentScanPath = compomentScanPath.replace(".","/");
//獲得URL 用于創建File
URL resource = classLoader.getResource(compomentScanPath);
//利用URL 創建File 檔案
File file = new File(resource.getFile());
//是否是目錄
if (file.isDirectory()) {
//獲取目錄下面所有Files
File[] files = file.listFiles();
if(files.length>0){
//獲取到File后; 遍歷
for (File f : files) {
//獲取 Class的 路徑 :E:\Users\Administrator\hufSpring\target\classes\com\huf\service\StudentService.class
String fileName = f.getAbsolutePath();
if (fileName.endsWith(".class")) {
//截取名字;
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
className = className.replace("\\", ".");
try {
//通過名字拿到相對應的Clazz;
Class<?> clazz = classLoader.loadClass(className);
//加入集合 尾部回傳;
beanClasses.add(clazz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
return beanClasses;
}
//三
private void instanceSingletonBean() {
//遍歷beanDefinitionMap 得到beanDefinition集合;
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals(ScopeEnum.singleton)) {
//如果該類是單例類 就開始創建;
Object bean = doCreateBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
private Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
//通過BeanDefinition獲取Class;
Class beanClass = beanDefinition.getBeanClass();
try {
// 獲取構建物件;
Constructor declaredConstructor = beanClass.getDeclaredConstructor();
//得到實體化物件
Object instance = declaredConstructor.newInstance();
// 拿到當前物件的每個屬性;
// 這里舉個例子 Autowired 簡化;
Field[] fields = beanClass.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
String fieldName = field.getName();
Object bean = getBean(fieldName);
field.setAccessible(true);
field.set(instance, bean);
}
}
// Aware回呼
if (instance instanceof BeanNameAware) {
((BeanNameAware)instance).setBeanName(beanName);
}
//beanPostProcessorList 提取到所有 處理器 這是 在初始化前 呼叫該方法; 重要
for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
}
// 初始化
if (instance instanceof InitializingBean) {
((InitializingBean)instance).afterPropertiesSet();
}
//beanPostProcessorList 提取到所有 處理器 這是 在初始化后 呼叫該方法; 重要
for (BeanPostProcessor beanPostProcessor: beanPostProcessorList) {
//這里很關鍵 代理物件就是在這里創建的. 我們有一個StudentPostProcessor 類;
instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Object getBean(String beanName) {
if (singletonObjects.containsKey(beanName)) {
return singletonObjects.get(beanName);
} else {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
return doCreateBean(beanName, beanDefinition);
}
}
}
package huf_spring;
/**
* 該類是主要 目的是為了保存類的相關資訊;
* ps : 是類的相關資訊; 它是 Spring定義類的基石; 非常非常重要!
* 在實際情況下 當spring容器啟動的時候會去呼叫ConfigurationClassPostProcessor這個bean工廠的后置處理器完成掃描;
* 當掃描到的Class檔案 里面有很多資訊需要保存 例如 class中的 scope、lazy,等等資訊; 它的資訊不止以下幾個屬性;
* BeanDefinition 是 Spring 設計出來保存這些資訊的;
*
* auth:huf
*/
public class BeanDefinition {
private Class beanClass;
private ScopeEnum scope;
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
public ScopeEnum getScope() {
return scope;
}
public void setScope(ScopeEnum scope) {
this.scope = scope;
}
}
package huf_spring;
/**
* 后置處理器; 它主要作用于在Bean的初始化前 初始化后
* 該介面用于Bean的初始化
* 是Spring IOC容器給我們提供的一個擴展介面
* auth:huf
*/
public interface BeanPostProcessor {
//Bean初始化前
Object postProcessBeforeInitialization(String beanName, Object bean);
//Bean初始化后;
Object postProcessAfterInitialization(String beanName, Object bean);
}
package com.huf.service;
import huf_spring.BeanPostProcessor;
import huf_spring.Service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* StudentService 實作 BeanPostProcessor 類
* 在一開始就Bean初始化的時候就已經實體化 加載進入了 List<BeanPostProcessor> 中等待呼叫
* 這個地方僅僅使用類掃描后 使用的方法是 BeanPostProcessor.class.isAssignableFrom(clazz) 就得到了這個類的實體;
* 具體請看 hufApplicationContext
* auth:huf
*/
@Service("hufPostProcessor")
public class HufPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(String beanName, Object bean) {
System.out.println("前置方法執行:"+beanName);
return bean;
}
public Object postProcessAfterInitialization(String beanName, final Object bean1) {
System.out.println("后置方法執行:"+beanName);
//開始創建動態代理 這里為了方便直接使用JDK代理; 因為JDK代理 是使用介面代理的;
Object proxyInstance = null;
if(beanName.equals("teacherService")){
proxyInstance = Proxy.newProxyInstance(HufPostProcessor.class.getClassLoader(), bean1.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("切入點:test方法");
method.invoke(bean1,args);
System.out.println("切入點:test之后");
return null;
}
});
return proxyInstance;
}
return proxyInstance!=null?proxyInstance:bean1;
}
}
以下為運行結果集:

總結
至此; BeanPostProcessor or BeanDefinition or Aware or InitializingBean 以及Bean的詳細創建程序 已經全部模擬完畢; 感興趣的小伙伴 可以 (原始碼下載):環境只需要一個JDK1.8 其他任何包都不用加;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/297564.html
標籤:java
