一、了解Spring IOC/DI
1:Spring有兩大核心技術,控制反轉(Inversion of Control, IOC)/依賴注入(Dependency Injection,DI)和面向切面編程(Aspect Oriented Programming,AOP)
2. IOC/DI: 它用來管理所有的java類,類對象的創建和依賴關系都由IOC/DI進行控制。控制反轉(IOC)和依賴注入(DI)在spring中表示同一種意思,只是看問題的角度不同,例如
當在A類中new一個B類時,控制權由A掌握,可以理解為控制正轉,當A類使用的B類實例有spring創建時,控制權由spring掌握,就是控制反轉;
依賴注入可以理解為A類依賴於spring,由spring注入B類。控制反轉是抽象的概念,只是提出了一種“控制”的方式,而依賴注入是spring框架實現“控制反轉”的具體方法。
3. IOC/DI工作原理:spring IOC/DI的更為直觀的叫法是容器,這是因為spring可以管理很多類,當需要某一類對象的實例時,spring就會提供相應的實例,就像是一個容器里面
可以放入很多東西,需要什么就取什么。那么在spring容器中都有什么類可以使用呢?這需要預先定義在spring的配置文件中,默認的配置文件名稱是applicationContext.xml
例如在配置文件中定義了A類和B類,而A類中使用到了B類,那么配置文件中再定義好這種依賴關系,即可由Spring自動地把B類實例注入到A類中,但是,這種注入是有條件的,
類需要符合Javabean的定義規范,在A類中需要定義對B類賦值的setter方法。這是Spring對管理的類唯一的要求,不需要像EJB那樣實現框架本身的任何接口,也是spring被稱
為輕量級框架的原因。
二、IOC/DI使用到的技術
1. JDOM:JDOM是對xml文件進行解析的技術,Spring的配置文件applicationContext.xml就是由JDOM進行解析的,它可以提取出xml文件中定義的標簽和屬性值。
1.1 環境的搭建:
1.2 StudentAction.java
public class StudentAction { private StudentService studentService; public void setStudentService(StudentService studentService) { this.studentService = studentService; } public void printName() { System.out.println(studentService.getName()); } }
1.3 StudentServiceImpl.java
public class StudentServiceImpl implements StudentService{ private StudentDao studentDao; public void setStudentDao(StudentDao studentDao) { this.studentDao = studentDao; } public String getName() { return studentDao.getName(); } }
1.4 StudentService.java
public interface StudentService { public String getName(); }
1.5 StudentDao.java
public interface StudentDao { public String getName(); }
1.6 StudentDaoImpl.java
public class StudentDaoImpl implements StudentDao{ public String getName() { return "Jike Wang"; } }
1.7 測試
public class TestAction { public static void main(String[] args) { //使用ApplicationContext接口的實現類ClassPathXmlApplicationContext加載spring配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml"); //通過ApplicationContext接口的getBean方法獲取id或name為studentAction的Bean實例 StudentAction studentAction = (StudentAction) applicationContext.getBean("studentAction"); //調用方法 studentAction.printName(); } }
1.8 使用jdom模擬spring解析xml文件,讀取關鍵信息
自定義XML代碼:
<?xml version="1.0" encoding="UTF-8"?> <beans> <!-- 定義StudentDaoImpl對象並指定id為studentDao --> <bean id="studentDao" class="com.IOC.dao.impl.StudentDaoImpl"></bean> <!-- 定義StudentServiceImpl對象並指定id為studentService--> <bean id="studentService" class="com.IOC.service.impl.StudentServiceImpl"> <property name="studentDao" ref="studentDao"></property> </bean> <!-- 定義StudentAction對象並指定id為studentAction --> <bean id="studentAction" class="com.IOC.action.StudentAction"> <property name="studentService" ref="studentService"></property> </bean> </beans>
public class TestJDOM { public static void main(String[] args) { String path = "src/main/resources/applicationContext.xml";//xml文件目錄 //用於創建文檔對象 SAXBuilder sb = new SAXBuilder(); //構造的XML文檔對象 Document doc; try { //創建文檔對象 doc = sb.build(path); //得到文檔的根元素<beans> Element rootElement = doc.getRootElement(); //得到文檔的所有<bean> List<Element> list = rootElement.getChildren("bean"); for (Element element : list) { //得到<bean>的id屬性值 String id = element.getAttributeValue("id"); //得到<bean>的class屬性值 String classValue = element.getAttributeValue("class"); //得到<bean>的子元素<property> Element propertyElement = element.getChild("property"); String propertyName = null; String propertyRef = null; if (propertyElement != null) { //得到<property>的name屬性值 propertyName = propertyElement.getAttributeValue("name"); //得到property的內容 propertyRef = propertyElement.getAttributeValue("ref"); } System.out.println("========================"); System.out.println("id="+id); System.out.println("class="+classValue); System.out.println("propertyName="+propertyName); System.out.println("propertyRef="+propertyRef); System.out.println("========================"); } } catch (Exception e) { e.printStackTrace(); } } }
測試結果:
2. 反射機制:對配置文件中的類名使用反射機制可以實現類加載初始化等工作,也可以調用類的方法進行屬性注入,java.lang.reflect提供了反射相關的工具
public class TestReflect { public static void main(String[] args) { //表示StudentDao接口全路徑 String studentDao = "com.IOC.dao.StudentDao"; //表示StudentService接口全路徑 String studentService = "com.IOC.service.StudentService"; //表示StudentDaoImpl類全路徑 String studentDaoImpl = "com.IOC.dao.impl.StudentDaoImpl"; //表示StudentServiceImpl String studentServiceImpl = "com.IOC.service.impl.StudentServiceImpl"; //表示StudentAction類全路徑 String studentAction = "com.IOC.action.StudentAction"; //表示setStudentService方法的字符串 String setStudentService = "setStudentService"; //表示setStudentDao方法的字符串 String setStudentDao = "setStudentDao"; try { //使用全路徑字符串加載StudentDao類別 Class studentDaoClass = Class.forName(studentDao); //使用全路徑字符串加載StudentService類別 Class studentServiceClass = Class.forName(studentService); //使用全路徑字符串加載StudentDaoImpl類別 Class studentDaoImplClass = Class.forName(studentDaoImpl); //使用全路徑字符串加載StudentServiceImpl類別 Class studentServiceImplClass = Class.forName(studentServiceImpl); //使用全路徑字符串加載StudentAction類別 Class studentActionClass = Class.forName(studentAction); //setStudentDao方法簽名,相當於獲取次此方法,使用類別獲取setStudentDao方法 Method setDaoMethod = studentServiceImplClass.getMethod(setStudentDao, studentDaoClass); //setStudentService方法簽名,使用類別獲取setStudentService方法 Method setServiceMethod = studentActionClass.getMethod(setStudentService, studentServiceClass); //創建StudentDaoImpl對象,相當於new StudentDaoImpl(),但返回的是Object對象 Object studentDaoImplnstance = studentDaoImplClass.newInstance(); //創建StudentServiceImpl對象,相當於new StudentServiceImpl(),但返回的是Object對象 Object studentServiceImplInstance = studentServiceImplClass.newInstance(); //創建StudentAction對象,相當於new StudentAction(),但返回的是Object對象 Object studentActionInstance = studentActionClass.newInstance(); //使用反射機制調用StudentServiceImpl的setStudentDao方法,參數是StudentDaoImpl對象, //第一個參數是執行方法的類實例,第二個參數是方法參數 setDaoMethod.invoke(studentServiceImplInstance, studentDaoImplnstance); setServiceMethod.invoke(studentActionInstance, studentServiceImplInstance); //調用StudentAction的printName方法 ((StudentAction)studentActionInstance).printName(); } catch (Exception e) { e.printStackTrace(); } } }
測試結果: