Springboot框架自动装配原理之@Import注解作用

Springboot框架自动装配原理之@Import注解作用,第1张

Springboot框架自动装配原理之@Import注解作用 1. 简介

在平时看源码或者很多配置类上面都会出现@import注解,功能就是和Spring XML 里面 的 一样. @import注解是用来导入配置类或者一些需要前置加载的类.,springboot框架实现自动装配的原理之一正是利用这一特性解决了spring框架中重量级的xml配置

2. 源码解析

@import注解源码以及源码描述的翻译

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface import {

	
	Class[] value();

通过源码的描述翻译可以总结出@import可以通过以下四种方式导入一个bean(其实只有三种):

  • 导入普通类(4.2 版本之前只可以导入配置类,4.2版本之后 也可以导入 普通类)
  • 导入@Configuration配置类(@Configuration配置类已经是被注册为bean了,因此再用import导入没什么意义
  • 导入importSelector实现类
  • 导入importBeanDefinitionRegistrar实现类

3. 测试例子 3.1 导入普通类测试

配置类importConfig

package com.eureka.config;

import com.eureka.register.SelfimportBeanDefinitionRegistrar;
import com.eureka.selector.SelfimportSelector;
import com.eureka.service.TestA;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.import;

@Configuration
@import({TestA.class})
public class importConfig {
}

普通类TestA

public class TestA {

    public void printName() {
        System.out.println("我是一个注入的测试类A, " + TestA.class.getName());
    }
}

测试:

@SpringBootTest
public class ImprotTest {
    @Autowired
    private TestA testA;
    
    @Test
    public void test() {
        testA.printName();
    }
}

测试结果:


3.2 导入importSelector实现类测试

importSelector实现类如何导入bean,我们来分析下importSelector的源码

public interface importSelector {

	
	String[] selectimports(Annotationmetadata importingClassmetadata);

	
	@Nullable
	default Predicate getExclusionFilter() {
		return null;
	}

}

通过importSelector 源码的描述翻译可以得知importSelector 类的通过 selectimports方法返回的一个类全名的数组,spring容器根据这些类全名查找这些类并注册为bean;如果需要还可以通过getExclusionFilter方法过滤 selectimports返回的不需要注册为bean的类全名


下面分别创建TestB和TestC以及importSelector实现类:

public class TestB {

    public void printInfo() {
        System.out.println("我是一个注入的测试类B, " + TestA.class.getName());
    }
}
public class TestC {

    public void printInfo() {
        System.out.println("我是一个注入的测试类C, " + TestC.class.getName());
    }
}
public class SelfimportSelector implements importSelector {
    @Override
    public String[] selectimports(Annotationmetadata annotationmetadata) {
        return new String[]{"com.eureka.service.TestC","com.eureka.service.TestB"};
    }
}
@Configuration
@import({SelfimportSelector.class})
public class importConfig {
}

测试:

@SpringBootTest
public class ImprotTest {
    @Autowired
    private TestB testB;
    @Autowired
    private TestC testC;
   
    @Test
    public void test1() {
        testB.printInfo();
        testC.printInfo();
    }
}

测试结果:

3.3 导入importBeanDefinitionRegistrar实现类

importBeanDefinitionRegistrar实现类如何导入bean,我们来分析importBeanDefinitionRegistrar的源码

public interface importBeanDefinitionRegistrar {

	
	default void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassmetadata, registry);
	}

	
	default void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {
	}

}

根据源码可知 registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) 方法的参数BeanDefinitionRegistry 来注册一个bean对象,我们可以通过将需要注册为bean的类封装成一个BeanDefinition对象交由BeanDefinitionRegistry对象来处理,同时还可以为该类配置相应的属性,此 *** 作相当于spring xml中的bean标签内的所有配置


下面分别创建 DefaultTestService类 和 importTestService类 以及 importBeanDefinitionRegistrar 实现类 SelfimportBeanDefinitionRegistrar

public interface TestService {
    void printInfo();
}
public class DefaultTestService implements TestService {

    private String beanName;
    private String beanType;
    private Integer beanTime;

    @Override
    public void printInfo() {
        System.out.println("我是一个注入的default测试类, " + DefaultTestService.class.getName());
    }

	...getter setter略...
    
    @Override
    public String toString() {
        return "DefaultTestService{" +
                "beanName='" + beanName + ''' +
                ", beanType='" + beanType + ''' +
                ", beanTime=" + beanTime +
                '}';
    }
}
public class importTestService implements TestService {

    private String importName;
    private String importType;
    private String importTime;

    @Override
    public void printInfo() {
        System.out.println("我是一个注入的import测试类, " + importTestService.class.getName());
    }

	...getter setter略...
    
   	@Override
    public String toString() {
        return "importTestService{" +
                "importName='" + importName + ''' +
                ", importType='" + importType + ''' +
                ", importTime='" + importTime + ''' +
                '}';
    }
}
public class SelfimportBeanDefinitionRegistrar implements importBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {
    	// 创建DefaultTestService类的BeanDefinition对象
        RootBeanDefinition root = new RootBeanDefinition(DefaultTestService.class);
        MutablePropertyValues mpv = root.getPropertyValues();
        // 给DefaultTestService类设置属性
        mpv.addPropertyValue("beanName", "defaultTestService");
        mpv.addPropertyValue("beanType", DefaultTestService.class.getTypeName());
        mpv.addPropertyValue("beanTime", (int)(Math.random()*1000 + 200));
        // 创建importTestService类的BeanDefinition对象
        RootBeanDefinition root1 = new RootBeanDefinition(importTestService.class);
        MutablePropertyValues mpv1 = root1.getPropertyValues();
        // 给importTestService类设置属性
        mpv1.addPropertyValue("importName", "importTestService");
        mpv1.addPropertyValue("importType", importTestService.class.getTypeName());
        mpv1.addPropertyValue("importTime", (int)(Math.random()*1000 + 200));
        registry.registerBeanDefinition("defaultTestService", root);
        registry.registerBeanDefinition("importTestService", root1);
    }
}
@Configuration
@import({SelfimportBeanDefinitionRegistrar.class})
public class importConfig {
}

测试类:

@SpringBootTest
public class ImprotTest {
    @Resource(name = "defaultTestService")
    private TestService defaultTestService;
    @Resource(name = "importTestService")
    private TestService importTestService;

    @Test
    public void test3() {
        defaultTestService.printInfo();
        System.out.println(defaultTestService.toString());
        importTestService.printInfo();
        System.out.println(importTestService.toString());
    }
}

测试结果:

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5564018.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-14
下一篇2022-12-14

发表评论

登录后才能评论

评论列表(0条)

    保存