如何在 Spring Boot 类之间正确注入 @Autowired?

Posted

技术标签:

【中文标题】如何在 Spring Boot 类之间正确注入 @Autowired?【英文标题】:How to properly inject @Autowired between Spring Boot classes? 【发布时间】:2021-10-07 05:34:13 【问题描述】:

我有一个实现 interfaceA 的 classA,带有一个 methodA,然后我有一个 classB,我在其中调用带有 @Autowired 的 classA 以便能够使用 methodA,但它给了我一个警告,我必须为它创建一个方法A类。为什么会这样?在这种情况下,@Autowired 不是这样工作的吗?我应该只实例化classA吗?非常感谢您的回答。

A类

@RequiredArgsConstructor
public class RepositoryImpl implements IRepository 

    @Autowired
    private final TransactionDataMapper transactionDataMapper;

    @Autowired
    private SpringDataColminvoice springDataColminvoice;

    @Override
    public <S extends TransactionDto> S save(S s) 
        
        Colm colm = transactionDataMapper.toEntity(s);

        //methodA
        springDataColminvoice.save(colm);
        return null;
    

接口A

public interface IRepository extends IRepository<TransactionDto, Integer> 

B类

@Service
@RequiredArgsConstructor
public class ServiceImpl implements IInvoiceService 

    @Autowired
    private RepositoryImpl repositoryImpl;
        
    @Override
    public void save(CMessage cMessage) throws HandlerException 
        try 

            TransactionDto transactionDto = cMessage.getTransaction();

            // methodA
            repositoryImpl.save(transactionDto);
         catch (Exception e) 
            throw new HandlerException(e.getMessage());
        
    

例外

Action:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field RepositoryImpl in com.st.ms.yyu.d.binvoce.infraestructure.rest.spring.services.impl.InvoiceServiceImpl required a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.ServiceImpl' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'com.st.ms.yyu.d.binvoce.infraestructure.db.springdata.repository.impl.RepositoryImpl' in your configuration.

【问题讨论】:

能否请您编写示例代码和收到的警告? 确保methodA有一个公共访问器,并且一定要添加代码示例 @geobreze 我已经添加了代码,谢谢。 @DmitriiBykov 我已经添加了代码,谢谢。 很难阅读您发布的代码,但您的 A 类上可能缺少 @Service 注释。另外,您的 Spring 上下文是如何加载的? 【参考方案1】:

(发布此作为答案,因为我没有足够的声誉来发表评论)

正如其他人已经指出的那样,代码示例会有很大帮助。 话虽这么说,但听起来您缺少“ClassA”的实现。

如果您有“ClassA”实现的接口,则必须先在“ClassA”中实现接口的方法,然后才能使用它们。

我假设您的代码目前看起来有点像这样?

public interface InterfaceA 

    void methodA();



public class ClassA implements InterfaceA 


public class ClassB 

    @Autowired
    ClassA classA; // Cannot use @link InterfaceA#methodA because the class does not implement the function


如果这是您的代码,请确保在“ClassA”中添加“methodA()”函数的实现。有点像这样:

public class ClassA implements InterfaceA 

    @Override
    public void methodA() 
    


此外,为了在 Spring (Boot) 中自动装配,您需要确保将要自动装配的类标记为此类。您可以自动装配 bean。

要使示例中的“ClassA”符合自动装配条件,请确保将其实例化为:

一个 bean(使用 @Bean 注释)。 一个组件(使用@Component 注解)。 一个服务(使用@Service注解)。 可能与您的用例最匹配的任何其他注释。

在我们的示例中,这看起来有点像这样:

@Component // Or @Service / whatever you may need
public class ClassA implements InterfaceA 

    @Override
    public void methodA() 
    


希望这些对您有所帮助。万事如意!

-T

【讨论】:

【参考方案2】:

据我了解,@Autowire 意味着注入您放置注释@Autowire 的特定属性的值/实例。在这种情况下,@Autowire 仅在您的 Spring Boot 项目的 basePackage 中定义/创建的 Bean 可以匹配它时发生,即您的 @Autowire 所指的位置(意味着没有歧义等冲突问题和 DataType (Class) 可以被隐式转换)。在您的示例中,首先您将 IRepository 和/或 RepositoryImpl 视为 Repository 而不使用 @Repository 注释来通知 Spring Boot 默认配置这是一个 Repository bean。由于您没有放置 POM.xml 或发布相关代码,我假设您正在创建自己的存储库类。我认为在这里发布您的依赖项要好得多。

但正如其他人指出的那样。您需要创建一个可以匹配您放在 TransactDataManager 和 SpringDataColminvoice 上的 @Autowired 的 bean。您还需要通过注解通知 Spring Boot 或注册您的类 A 是 Bean

@Bean - defining a regular bean, 
@Component - a Component in the Project, 
@Service - a Service in the Project, 
@Repository - a Repository (if you're using Spring JPA), etc. 
@<Other Annotations depending of what other Spring Project/Dependencies your using>

由于 Spring 的较新版本正在转向基于 XML 映射的注释,我们需要根据角色使用上述示例注释从 @Autowired 自动注入/实例化的每个类/对象放置适当的注释/你的类/对象的目的是。

如果您不确定,我建议您。然后使用公共注解@Bean 创建一个典型的bean。所以你的A类可能是

@Component //Insert proper Annotation for your class if necessary. This is just a sample
@RequiredArgsConstructor
public class RepositoryImpl implements IRepository 

    @Autowired
    private final TransactionDataMapper transactionDataMapper;

    @Autowired
    private SpringDataColminvoice 
    springDataColminvoice;//segunda

    @Override
    public <S extends TransactionDto> S save(S s) 
       //Some implementation
    

    @Bean
    private TransactionDataMapper getTransactionDataMapper(<Some parameters if needed>)
       return <an instance for TransactionDataManager>;
    

    @Bean
    private SpringDataColminvoice getSpringDataColmInvoice(<Some parameters if needed>)
       return <an instance for SpringDataColminvoice>;
    

请注意,如果在外部类上已经有一个 Bean 定义,或者如果它被 @Service、@Component 或其他适当的注释等其他注释标记,并且另一个 bean 只是一个参考参数,则 2 个 bean 定义是可选的其他 bean 以便正确实例化。

在你的 B 类中是这样的:

public class ClassB 

    @Autowired
    ClassA classA; 

    /*Note: ignore this Bean definition if Class A is annotated with @Component,
       @Service, or other proper @Annotation for Class A.
    */
    @Bean
    private ClassA getClassA(<Some Parameters if Needed>)
       return <Instance of Class A>
    


请注意,如果您为您的 A 类添加了适当的注解(如 @Component、@Service 等),则无需在 B 类中添加 Bean 定义。

【讨论】:

以上是关于如何在 Spring Boot 类之间正确注入 @Autowired?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 工程中Bean的依赖注入分析

如何在 Spring Boot 中将属性注入测试类?

使用注入 java 和 spring boot 的 RestTemplate 类进行单元测试

Spring boot中普通工具类不能使用@Value注入yml文件中的自定义参数的问题

解决Spring Boot集成Shiro,配置类使用Autowired无法注入Bean问题

多部分表单数据输入 Java 模型属性未在请求类中注入元素 - Spring Boot