Tại sao trường Spring @Autowired của tôi không có giá trị?


608

Lưu ý: Đây được dự định là một câu trả lời chính tắc cho một vấn đề phổ biến.

Tôi có một @Servicelớp Spring ( MileageFeeCalculator) có một @Autowiredtrường ( rateService), nhưng trường đó là nullkhi tôi cố gắng sử dụng nó. Nhật ký cho thấy cả MileageFeeCalculatorbean và MileageRateServicebean đang được tạo, nhưng tôi nhận được NullPointerExceptionbất cứ khi nào tôi cố gắng gọi mileageChargephương thức trên bean dịch vụ của mình. Tại sao mùa xuân không tự động lĩnh vực?

Lớp điều khiển:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = new MileageFeeCalculator();
        return calc.mileageCharge(miles);
    }
}

Lớp dịch vụ:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- should be autowired, is null

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); // <--- throws NPE
    }
}

Bean dịch vụ nên được tự động đăng nhập MileageFeeCalculatornhưng không phải:

@Service
public class MileageRateService {
    public float ratePerMile() {
        return 0.565f;
    }
}

Khi tôi cố gắng GET /mileage/3, tôi nhận được ngoại lệ này:

java.lang.NullPointerException: null
    at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
    at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
    ...

3
Một kịch bản khác có thể là khi bean Fđược gọi bên trong hàm tạo của bean khác S. Trong trường hợp này, chuyển bean yêu cầu Flàm tham số cho hàm tạo bean khác Svà chú thích hàm tạo của Svới @Autowire. Nhớ chú thích lớp của bean đầu tiên Fvới @Component.
aliopi

Tôi đã mã hóa một vài ví dụ rất giống với ví dụ này bằng Gradle tại đây: github.com/swimorsink/spring-aspectj-examples . Hy vọng ai đó sẽ tìm thấy nó hữu ích.
Ross117

Câu trả lời:


649

Trường được chú thích @Autowirednullbởi vì Spring không biết về bản sao MileageFeeCalculatormà bạn đã tạo newvà không biết để tự động xác định nó.

Bộ chứa Spring Inversion of Control (IoC) có ba thành phần logic chính: một thanh ghi (được gọi là ApplicationContext) các thành phần (đậu) có sẵn để ứng dụng sử dụng, một hệ thống cấu hình đưa các phụ thuộc của đối tượng vào chúng bằng cách khớp với phụ thuộc với các bean trong ngữ cảnh và một bộ giải phụ thuộc có thể xem xét cấu hình của nhiều loại đậu khác nhau và xác định cách khởi tạo và cấu hình chúng theo thứ tự cần thiết.

Bộ chứa IoC không phải là ma thuật và nó không có cách nào biết về các đối tượng Java trừ khi bạn bằng cách nào đó thông báo cho chúng về chúng. Khi bạn gọi new, JVM khởi tạo một bản sao của đối tượng mới và trao thẳng cho bạn - nó không bao giờ trải qua quá trình cấu hình. Có ba cách để bạn có thể cấu hình hạt đậu của mình.

Tôi đã đăng tất cả các mã này, sử dụng Spring Boot để khởi chạy, tại dự án GitHub này ; bạn có thể xem xét một dự án đang chạy đầy đủ cho từng phương pháp để xem mọi thứ bạn cần để làm cho nó hoạt động. Gắn thẻ với NullPointerException:nonworking

Tiêm đậu của bạn

Tùy chọn thích hợp nhất là để Spring tự động tất cả các loại đậu của bạn; điều này đòi hỏi số lượng mã ít nhất và có thể duy trì nhiều nhất. Để thực hiện công việc tự động như bạn muốn, cũng MileageFeeCalculatortự động thực hiện như thế này:

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

Nếu bạn cần tạo một phiên bản mới của đối tượng dịch vụ cho các yêu cầu khác nhau, bạn vẫn có thể sử dụng phép tiêm bằng cách sử dụng phạm vi Spring bean .

Tag hoạt động bằng cách tiêm @MileageFeeCalculatorđối tượng dịch vụ:working-inject-bean

Sử dụng @Configurable

Nếu bạn thực sự cần các đối tượng được tạo newđể tự động, bạn có thể sử dụng @Configurablechú thích Spring cùng với dệt thời gian biên dịch AspectJ để tiêm các đối tượng của bạn. Cách tiếp cận này chèn mã vào hàm tạo của đối tượng để thông báo cho Spring rằng nó đang được tạo để Spring có thể định cấu hình thể hiện mới. Điều này đòi hỏi một chút cấu hình trong bản dựng của bạn (chẳng hạn như biên dịch với ajc) và bật trình xử lý cấu hình thời gian chạy của Spring ( @EnableSpringConfiguredvới cú pháp JavaConfig). Cách tiếp cận này được sử dụng bởi hệ thống Bản ghi hoạt động của Roo để cho phép các newphiên bản của các thực thể của bạn nhận được thông tin lưu giữ cần thiết được đưa vào.

@Service
@Configurable
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService;

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile());
    }
}

Thẻ hoạt động bằng cách sử dụng @Configurabletrên đối tượng dịch vụ:working-configurable

Tra cứu bằng tay: không nên

Cách tiếp cận này chỉ phù hợp để giao tiếp với mã kế thừa trong các tình huống đặc biệt. Gần như luôn luôn thích hợp hơn để tạo một lớp bộ điều hợp đơn mà Spring có thể tự động và mã kế thừa có thể gọi, nhưng có thể trực tiếp yêu cầu bối cảnh ứng dụng Spring cho một bean.

Để làm điều này, bạn cần một lớp mà Spring có thể đưa ra một tham chiếu đến ApplicationContextđối tượng:

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

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

    public static ApplicationContext getContext() {
        return context;
    }
}

Sau đó, mã kế thừa của bạn có thể gọi getContext()và lấy các hạt mà nó cần:

@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
        return calc.mileageCharge(miles);
    }
}

Thẻ hoạt động bằng cách tìm kiếm thủ công đối tượng dịch vụ trong ngữ cảnh Spring: working-manual-lookup


1
Một điều khác cần xem xét là tạo các đối tượng cho các hạt trong một @Configurationhạt đậu, trong đó phương thức tạo một thể hiện của một lớp đậu cụ thể được chú thích bằng @Bean.
Donal Fellows

@DonalFellows Tôi không hoàn toàn chắc chắn về những gì bạn đang nói ("làm" là mơ hồ). Bạn đang nói về một vấn đề với nhiều cuộc gọi đến @Beancác phương thức khi sử dụng Spring Proxy AOP?
chrylis -cautiouslyoptimistic-

1
Xin chào, tôi đang gặp phải một vấn đề tương tự, tuy nhiên khi tôi sử dụng đề xuất đầu tiên của bạn, ứng dụng của tôi nghĩ rằng "calc" là null khi gọi phương thức "mileageFee". Như thể nó không bao giờ khởi tạo @Autowired MileageFeeCalculator calc. Có suy nghĩ gì không?
Theo

Tôi nghĩ bạn nên thêm một mục ở đầu câu trả lời của bạn giải thích rằng việc truy xuất bean đầu tiên, gốc mà bạn làm mọi thứ, nên được thực hiện thông qua ApplicationContext. Một số người dùng (mà tôi đã đóng dưới dạng trùng lặp) không hiểu điều này.
Sotirios Delimanolis

@SotiriosDelimanolis Hãy giải thích vấn đề; Tôi không chắc chính xác những gì bạn đang làm.
chrylis -cautiouslyoptimistic-

59

Nếu bạn không mã hóa một ứng dụng web, hãy đảm bảo rằng lớp của bạn trong đó @Autowires được thực hiện là một hạt đậu mùa xuân. Thông thường, container mùa xuân sẽ không nhận thức được lớp mà chúng ta có thể nghĩ là đậu mùa xuân. Chúng ta phải nói với container mùa xuân về các lớp học mùa xuân của chúng ta.

Điều này có thể đạt được bằng cách cấu hình trong appln-contxt hoặc cách tốt hơn là chú thích lớp là @Component và vui lòng không tạo lớp chú thích bằng toán tử mới. Hãy chắc chắn rằng bạn nhận được nó từ Appln-bối cảnh như dưới đây.

@Component
public class MyDemo {


    @Autowired
    private MyService  myService; 

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
            System.out.println("test");
            ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
            System.out.println("ctx>>"+ctx);

            Customer c1=null;
            MyDemo myDemo=ctx.getBean(MyDemo.class);
            System.out.println(myDemo);
            myDemo.callService(ctx);


    }

    public void callService(ApplicationContext ctx) {
        // TODO Auto-generated method stub
        System.out.println("---callService---");
        System.out.println(myService);
        myService.callMydao();

    }

}

xin chào, tôi đã đi qua giải pháp của bạn, điều đó là chính xác. Và ở đây tôi muốn biết "Tại sao chúng ta không tạo ra thể hiện của lớp chú thích bằng toán tử mới, tôi có thể biết lý do đằng sau đó không
Ashish

3
Nếu bạn tạo đối tượng bằng cách sử dụng mới, bạn sẽ xử lý vòng đời của bean, điều này mâu thuẫn với khái niệm IOC. Chúng ta cần yêu cầu container làm điều đó, theo cách tốt hơn
Shirish Coolkarni

41

Trên thực tế, bạn nên sử dụng Đối tượng được quản lý JVM hoặc Đối tượng được quản lý Spring để gọi các phương thức. từ mã trên của bạn trong lớp trình điều khiển, bạn đang tạo một đối tượng mới để gọi lớp dịch vụ có đối tượng tự động có dây.

MileageFeeCalculator calc = new MileageFeeCalculator();

vì vậy nó sẽ không hoạt động theo cách đó.

Giải pháp làm cho MileageFeeCalculator này trở thành một đối tượng tự động có dây trong chính Bộ điều khiển.

Thay đổi lớp Trình điều khiển của bạn như dưới đây.

@Controller
public class MileageFeeController {

    @Autowired
    MileageFeeCalculator calc;  

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

4
Đây là câu trả lời. Vì bạn đang tự tạo một MilageFeeCalculator mới, Spring không liên quan đến việc khởi tạo, vì vậy Spring spring không có kiến ​​thức về đối tượng tồn tại. Vì vậy, nó không thể làm bất cứ điều gì với nó, như tiêm phụ thuộc.
Robert Greathouse

26

Tôi đã từng gặp vấn đề tương tự khi tôi chưa quen the life in the IoC world. Các @Autowiredlĩnh vực của một trong những hạt cà phê của tôi là null khi chạy.

Nguyên nhân sâu xa là, thay vì sử dụng bean được tạo tự động được duy trì bởi bộ chứa Spring IoC (có @Autowiredtrường được indeedtiêm đúng cách), tôi là newingví dụ của riêng tôi về loại bean đó và sử dụng nó. Tất nhiên @Autowiredlĩnh vực này là vô giá trị vì Spring không có cơ hội tiêm nó.


22

Vấn đề của bạn là mới (tạo đối tượng theo kiểu java)

MileageFeeCalculator calc = new MileageFeeCalculator();

Với chú thích @Service, @Component, @Configurationđậu được tạo ra trong
bối cảnh ứng dụng của mùa xuân khi máy chủ được bắt đầu. Nhưng khi chúng ta tạo các đối tượng bằng toán tử mới, đối tượng không được đăng ký trong ngữ cảnh ứng dụng đã được tạo. Ví dụ lớp Employee.java tôi đã sử dụng.

Kiểm tra này:

public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    String name = "tenant";
    System.out.println("Bean factory post processor is initialized"); 
    beanFactory.registerScope("employee", new Employee());

    Assert.state(beanFactory instanceof BeanDefinitionRegistry,
            "BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
        if (name.equals(definition.getScope())) {
            BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);
            registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
        }
    }
}

}

12

Tôi mới đến Spring, nhưng tôi đã khám phá ra giải pháp làm việc này. Xin vui lòng cho tôi biết nếu đó là một cách đáng tin cậy.

Tôi làm Spring tiêm applicationContexttrong đậu này:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class SpringUtils {

    public static ApplicationContext ctx;

    /**
     * Make Spring inject the application context
     * and save it on a static variable,
     * so that it can be accessed from any point in the application. 
     */
    @Autowired
    private void setApplicationContext(ApplicationContext applicationContext) {
        ctx = applicationContext;       
    }
}

Bạn cũng có thể đặt mã này trong lớp ứng dụng chính nếu muốn.

Các lớp khác có thể sử dụng nó như thế này:

MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);

Theo cách này, bất kỳ bean nào cũng có thể được lấy bởi bất kỳ đối tượng nào trong ứng dụng (cũng được đặt xen kẽ với new) và theo cách tĩnh .


1
Mẫu này là cần thiết để làm cho đậu mùa xuân có thể truy cập được vào mã kế thừa nhưng nên tránh trong mã mới.
chrylis -cautiouslyoptimistic-

2
Bạn không mới đến mùa xuân. Bạn là dân chuyên nghiệp. :)
buổi sáng

bạn đã cứu tôi ...
Govind Singh

Trong trường hợp của tôi, tôi yêu cầu điều này vì có ít lớp bên thứ ba. Spring (IOC) đã không kiểm soát chúng. Các lớp này không bao giờ được gọi từ ứng dụng khởi động mùa xuân của tôi. Tôi đã làm theo phương pháp này và nó hiệu quả với tôi.
Malik

12

Có vẻ như đây là trường hợp hiếm gặp nhưng đây là những gì đã xảy ra với tôi:

Chúng tôi đã sử dụng @Injectthay vì @Autowiredtiêu chuẩn javaee được Spring hỗ trợ. Mỗi nơi nó hoạt động tốt và đậu được tiêm chính xác, thay vì một nơi. Tiêm đậu có vẻ giống nhau

@Inject
Calculator myCalculator

Cuối cùng, chúng tôi thấy rằng lỗi là do chúng tôi (thực ra là tính năng tự động hoàn thành của Eclipse) đã nhập com.opensymphony.xwork2.Injectthay vì javax.inject.Inject!

Vì vậy, để tóm tắt, hãy chắc chắn rằng chú thích của bạn ( @Autowired, @Inject, @Service, ...) có các gói đúng!


5

Tôi nghĩ rằng bạn đã bỏ lỡ để hướng dẫn mùa xuân để quét các lớp với chú thích.

Bạn có thể sử dụng @ComponentScan("packageToScan")trên lớp cấu hình của ứng dụng lò xo của bạn để hướng dẫn mùa xuân quét.

@Service, @Component chú thích vv thêm mô tả meta.

Spring chỉ tiêm các thể hiện của các lớp được tạo như bean hoặc được đánh dấu bằng chú thích.

Các lớp được đánh dấu bằng chú thích cần được xác định bằng lò xo trước khi tiêm, @ComponentScanhướng dẫn tìm mùa xuân cho các lớp được đánh dấu bằng chú thích. Khi Spring tìm thấy @Autowirednó tìm kiếm các bean liên quan và đưa vào thể hiện cần thiết.

Chỉ thêm chú thích, không sửa chữa hoặc tạo điều kiện cho việc tiêm phụ thuộc, Spring cần biết nơi để tìm.


gặp phải vấn đề này khi tôi quên thêm <context:component-scan base-package="com.mypackage"/>vào beans.xmltập tin của mình
Ralph Callaway

5

Nếu điều này xảy ra trong một lớp kiểm tra, hãy chắc chắn rằng bạn đã không quên chú thích lớp đó.

Ví dụ: trong Spring Boot :

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
    ....

Một thời gian trôi qua ...

Spring Boot tiếp tục phát triển . Không còn bắt buộc phải sử dụng @RunWith nếu bạn sử dụng đúng phiên bản JUnit .

Để @SpringBootTestlàm việc độc lập, bạn cần sử dụng @Testtừ JUnit5 thay vì JUnit4 .

//import org.junit.Test; // JUnit4
import org.junit.jupiter.api.Test; // JUnit5

@SpringBootTest
public class MyTests {
    ....

Nếu bạn nhận được sai cấu hình này kiểm tra của bạn sẽ biên dịch, nhưng @Autowired@Valuelĩnh vực (ví dụ) sẽ null. Vì Spring Boot hoạt động bằng phép thuật, bạn có thể có một vài cách để gỡ lỗi trực tiếp lỗi này.



Lưu ý: @Valuesẽ là null khi được sử dụng với staticcác trường.
tộc

Spring cung cấp nhiều cách để thất bại (không có sự trợ giúp từ trình biên dịch). Khi gặp sự cố, cách tốt nhất của bạn là quay lại hình vuông - chỉ sử dụng kết hợp các chú thích mà bạn biết sẽ hoạt động cùng nhau.
tộc

4

Một giải pháp khác sẽ là thực hiện cuộc gọi: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
Trình xây dựng MileageFeeCalculator như thế này:

@Service
public class MileageFeeCalculator {

    @Autowired
    private MileageRateService rateService; // <--- will be autowired when constructor is called

    public MileageFeeCalculator() {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
    }

    public float mileageCharge(final int miles) {
        return (miles * rateService.ratePerMile()); 
    }
}

Điều này sử dụng ấn phẩm không an toàn.
chrylis -cautiouslyoptimistic-

3

CẬP NHẬT: Những người thực sự thông minh đã nhanh chóng chỉ ra câu trả lời này , điều này giải thích sự kỳ lạ, được mô tả dưới đây

TRẢ LỜI GỐC:

Tôi không biết nó có giúp được ai không, nhưng tôi đã bị mắc kẹt với cùng một vấn đề ngay cả khi làm những việc có vẻ đúng. Trong phương thức chính của tôi, tôi có một mã như thế này:

ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {
        "common.xml",
        "token.xml",
        "pep-config.xml" });
    TokenInitializer ti = context.getBean(TokenInitializer.class);

và trong một token.xmltập tin tôi đã có một dòng

<context:component-scan base-package="package.path"/>

Tôi nhận thấy rằng gói.path không còn tồn tại, vì vậy tôi đã bỏ dòng này cho tốt.

Và sau đó, NPE bắt đầu tham gia. Trong một pep-config.xmltôi chỉ có 2 hạt đậu:

<bean id="someAbac" class="com.pep.SomeAbac" init-method="init"/>
<bean id="settings" class="com.pep.Settings"/>

và lớp Một số lớp có một thuộc tính được khai báo là

@Autowired private Settings settings;

vì một số lý do không rõ, cài đặt là null trong init (), khi <context:component-scan/>phần tử hoàn toàn không có, nhưng khi nó xuất hiện và có một số bs làm BasePackage, mọi thứ đều hoạt động tốt. Dòng này bây giờ trông như thế này:

<context:component-scan base-package="some.shit"/>

Và nó hoạt động. Có thể ai đó có thể đưa ra lời giải thích, nhưng đối với tôi nó là đủ ngay bây giờ)


5
Câu trả lời đó là lời giải thích. <context:component-scan/>ngầm cho phép <context:annotation-config/>cần thiết @Autowiredđể làm việc.
ForNeVeR

3

Đây là thủ phạm của việc đưa ra NullPulumException MileageFeeCalculator calc = new MileageFeeCalculator();Chúng tôi đang sử dụng Spring - không cần tạo đối tượng theo cách thủ công. Việc tạo đối tượng sẽ được chăm sóc bởi container IoC.


2

Bạn cũng có thể khắc phục sự cố này bằng cách sử dụng chú thích @Service trên lớp dịch vụ và chuyển lớp bean yêu cầuA làm tham số cho hàm tạo khác của lớp classB và chú thích hàm tạo của lớpB với @Autowired. Đoạn trích mẫu tại đây:

@Service
public class ClassB {

    private ClassA classA;

    @Autowired
    public ClassB(ClassA classA) {
        this.classA = classA;
    }

    public void useClassAObjectHere(){
        classA.callMethodOnObjectA();
    }
}

Điều này làm việc cho tôi bu bạn có thể vui lòng giải thích về cách giải quyết vấn đề này không?
CruelEngine

1
@CruelEngine, hãy xem đây là phương thức tiêm xây dựng (trong đó bạn thiết lập rõ ràng một đối tượng) thay vì chỉ sử dụng phương thức tiêm trường (điều này chủ yếu được thực hiện bởi cấu hình mùa xuân). Vì vậy, nếu bạn đang tạo một đối tượng của ClassB bằng cách sử dụng toán tử "mới" là một số phạm vi khác thì đó sẽ không được hiển thị hoặc thiết lập tự động cho ClassA. Do đó, trong khi gọi classB.useClassAObjectHere () sẽ ném NPE vì đối tượng classA không được tự động nếu bạn chỉ khai báo trường Tiêm. Đọc chrylis là cố gắng giải thích tương tự. Và đây là lý do tại sao tiêm constructor được khuyến cáo trên tiêm lĩnh vực. Liệu nó có ý nghĩa bây giờ?
Abhishek

1

Điều gì đã không được đề cập ở đây được mô tả trong này viết trong đoạn "Trình tự thực hiện".

Sau khi "học" rằng tôi phải chú thích một lớp với @Component hoặc các dẫn xuất @Service hoặc @Rep repository (tôi đoán là có nhiều hơn), để tự động xác nhận các thành phần khác bên trong chúng, tôi nhận ra rằng các thành phần khác này vẫn còn trống trong hàm tạo của thành phần cha mẹ.

Sử dụng @PostConstruct giải quyết rằng:

@SpringBootApplication
public class Application {
    @Autowired MyComponent comp;
}

và:

@Component
public class MyComponent {
    @Autowired ComponentDAO dao;

    public MyComponent() {
        // dao is null here
    }

    @PostConstruct
    public void init() {
        // dao is initialized here
    }
}

1

Điều này chỉ hợp lệ trong trường hợp kiểm tra đơn vị.

Lớp Dịch vụ của tôi có chú thích dịch vụ và đó là @autowiredmột lớp thành phần khác. Khi tôi kiểm tra lớp thành phần đã đến null. Bởi vì đối với lớp dịch vụ tôi đã tạo đối tượng bằng cách sử dụngnew

Nếu bạn đang viết bài kiểm tra đơn vị, hãy chắc chắn rằng bạn không tạo đối tượng bằng cách sử dụng new object(). Sử dụng thay thế tiêmMock.

Điều này đã khắc phục vấn đề của tôi. Đây là một liên kết hữu ích


0

Cũng lưu ý rằng, vì bất kỳ lý do gì, bạn thực hiện một phương thức @Servicenhư là final, các hạt tự động mà bạn sẽ truy cập từ đó sẽ luôn luôn như vậy null.


0

Nói một cách đơn giản, chủ yếu có hai lý do cho một @Autowiredlĩnh vựcnull

  • LỚP CỦA BẠN KHÔNG PHẢI LÀ MÙA XUÂN.

  • L FINH VỰC KHÔNG PHẢI LÀ MỘT BEAN.


0

Không hoàn toàn liên quan đến câu hỏi, nhưng nếu trường tiêm là null, thì hàm tạo dựa trên hàm tạo sẽ vẫn hoạt động tốt.

    private OrderingClient orderingClient;
    private Sales2Client sales2Client;
    private Settings2Client settings2Client;

    @Autowired
    public BrinkWebTool(OrderingClient orderingClient, Sales2Client sales2Client, Settings2Client settings2Client) {
        this.orderingClient = orderingClient;
        this.sales2Client = sales2Client;
        this.settings2Client = settings2Client;
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.