Spring Boot 2从入门到入坟 | 底层注解篇:使用@Import注解导入组件

在前一篇文章中,我们说了一下使用@Configuration注解结合@Bean注解来向容器中注册组件,以及Spring Boot给我们带来的两种配置模式,即Full模式和Lite模式。在这一篇文章中,咱们就来说说给容器中注册组件的其他方法,因为我们以前的方法也是可以使用的嘛!

例如,我们可以给类上标注一个@Component注解,以代表该类是一个组件,或者标注一个@Controller注解,以代表它是一个控制器,或者标注一个@Service注解,以代表它是一个业务逻辑组件,或者标注一个@Repository注解,以代表它是一个数据访问层的组件,以前的这些注解,我们依然也能用,而且,默认这些组件都是在包扫描的范围内哟😘。我们默认扫描的包是com.meimeixia.boot吧,也就是主配置类(又可以叫主程序类,或者主类)所在的包。我们除了能在主配置类里面写配置外,还可以使用@Configuration注解来自己自定义一些配置类哟,我们前面就是这么干的,还记得吗?

@Component、@Controller、@Service以及@Repository这些注解我就不再赘述了,包括@ComponentScan这个注解,要知道我们可以通过该注解来指定包扫描规则,这些注解相信大家以前也都用过,所以在这里我就不再赘述了。接下来,我就来为大家介绍另外一种给容器中添加组件的方式,即使用@Import注解给容器中导入一个组件。

那么,@Import注解应该写在哪儿呢?我们只要写在任何一个配置类或者组件里面都是可行的。注意,@Import注解要写在容器中的组件它所属类型的那个类上,这个类可以是配置类,也可以是其他注解(例如@Component、@Controller、@Service以及@Repository)标注的类,总之,只要是容器中组件所属类型的类都行。这里,我们不妨将其标注在MyConfig配置类上。

@Import注解的作用是什么呢?一听其意思,就知道它是用来导入组件的。我们不妨点进该注解的源码里面去看一看,如下图所示。

在这里插入图片描述

发现它里面有一个Class类型数组的属性,也就是说,我们可以通过@Import注解给容器中导入非常多的组件。比如,我们可以给容器中导入我们自己编写的组件,如User类型的组件,除此之外,还可以给容器中导入一些第三方jar包里面的东东,我们不妨随便找一个咱们maven项目中引进来的第三方jar包,就是logback-core-1.2.3.jar吧!

在这里插入图片描述

你想要导入该jar包中的哪个类的对象都行,不妨导入一下该jar包中DBHelper类的对象试试。

在这里插入图片描述

我们看看能不能把DBHelper类的对象给导入到容器中,如下所示,发现确实可以。

package com.meimeixia.boot.config;

import ch.qos.logback.core.db.DBHelper;
import com.meimeixia.boot.bean.Pet;
import com.meimeixia.boot.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @author liayun
 * @create 2021-04-23 19:42
 *
 */
@Import({User.class, DBHelper.class}) // 这时,就会给容器中自动创建出这两个类型的组件了
@Configuration(proxyBeanMethods = true) // 告诉Spring Boot这是一个配置类 == 配置文件
public class MyConfig {

    @Bean // @Bean注解是给容器中添加组件的。添加什么组件呢?以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例
    public User user01() {
        User zhangsan = new User("zhangsan", 18);
        // User类型的组件依赖了Pet类型的组件
        zhangsan.setPet(tomcatPet());
        return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet() {
        return new Pet("tomcat");
    }

}

此时,@Import({User.class, DBHelper.class})注解就会给容器中自动创建出User和DBHelper这两个类型的组件,注意,调用的是这两个类中的无参构造器来创建出的对象并放在容器中的哟!

那不妨我们现在来看一下容器中到底会不会有这两个组件?怎么验证呢?不就是从容器中获取组件吗,这有什么难的,但问题就是我们给容器中放了非常多User这种类型的组件,那咋个办呢?我们可以在主程序类中编写下面这样的代码来进行验证。

package com.meimeixia.boot;

import ch.qos.logback.core.db.DBHelper;
import com.meimeixia.boot.bean.Pet;
import com.meimeixia.boot.bean.User;
import com.meimeixia.boot.config.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

/**
 * 主程序类,也叫主配置类
 * @author liayun
 * @create 2021-04-19 4:02
 */
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.meimeixia.boot")
public class MainApplication {

    public static void main(String[] args) {
        // 1. 返回IoC容器,IoC容器里面就包含了当前应用的所有组件
        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args); // 这是固定写法哟
        // 2. 我们可以来查看下IoC容器里面所有的组件,只要能查找到某一个组件,就说明这个组件是能工作的,至于怎么工作,这就是我们后来要阐述的原理了
        String[] names = run.getBeanDefinitionNames(); // 获取所有组件定义的名字
        for (String name : names) {
            System.out.println(name);
        }
        
        // 3. 从容器中获取组件
        Pet tom01 = run.getBean("tom", Pet.class);
        Pet tom02 = run.getBean("tom", Pet.class);
        System.out.println("组件是否为单实例:" + (tom01 == tom02));

        // 配置类打印:com.meimeixia.boot.config.MyConfig$$EnhancerBySpringCGLIB$$4559f04d@49096b06
        MyConfig bean = run.getBean(MyConfig.class);
        System.out.println(bean);

        // 如果@Configuration(proxyBeanMethods = true),代理对象调用方法
        User user = bean.user01();
        User user1 = bean.user01();
        System.out.println("(user == user1) = " + (user == user1));

        User user01 = run.getBean("user01", User.class);
        Pet tom = run.getBean("tom", Pet.class);
        System.out.println("用户的宠物:" + (user01.getPet() == tom));

        // 4. 获取组件
        System.out.println("=====================");
        String[] beanNamesForType = run.getBeanNamesForType(User.class); // 获取我们给容器中注册的User类型的组件的名字
        for (String s : beanNamesForType) {
            System.out.println(s);
        }

        DBHelper bean1 = run.getBean(DBHelper.class);
        System.out.println(bean1);
    }

}

然后,我们运行主程序类,发现IDEA控制台打印结果如下。

在这里插入图片描述

可以看到,在容器中,有一个组件的名字叫com.meimeixia.boot.bean.User,还有一个组件的名字叫user01,为什么会有这两个组件呢?名字为user01的组件是我们使用@Bean方法添进去的,而另外一个名字为com.meimeixia.boot.bean.User的组件,是我们使用@Import注解导入进去的。由此看来,使用@Import注解导入的组件,默认该组件的名字就是其全类名。除此之外,使用@Import注解导入进去的DBHelper类型的组件,我们也获取到了。

温馨提示:@Import注解更高级的用法,请看笔者辛辛苦苦写的「史上最详细的Spring注解驱动开发系列教程」专栏,童叟未欺哟😘

相关推荐
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:白松林 返回首页