美文网首页Spring Step By StepJava学习笔记Android
番外 01:Spring IoC 实现原理简析,Java的反射

番外 01:Spring IoC 实现原理简析,Java的反射

作者: 赖赖oO | 来源:发表于2016-11-26 13:57 被阅读824次

    转载请注明来源 赖赖的博客

    前景概要

    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

    相关文章

      网友评论

        本文标题: 番外 01:Spring IoC 实现原理简析,Java的反射

        本文链接:https://www.haomeiwen.com/subject/bdqgpttx.html