基于Java反射技術(shù)實(shí)現(xiàn)簡單IOC容器
前言
首先思考一個(gè)問題,如果你正在做一個(gè)復(fù)雜的系統(tǒng),一個(gè)系統(tǒng)模塊內(nèi)有幾百個(gè)功能業(yè)務(wù)類,這些類需要使用同一些對(duì)象來進(jìn)行工作。那么,你會(huì)怎樣去管理這些通用且一樣的對(duì)象呢?
學(xué)習(xí)過Spring的朋友會(huì)知道,Spring框架為此提供了一種非常先進(jìn)的思想,即IOC(控制反轉(zhuǎn))。Spring可以理解為一個(gè)工廠,負(fù)責(zé)對(duì)象的創(chuàng)建和對(duì)象間關(guān)系的維護(hù)。IoC即控制反轉(zhuǎn),簡單說就是之前需要使用new的方式創(chuàng)建對(duì)象,而Spring框架會(huì)從XML文件中根據(jù)配置的信息來創(chuàng)建對(duì)象,然后放進(jìn)它自己的容器之中。在程序要使用到該對(duì)象的時(shí)候,自動(dòng)注入。
下面就來做一個(gè)最簡單的IOC容器。
1.創(chuàng)建一個(gè)實(shí)體類,比如學(xué)生類,汽車類
2.創(chuàng)建XML文件配置對(duì)象的信息
3.編寫一個(gè)IOC容器類。這個(gè)類工作起來,首先加載XML文件,掃描自己配置的對(duì)象信息,之后使用反射技術(shù)創(chuàng)建對(duì)象,最后將這些
對(duì)象放進(jìn)自己的Map集合中(容器)。外部想要調(diào)用這些對(duì)象,那么就使用Map的鍵,來拿到這個(gè)集合中對(duì)應(yīng)的值(對(duì)象)。
編寫一個(gè)喜聞樂見的Student學(xué)生類。
我做的比較簡單,沒有使用get() set()方法。
后面使用反射技術(shù)可以強(qiáng)制給 private 修飾的屬性賦值
package cn.haidnor.bean;public class Student { /** 學(xué)生姓名 */ private String name; /** 學(xué)生性別 */ private String gender; /** 學(xué)生年齡 */ private int age; @Override public String toString() { return 'Student{' +'name=’' + name + ’’’ +', gender=’' + gender + ’’’ +', age=' + age +’}’; }}
創(chuàng)建XML文件,配置對(duì)象信息
id 表示在IOC容器(Map)的鍵 class 表示對(duì)象類的全類名 name 表示對(duì)象的各種屬性名 property下的文本節(jié)點(diǎn)表示該屬性的值<?xml version='1.0' encoding='UTF-8'?><beans> <bean class='cn.haidnor.bean.Student'> <property name='name'>Lucy</property> <property name='age'>18</property> <property name='gender'>female</property> </bean> <bean class='cn.haidnor.bean.Student'> <property name='name'>Tom</property> <property name='age'>21</property> <property name='gender'>male</property> </bean> <bean class='cn.haidnor.bean.Student'> <property name='name'>LiLi</property> <property name='age'>23</property> <property name='gender'>female</property> </bean></beans>
編寫IOC容器類
1.首先根據(jù)XML中的配置文件,生成學(xué)生對(duì)象
2.所有的對(duì)象都放入到一個(gè)Map中
3.提供一個(gè)getBean()的方法,傳入配置文件中的id,返回對(duì)應(yīng)的對(duì)象
package cn.haidnor.core;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class SpringIOC { /** * 配置文件地址 */ private static final String CONFIGURATION_PATH = 'resources/applicationContext.xml'; /** * ioc容器 */ private static Map<String, Object> ioc = new HashMap<>(); static { initialization(); } /** * 從 ioc 容器中獲取指定 bean * * @param name 需要獲取的 bean 的 id, 對(duì)應(yīng) XML 配置文件中的 bean id * @return bean */ public static Object getBean(String name) { return ioc.get(name); } /** * 初始化容器 */ private static void initialization() { Document document = null; try { DocumentBuilderFactory bdf = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = bdf.newDocumentBuilder(); document = documentBuilder.parse(CONFIGURATION_PATH); } catch (Exception e) { e.printStackTrace(); } NodeList beanNodes = document.getElementsByTagName('bean'); for (int i = 0; i < beanNodes.getLength(); i++) { Node node = beanNodes.item(i); reloadBean(node); } } /** * 裝載 benn * * @param beanNode xml 文件 bean 根節(jié)點(diǎn) */ private static void reloadBean(Node beanNode) { Element bean = (Element) beanNode; String id = bean.getAttribute('id'); // IOC 容器中 bean 的名字 String beanClass = bean.getAttribute('class'); // 全類名 // 每個(gè) bean 節(jié)點(diǎn)下的全部 property 節(jié)點(diǎn) NodeList childNodes = beanNode.getChildNodes(); Map<String, String> attributeMap = reloadAttribute(childNodes); // 使用反射構(gòu)造 bean 對(duì)象 Object instance = creatBean(beanClass, attributeMap); // 將所有的 bean 對(duì)象放入容器中 ioc.put(id, instance); } /** * 加載 bean 的屬性值 * * @param attributeNodes 所有的屬性 property 節(jié)點(diǎn) * @return Map 屬性的名字和值集合 */ private static Map<String, String> reloadAttribute(NodeList attributeNodes) { Map<String, String> keyValue = new HashMap<>(); for (int i = 0; i < attributeNodes.getLength(); i++) { Node filed = attributeNodes.item(i); if (filed.getNodeType() == Node.ELEMENT_NODE) {Element element = (Element) filed;String fileName = element.getAttribute('name');String value = element.getFirstChild().getNodeValue();keyValue.put(fileName, value); } } return keyValue; } /** * 構(gòu)造bean對(duì)象 * * @param className 全類名 * @param attributes 每個(gè)對(duì)象的屬性和 * @return Object 構(gòu)造完成的 bean 對(duì)象 */ private static Object creatBean(String className, Map<String, String> attributes) { Object instance = null; try { Class<?> clazz = Class.forName(className); instance = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) {setFiledValue(instance, field, attributes); } } catch (Exception e) { e.printStackTrace(); } return instance; } /** * 為實(shí)例對(duì)象的屬性賦值 * * @param instance 實(shí)例對(duì)象 * @param field 屬性字段對(duì)象 * @param attributes 屬性名與屬性值的 Map 集合 */ private static void setFiledValue(Object instance, Field field, Map<String, String> attributes) { // 忽略 field 權(quán)限檢查 field.setAccessible(true); String type = field.getType().toString(); String name = field.getName(); try { switch (type) {case 'char': field.setChar(instance, attributes.get(name).charAt(0)); break;case 'class java.lang.Boolean':case 'boolean': field.setBoolean(instance, Boolean.parseBoolean(attributes.get(name))); break;case 'class java.lang.Byte':case 'byte': field.setByte(instance, Byte.parseByte(attributes.get(name))); break;case 'class java.lang.Float':case 'float': field.setFloat(instance, Float.parseFloat(attributes.get(name))); break;case 'class java.lang.Integer':case 'int': field.setInt(instance, Integer.parseInt(attributes.get(name))); break;case 'class java.lang.Long':case 'long': field.setLong(instance, Long.parseLong(attributes.get(name))); break;case 'class java.lang.Short':case 'short': field.setShort(instance, Short.parseShort(attributes.get(name))); break;default: field.set(instance, attributes.get(name)); break; } } catch (Exception e) { e.printStackTrace(); } }}
最后編寫測試類
不使用new的方式創(chuàng)建學(xué)生對(duì)象 使用ioc容器getBean()方法獲取對(duì)象 調(diào)用對(duì)象的復(fù)寫的toString()方法package cn.haidnor.test;import cn.haidnor.bean.Student;import cn.haidnor.core.SpringIOC;public class Test { public static void main(String[] args) { // 不使用 new 的方式創(chuàng)建對(duì)象, 從容器中獲取 Student stu1 = (Student) SpringIOC.getBean('stu3'); // 調(diào)用學(xué)生類的方法,打印信息 System.out.println(stu1.toString()); }}
運(yùn)行結(jié)果,控制臺(tái)打印輸出的內(nèi)容
Student{name=’LiLi’, gender=’female’, age=23}
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. js實(shí)現(xiàn)跳一跳小游戲2. JVM之class文件結(jié)構(gòu)3. js實(shí)現(xiàn)貪吃蛇小游戲(加墻)4. XMLDOM對(duì)象方法:對(duì)象屬性5. python對(duì)批量WAV音頻進(jìn)行等長分割的方法實(shí)現(xiàn)6. Html5播放器實(shí)現(xiàn)倍速播放的方法示例7. asp.net core 認(rèn)證和授權(quán)實(shí)例詳解8. CSS linear-gradient屬性案例詳解9. Ajax報(bào)錯(cuò)400的參考解決辦法10. Python中Anaconda3 安裝gdal庫的方法
