Spring的IOC/DI使用到的技術


一、了解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();
        }
    }
}

測試結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM