问题:springboot 项目 ,在@Component注解下@Autowired的类为null的情况,也就是没注入成功,或者说是此类在bean加载之前就被调用了。

前言

为什么SpringBoot可以省去配置文件?
其实Spring的注解可以解决大部分本来应该要写在配置文件中的内容,比如 如何将bean加入容器,AOP代理类、切面以及切点。但是不可以没有配置文件是因为有一些固定的类必须要在配置文件中写入,比如DispatchServlet,DataSource等,SpringBoot所做的就是将这些固定的配置自动化,不需要我们配置文件来实现;还有以往spring使用注解时需要手动在XML文件中配置自动注解扫描,springboot也自动做了这件事,以此省去了繁杂的配置文件

springboot自动配置:
 1、自动配置固定的bean @EnableAutoConfiguration
 2、自动进行注解扫描 @ComponentScan

我们知道,当我们自定义bean需要加入到容器中的时候,不是简单一个@Component就可以解决的了,需要有一些注意事项。具体有下面两种解决方法。

1、规范建立包,让SpringBoot自动扫描(推荐)

要想Springboot自动扫描注册你定义的bean一方面要加@Component标签,一方面必须要把类放在@ComponentScan能够扫描到的目录下面,也就是启动类的同级目录或者子目录下面(原因需要自己走一遍自动配置原理),这是因为@ComponentScan标签自动扫描的范围是启动类上一级目录下的所有类文件。

在这里插入图片描述
也就是这样,以上图为例,RedisApplication为我这边SpringBoot的启动类,想让SpringBoot自动将我们自定义的bean扫描为组件注册在容器中,必须配置在启动类同级目录config、utils等之下。像下图这样是不能直接被扫描到容器中的。
在这里插入图片描述

2、手动指定扫描路径

那实际开发中其实也有项目是这样建的包,那么怎么才能让SpringBoot扫描到我们自定义的bean呢?如果想要超出启动类自定义的范围,可以自定义 @ComponentScan标签并且自定义其解析范围、不过必须要加@Component,也就是下面的两个注解加在我们自定义的bean中。
在这里插入图片描述

如图,我们直接在启动类上自定义@ComponentScan扫描范围,记得一定要将启动类及其下面的子包强制扫描进容器。我们需要将@ComponentScan和@Component一起使用,由于SpringBootConfiguration下面包含了@Component,因此这儿就不需要加了。

加这个扫面所有包的原因是因为添加@ComponentScan之后SpringBoot就不会自己扫描启动类目录及其子目录了,因此需要我们手动指定扫描。
在这里插入图片描述

3、其他方法

3.1 声明一个此类的静态变量,用以保存bean。

使用@PostConstruct注解,将需要注入的类添加到静态变量中。
接下来,使用这个静态变量来调用注入类就行了。

package com.gblfy;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * @author tonghua
 * @ClassNme BaseCommon
 */
@Component//关键点 1 为spring组件
public class BaseCommon {

    //添加所需ConfigParam的私有成员
    @Resource
    private ConfigParam configParam;
    //  关键点2  静态初使化 一个工具类  这样是为了在spring初使化之前
    private static BaseCommon baseCommon;

    //关键 3   通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作
    @PostConstruct
    public void init() {
        baseCommon = this;
        // 初使化时将已静态化的configParam实例化
        baseCommon.configParam = this.configParam;
    }

    /**
     * @param serviceName
     * @throws Exception
     */
    @Transactional
    public void logWebService(String serviceName) throws Exception {
        //关键点 4 调用时请使用 此类静态变量 .对象 例如:baseCommon.configParam
        String params = baseCommon.configParam.getParams(serviceName);
        System.out.println("返回参数" + params);
    }
}

@PostConstruct这个注解的具体作用就是:

注解在方法上,表示此方法是在Spring实例化该bean之后马上执行此方法,之后才会去实例化其他bean。
这样在Spring实例化ComponentClass之后,马上执行此方法,初始化baseCommon静态对象和成员变量configParam

3.2 编写工具类实现ApplicationContextAware接口,重写setApplicationContext方法
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 获取java bean的工具
 */
@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    /**
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName) {
        return context.getBean(beanName);
    }
}

调用方式:

在无法引入的类中,通过beanName引入

    public RedisConfig getRedisConfig() {
        return SpringContextUtil.getBean("redisConfig");
    }

参考:
[1]、Spring Boot@Component注解下的类无法@Autowired的问题

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐