番外 01:Spring IoC 實現原理簡析,Java的反射機制,通過類名建立物件
阿新 • • 發佈:2019-02-02
轉載請註明來源 賴賴的部落格
前景概要
在 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
卻成功建立了他的物件並呼叫其方法。
呼叫過程如下
- 通過Thread獲取當前的類載入器(
ClassLoader
) - 通過
ClassLoader
獲取me.laiyijie.demo.service.AccountService
對應的Class
物件 - 通過
Class
物件獲取建構函式對應的Constructor
的物件 - 通過
Contructor
物件建立AccountService
物件 - 呼叫
sayHello
方法
hello