設計模式(三十一)----綜合應用-自定義Spring框架-自定義Spring IOC-定義解析器、IOC容器相關類

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();
    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章