Spring中new出一個物件導致的空指標異常

燕子去了發表於2024-04-18

報錯概述

背景

單體專案升級微服務時,在BeforeSave_2250042中呼叫了一個公共模組CommonVerifyHandlerverifySeal()方法,但是執行時顯示空指標異常

程式碼

根據斷點和報錯資訊可以看到是這裡出錯

image

大致報錯內容

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2715c179] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@bd1cd86] will not be managed by Spring
==>  Preparing: select count(1) from 簽約主體對映組織檢視 where 簽約主體編號=? and 組織編號 = ? 
==> Parameters: QYZT-0001(String), ORG100000(String)
<==    Columns: COUNT(1)
<==        Row: 1
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2715c179]
[http-nio-8075-exec-1] 01/26 21:51:18.703 ERROR [c.d.s.beforesave.BeforeSave_2250042] - 不涉及金額合同 儲存前事件處理異常,功能編號:2250042,單據ID:624060420265480192,錯誤資訊:{}
java.lang.NullPointerException: null
	at com.dhcc.sdg.beforeinsert.CommonVerifyHandler.verifySeal(CommonVerifyHandler.java:41)
	at com.dhcc.sdg.beforesave.BeforeSave_2250042.doBefore(BeforeSave_2250042.java:46)
	at 
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79a446c1] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@bd1cd86] will not be managed by Spring
==>  Preparing: SELECT 集團內外 FROM 簽約方資訊檢視 WHERE 簽約方編號= ? AND DELETED_MARK =0 
==> Parameters: GYS-2022-013436(String)
<==    Columns: 集團內外
<==        Row: 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@79a446c1]

CommonVerifyHandler

@Component
public class CommonVerifyHandler {
    @Autowired
    public  CommonVerifyHandlerMapper commonVerifyHandlerMapper;
    /**
     * 驗證印章 xlm
     */
    public boolean verifySeal(BillData billData){
        boolean result = true;
        String PHY_ID = billData.getMasterData().get("PHY_SEAL_ID").toString().trim();
        String PHY_PARTY_ID = getSignPhyId( billData);
        System.out.println("PHY_ID:"+PHY_ID+",PHY_PARTY_ID:"+PHY_PARTY_ID);
        System.out.println("開始執行commonVerifyHandlerMapper.sealInfo");
        List<String> maps = commonVerifyHandlerMapper.sealInfo(PHY_ID, PHY_PARTY_ID);
        System.out.println("map:"+maps);
        if (maps == null || maps.isEmpty()) {
            result = false;
        }
        return result;
    }
}

錯誤一:

commonVerifyHandler沒有加入@Component註解被Spring管理

錯誤二:

BeforeSave_2250042commonVerifyHandler沒有被注入,相當於於commonVerifyHandler是new出來的


在Spring管理的類中直接透過new關鍵字來建立一個物件(模組)時,Spring容器本身是不會自動識別和管理這個新建立的物件的。Spring容器負責管理和裝配的是那些被它自己建立和初始化的bean。

使用new來建立一個物件時,這個物件是在Spring容器的控制之外的,也就是說,它不會享受到Spring容器的任何服務,比如依賴注入、事務管理、AOP等。

如果想要Spring容器能夠識別並管理一個物件,需要將這個物件宣告為一個Spring bean。這可以透過在類上新增@Component@Service@Repository@Controller等註解來實現,或者在Spring的配置檔案中顯式地宣告這個bean。

如果確實需要在Spring管理的類中建立一個新的物件,並且希望這個物件能夠享受到Spring容器的某些服務,你可以考慮使用ApplicationContext.getBean()方法來從Spring容器中獲取這個物件,而不是直接使用new來建立它。但是,這要求這個物件必須已經被宣告為一個Spring bean,並且已經被Spring容器初始化和管理。

另外,如果想要Spring容器能夠管理透過new關鍵字建立的物件的某些方面,可以考慮使用AspectJ等AOP框架來在執行時動態地為這些物件新增額外的行為。但是,這通常會增加系統的複雜性和維護成本,因此應該謹慎使用。

總之,直接在Spring管理的類中透過new來建立一個物件通常不是一個好的做法,除非有特殊的理由需要這樣做,並且瞭解這樣做可能帶來的後果。更好的做法是讓Spring容器來負責物件的建立和管理,這樣可以確保物件能夠享受到Spring容器提供的所有服務,並且更容易地進行單元測試和整合測試。

相關文章