1. 程式人生 > >番外 01:Spring IoC 實現原理簡析,Java的反射機制,通過類名建立物件

番外 01:Spring IoC 實現原理簡析,Java的反射機制,通過類名建立物件

轉載請註明來源 賴賴的部落格

前景概要

01 走進Spring,Context、Bean和IoC 中,我們看到了強大的Spring通過ApplicationContext實現了bean工廠(也就是物件工廠),那究竟是怎麼實現的呢,本次給大家寫一個小Demo展現其原理;

Spring bean的呼叫方式和配置方式

(詳情可以檢視 01 走進Spring,Context、Bean和IoC 這一課程)此處僅貼出程式碼,如果已經看過 01 走進Spring,Context、Bean和IoC 這一課,可以直接跳過前景概要。

執行App.java輸出結果如下

hello

App.java

package me.laiyijie.demo;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import me.laiyijie.demo.service.AccountService;

/**
 * Hello
 *
 */
public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");

        AccountService accountService = context.getBean(AccountService.class);

        System.out.println(accountService.sayHello());

        context.close();
    }
}

root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

    <bean class="me.laiyijie.demo.service.AccountService"></bean>

</beans>

AccountService.java

package me.laiyijie.demo.service;

public class AccountService {

    public String sayHello() {

        return "hello";
    }
}

pom.xml程式碼如下

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>me.laiyijie</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>

    </dependencies>
</project>

通過類名建立物件

問題引出和分析

在App.java中,調出AccountService用了兩步:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");

AccountService accountService = context.getBean(AccountService.class);

而root-context.xml中配置AccountService例項只用了一行配置

<bean class="me.laiyijie.demo.service.AccountService"></bean>

那麼問題來了,Spring是如何通過這一行配置檔案來建立這個物件的呢?

此處配置檔案只提供了一個類的全限定名me.laiyijie.demo.service.AccountService,那麼問題就轉化成:

如何通過類名建立物件

問題解決

要解決通過類名建立物件的問題就要引入Java的反射機制。

例項:通過類名建立物件

App.java
package me.laiyijie.demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import me.laiyijie.demo.service.AccountService;

public class App {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        Class clazz = classLoader.loadClass("me.laiyijie.demo.service.AccountService");

        Constructor constructor = clazz.getConstructor();

        AccountService accountService = (AccountService) constructor.newInstance();

        System.out.println(accountService.sayHello());
    }
}

沒有用到 new AccountService 卻成功建立了他的物件並呼叫其方法。

呼叫過程如下
  1. 通過Thread獲取當前的類載入器(ClassLoader
  2. 通過ClassLoader獲取me.laiyijie.demo.service.AccountService對應的Class物件
  3. 通過Class物件獲取建構函式對應的Constructor的物件
  4. 通過Contructor物件建立AccountService物件
  5. 呼叫sayHello方法

hello