3 定義解析器相關類
3.1 BeanDefinitionReader接口
BeanDefinitionReader是用來解析配置文件並在註冊表中註冊bean的信息。定義了兩個規範:
-
獲取註冊表的功能,讓外界可以通過該對象獲取註冊表對象。
-
加載配置文件,並註冊bean數據。
/**
* @version v1.0
* @ClassName: BeanDefinitionReader
* @Description:
* 用來解析配置文件的,而該接口只是定義了規範
*/
public interface BeanDefinitionReader {
//獲取註冊表對象
BeanDefinitionRegistry getRegistry();
//加載配置文件並在註冊表中進行註冊
void loadBeanDefinitions(String configLocation) throws Exception;
}
3.2 XmlBeanDefinitionReader類
XmlBeanDefinitionReader類是專門用來解析xml配置文件的。該類實現BeanDefinitionReader接口並實現接口中的兩個功能。
/**
* @version v1.0
* @ClassName: XmlBeanDefinitionReader
* @Description: 針對xml配置文件進行解析的類
*/
public class XmlBeanDefinitionReader implements BeanDefinitionReader {
//聲明註冊表對象
private BeanDefinitionRegistry registry;
public XmlBeanDefinitionReader() {
this.registry = new SimpleBeanDefinitionRegistry();
}
@Override
public BeanDefinitionRegistry getRegistry() {
return registry;
}
public void loadBeanDefinitions(String configLocation) throws Exception {
//使用dom4j進行xml配置文件的解析 須需在pom文件裏面引入dom4j 1.6.1版本
SAXReader reader = new SAXReader();
//獲取類路徑下的配置文件
InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);
Document document = reader.read(is);
//根據Document對象獲取根標籤對象 (beans)
Element rootElement = document.getRootElement();
//獲取根標籤下所有的bean標籤對象
List<Element> beanElements = rootElement.elements("bean");
//遍歷集合
for (Element beanElement : beanElements) {
//獲取id屬性
String id = beanElement.attributeValue("id");
//獲取class屬性
String className = beanElement.attributeValue("class");
//將id屬性和class屬性封裝到BeanDefinition對象中
//1,創建BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setId(id);
beanDefinition.setClassName(className);
//創建MutablePropertyValues對象
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
//獲取bean標籤下所有的property標籤對象
List<Element> propertyElements = beanElement.elements("property");
for (Element propertyElement : propertyElements) {
String name = propertyElement.attributeValue("name");
String ref = propertyElement.attributeValue("ref");
String value = propertyElement.attributeValue("value");
PropertyValue propertyValue = new PropertyValue(name,ref,value);
mutablePropertyValues.addPropertyValue(propertyValue);
}
//將mutablePropertyValues對象封裝到BeanDefinition對象中
beanDefinition.setPropertyValues(mutablePropertyValues);
//將beanDefinition對象註冊到註冊表中
registry.registerBeanDefinition(id,beanDefinition);
}
}
}
4 IOC容器相關類
4.1 BeanFactory接口
在該接口中定義IOC容器的統一規範即獲取bean對象。
public interface BeanFactory {
//根據bean對象的名稱獲取bean對象
Object getBean(String name) throws Exception;
//根據bean對象的名稱獲取bean對象,並進行類型轉換
<T> T getBean(String name, Class<? extends T> clazz) throws Exception;
}
4.2 ApplicationContext接口
該接口的所以的子實現類對bean對象的創建都是非延時的,所以在該接口中定義 refresh()
方法,該方法主要完成以下兩個功能:
-
加載配置文件。
-
根據註冊表中的BeanDefinition對象封裝的數據進行bean對象的創建。
//定義非延時加載功能
public interface ApplicationContext extends BeanFactory {
//進行配置文件加載並進行對象創建
void refresh() throws IllegalStateException, Exception;
}
4.3 AbstractApplicationContext類
-
作爲ApplicationContext接口的子類,所以該類也是非延時加載,所以需要在該類中定義一個Map集合,作爲bean對象存儲的容器。
-
聲明BeanDefinitionReader類型的變量,用來進行xml配置文件的解析,符合單一職責原則。
BeanDefinitionReader類型的對象創建交由子類實現,因爲只有子類明確到底創建BeanDefinitionReader哪兒個子實現類對象。
public abstract class AbstractApplicationContext implements ApplicationContext {
protected BeanDefinitionReader beanDefinitionReader;
//用來存儲bean對象的容器 key存儲的是bean的id值,value存儲的是bean對象
protected Map<String, Object> singletonObjects = new HashMap<String, Object>();
//存儲配置文件的路徑
protected String configLocation;
public void refresh() throws IllegalStateException, Exception {
//加載BeanDefinition
beanDefinitionReader.loadBeanDefinitions(configLocation);
//初始化bean
finishBeanInitialization();
}
//bean的初始化
private void finishBeanInitialization() throws Exception {
//獲取註冊表對象
BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
//獲取BeanDefinition對象
String[] beanNames = registry.getBeanDefinitionNames();
for (String beanName : beanNames) {
//進行bean的初始化
getBean(beanName);
}
}
}
注意:該類finishBeanInitialization()方法中調用getBean()方法使用到了模板方法模式。
4.4 ClassPathXmlApplicationContext類
該類主要是加載類路徑下的配置文件,並進行bean對象的創建,主要完成以下功能:
-
在構造方法中,創建BeanDefinitionReader對象。
-
在構造方法中,調用refresh()方法,用於進行配置文件加載、創建bean對象並存儲到容器中。
-
重寫父接口中的getBean()方法,並實現依賴注入操作。
/**
* @version v1.0
* @ClassName: ClassPathXmlApplicationContext
* @Description: IOC容器具體的子實現類
* 用於加載類路徑下的xml格式的配置文件
*/
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
public ClassPathXmlApplicationContext(String configLocation) {
this.configLocation = configLocation;
//構建解析器對象
beanDefinitionReader = new XmlBeanDefinitionReader();
try{
this.refresh();
} catch (Exception e) {
}
}
//根據bean對象的名稱獲取bean對象
public Object getBean(String name) throws Exception {
//判斷對象容器中是否包含指定名稱的bean對象,如果包含,直接返回即可,如果不包含,需要自行創建
Object obj = singletonObjects.get(name);
if (obj != null) {
return obj;
}
//獲取BeanDefinition對象
BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
BeanDefinition beanDefinition = registry.getBeanDefinition(name);
//獲取bean信息中的className
String className = beanDefinition.getClassName();
//通過反射創建對象
Class<?> clazz = Class.forName(className);
Object beanObj = clazz.newInstance();
//進行依賴注入操作
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues) {
//獲取name屬性值
String propertyName = propertyValue.getName();
//獲取value屬性
String value = propertyValue.getValue();
//獲取ref屬性
String ref = propertyValue.getRef();
if(ref != null && !"".equals(ref)) {
//獲取依賴的bean對象
Object bean = getBean(ref);
//拼接方法名
String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
//獲取所有的方法對象
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
//執行該setter方法
method.invoke(beanObj,bean);
}
}
}
if(value != null && !"".equals(value)) {
//拼接方法名
String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
//獲取method對象
Method method = clazz.getMethod(methodName, String.class);
method.invoke(beanObj,value);
}
}
//在返回beanObj對象之前,將該對象存儲到map容器中
singletonObjects.put(name,beanObj);
return beanObj;
}
public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
Object bean = getBean(name);
if(bean == null) {
return null;
}
return clazz.cast(bean);
}
}
/**
* @version v1.0
* @ClassName: StringUtils
*/
public class StringUtils {
private StringUtils() {
}
// userDao ==> setUserDao
public static String getSetterMethodByFieldName(String fieldName) {
String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
return methodName;
}
}
如此已經完成,只需對這個工程執行mvn install打包成一個jar,通過pom文件引入到其他工程(例如:spring使用回顧)中即可進行測試。
// 這是另外一個工程
// 引用的類均來自於前面自定義的類
public static void main(String[] args) throws Exception {
//1,創建spring的容器對象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
//2,從容器對象中獲取userService對象
UserService userService = applicationContext.getBean("userService", UserService.class);
//3,調用userService方法進行業務邏輯處理
userService.add();
}