多个@Configuration配置文件,引用方式。多配置文件引用时提示could not autowired时,没有扫描到注解所在的包。springboot中,ContextLoader.getCu


当需要一个 Bean 初始化后,利用其实例方法或者其他巴拉巴拉,来初始化当前 Bean ,引用方式。

引用方式

1、注入时添加 不必要 条件

2、添加 @DependsOn 或 @ConditionalOnBean注解,参数调用

3.  依赖不太复杂时,可使用 @Lazy 注解 

配置类1

package cc.ash.config;

import cc.ash.bo.Course;
import cc.ash.bo.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;

@Slf4j
@Configuration
public class InitConfig {

    /**
     * 1、注入时添加 不必要 条件
     * 2、添加 DependsOn 注解,参数调用其对象方法
     * 3. 依赖不太复杂时,可使用 @Lazy 注解
     */
    @Autowired(required = false)
    Course course;

    /**
     * @Dependson注解是在另外一个实例创建之后才创建当前实例,也就是,最终两个实例都会创建,只是顺序不一样
     *
     * @ConditionalOnBean注解是只有当另外一个实例存在时,才创建,否则不创建,也就是,最终有可能两个实例都创建了,有可能只创建了一个实例,也有可能一个实例都没创建
     */
    @Bean
    @Scope("prototype") //singleton(默认)、prototype、request、session
    @DependsOn(value = {"course"})
    public Student stu(Course course) {
        log.info(">>>>>>>>>>>>>>>>>>" + course.toString());
        return new Student();
    }
}

配置类2

package cc.ash.config;

import cc.ash.bo.Course;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class InitialConfig {

    @Bean
    public Course course() {
        return new Course();
    }
}

启动类

(不在基础包下,添加基础包扫描注解)

package cc.ash.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(value = "cc.ash")
@SpringBootApplication
public class PaymentMain8001 {

    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

junit测试类

package cc.ash.test;

import cc.ash.config.ApplicationContextRegister;
import cc.ash.springcloud.PaymentMain8001;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = PaymentMain8001.class)
public class Test {

    @org.junit.Test
    public void test() {

        System.out.println("Test.test");

        ApplicationContext applicationContext = ApplicationContextRegister.getApplicationContext();
        Object course1 = applicationContext.getBean("course");

        WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
        // java.lang.NullPointerException
        Object course = context.getBean("course");
    }

}

获取上下文配置类

>>> springboot中,ContextLoader.getCurrentWebApplicationContext()获取的为Null

springboot无论以main方法还是spring-boot:run的方式执行都不会跑SpringBootServletInitializer中的onStartup导致ContextLoaderListener没有执行。考虑到以往的经验ContextLoaderListener一般是配置在web.xml中的对web容器有依赖,所以我直接把工程打成war放到tomcat跑果然可以调用SpringBootServletInitializer中的onStartup,但是还是不能获取ContextLoader.getCurrentWebApplicationContext(),原因是在onStartup初始化ContextLoader时使用的是构造函数,没有用ContextLoader.initWebApplicationContext方式,所以获取不到,要用这种方式得重写SpringBootServletInitializer中的onStartup

package cc.ash.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
 * 确实有这个问题,我debug了一下源码,发现springboot无论以main方法还是spring-boot:run的方式执行都不会跑
 * SpringBootServletInitializer中的onStartup导致ContextLoaderListener没有执行。
 * 考虑到以往的经验ContextLoaderListener一般是配置在web.xml中的对web容器有依赖,
 * 所以我直接把工程打成war放到tomcat跑果然可以调用SpringBootServletInitializer中的onStartup,
 * 但是还是不能获取ContextLoader.getCurrentWebApplicationContext(),
 * 原因是在onStartup初始化ContextLoader时使用的是构造函数,
 * 没有用ContextLoader.initWebApplicationContext方式,所以获取不到,
 * 要用这种方式得重写SpringBootServletInitializer中的onStartup
 *
 * ApplicationContextRegister.getApplicationContext() .getBean("xx");就可以获取对应的bean
 */
@Component
@Lazy(false)
public class ApplicationContextRegister implements ApplicationContextAware {
    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationContextRegister.class);
    private static ApplicationContext APPLICATION_CONTEXT;

    /**
     * 设置spring上下文 
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        LOGGER.debug("ApplicationContext registed-->{}", applicationContext);
        APPLICATION_CONTEXT = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return APPLICATION_CONTEXT;
    }
}