springboot用Depends_ON注解控制bean的依赖关系和创建顺序,用Configuration注解类设置bean之间的关系和多例模式,实现ApplicationContextAware接口后setApplication执行的时机,和访问的自动顺序,阻止空指针异常

项目+测试+测试配置工程结构:

本测试类中没有用到src/test/resources的资源文件

myconfigurations.java
@Configuration
public class myconfigurations  {

    @Autowired
    private Designgraph dg;
    
    @Bean(name = "car")  
    @Scope("prototype")     
    public Car car() {  
        Car car = new Car();
        car.setDg(dg);
        return car;
    }  

}

Designgraph.java
//一个设计图纸可以造很多车
@Component
public class Designgraph {
    private String graph = "car graph";
    public String Designcar(){
        return "benz"+graph;
    }
}

Car.java
public class Car {
    private String name;
    private Designgraph dg;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Designgraph getDg() {
        return dg;
    }
    public void setDg(Designgraph dg) {
        this.dg = dg;
    }    
}

SpringContextUtil.java
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private Logger LOGGER = LoggerFactory.getLogger(SpringContextUtil.class);
 
    // Spring应用上下文环境
    @Autowired
    private static ApplicationContext applicationContext;
 
    /**
     * 实现ApplicationContextAware接口的回调方法,设置上下文环境
     * 
     * @param applicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext c) {
        
        applicationContext = c;
        LOGGER.info("get appcontext:{}",applicationContext);
    }
 
    
    /**
     * 获取对象 这里重写了bean方法,起主要作用
     * 
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws BeansException
     */
    public static Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);
    } 
}

testscope.java
@RunWith(SpringRunner.class)
@SpringBootTest

public class testscope {
    Logger log = LoggerFactory.getLogger(testscope.class);

    @Test
    public void teststaticctx(){
        Car car1 = (Car)SpringContextUtil.getBean("car");
        System.out.println(car1);
        Car car2 = (Car)SpringContextUtil.getBean("car");
        System.out.println(car2);
    }
 
}

如果在myconfigurations.java的car()方法上没有添加  @Scope("prototype")这个注解,那么在testscope.java中调用SpringContextUtil.getBean("car")每次得到的都是同一个Bean

所以为了保证car多例, @Scope("prototype")这个注解是必须的;

怎样可以将SpringContextUtil.java的捕获ApplicationContext的功能结合到myconfigurations.java中?

怎样控制bean创建顺序,逻辑顺序?时间顺序?

代码地址:

https://github.com/KouReal/springbootstudy_buycar

myconfigurations实现了ApplicationContextAware接口,按照接口要求定义了setApplicationContext(Applicationcontext appcontext)方法;

然后自己为myconfigurations添加了static applicationcontext字段,static getBean(String name)方法;

现在要测试,在springboot启动后,主线程,其他线程都访问myconfigurations的applicationcontext字段,然后访问getbean方法,看看是否会有空指针异常,就是考虑是否会在myconfigurations完成实例化之前就执行到测试线程和其他线程的getbean方法,从而导致nullpointerexeception。

故意在myconfigurations的setApplicationContext(Applicationcontext appcontext)方法中设置了8秒的sleep

@Configuration
public class myconfigurations implements ApplicationContextAware{
    Logger log = LoggerFactory.getLogger(myconfigurations.class);
    public static ApplicationContext applicationcontext;
    ...
    
    @Bean(name="test222")
    public Test222 test222(){
        return new Test222();
    }

    @Override
    public void setApplicationContext(ApplicationContext actx) throws BeansException {
        try {
            log.info("setapplicationcontext sleep 8000:thread:{}",Thread.currentThread());
            Thread.currentThread().sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // TODO Auto-generated method stub
        applicationcontext=actx;
    }  
    public static Object getBean(String name) throws BeansException {
        return applicationcontext.getBean(name);
    }

}
class Test222{
    private int i;
}
@Test
    public void teststaticctx(){
        //test context
        ApplicationContext act = myconfigurations.applicationcontext;
        System.out.println("act is : "+act);
        try{
            Test222 test222 = (Test222) myconfigurations.getBean("test222");
            System.out.println("test222:"+test222);
        }catch(Exception e){
            System.out.println("getBean遭遇异常:"+e.getLocalizedMessage());
        }
        Thread th = new Thread(new Runnable() {
            
            @Override
            public void run() {
                //test context
                ApplicationContext act = myconfigurations.applicationcontext;
                System.out.println("act is : "+act);
                try{
                    Test222 test222 = (Test222) myconfigurations.getBean("test222");
                    System.out.println("test222:"+test222);
                }catch(Exception e){
                    System.out.println("getBean遭遇异常:"+e.getLocalizedMessage());
                }
                
                //boss买车
                log.info("testscope:thread:{}",Thread.currentThread());
                System.out.println(boss.seegrapth());
                Car car1 = (Car)myconfigurations.getBean("car");
                Car car2 = (Car)myconfigurations.getBean("car");
                System.out.println("boss buy:"+car1.getcontent());
                System.out.println("boss buy:"+car2.getcontent());
                try {
                    log.info("boss sleep...:thread:{}",Thread.currentThread());
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("boss wake up");
                Car car3 = (Car)myconfigurations.getBean("car");
                System.out.println("boss buy:"+car3.getcontent());
            }
        });
        th.start();
        
        try {
            th.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

myconfigurations实现了ApplicationContextAware接口,按照接口要求定义了setApplicationContext(Applicationcontext appcontext)方法;

然后自己为myconfigurations添加了static applicationcontext字段,static getBean(String name)方法;

现在要测试,在springboot启动后,主线程,其他线程都访问myconfigurations的applicationcontext字段,然后访问getbean方法,看看是否会有空指针异常,就是考虑是否会在myconfigurations完成实例化之前就执行到测试线程和其他线程的getbean方法,从而导致nullpointerexeception。

故意在myconfigurations的setApplicationContext(Applicationcontext appcontext)方法中设置了8秒的sleep

经过测试,发现没有发生上述现象,无论主线程还是其他线程都在阻塞等待8秒。有时间看下源码有哪些设计。

原文地址:https://www.cnblogs.com/CreatorKou/p/11328017.html