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秒。有時間看下源碼有哪些設計。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM