Spring框架中的依赖检查机制详解

在大型项目开发中,多个开发者并行工作时,确保所有必需的依赖项都已正确设置是至关重要的。理想情况下,这种检查应该在编译时进行,如果不可能,那么至少在应用启动时尽早进行,以避免在缺少值时出现NullPointerException。Spring框架提供了多种在启动时进行依赖检查的机制。本文将探讨Spring框架在依赖检查方面的一些方面和选项。

构造器注入与Setter注入

在我们之前的教程中,我们讨论了依赖注入的不同方式,我们总是应该使用基于构造器的注入来处理必需的属性(并进行程序化的参数验证),而使用基于Setter的注入来处理可选属性。尽管如此,我们可能仍有许多理由选择使用Setter而不是构造器来注入必需的属性。可能是因为我们的构造器变得过于复杂,也可能是我们稍后想要重新配置某些属性(当然,在这种情况下它们不能是final的,但在连接时仍然是必需的)。

通过构造器进行依赖注入

如果缺少目标构造器所需的依赖项,Spring会抛出UnsatisfiedDependencyException

package com.logicbig.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@ComponentScan(useDefaultFilters = false,
        includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "ConstructorDiExample"))
public class ConstructorDiExample {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(ConstructorDiExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }
    @Component
    private static class ClientBean {
        private final ServiceBean serviceBean;
        private ClientBean(ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }
        void doSomething() {
            System.out.println("doing something with: " + serviceBean);
        }
    }
    //uncomment @service to get rid of UnsatisfiedDependencyException       
    //         private class ServiceBean {
    //         }
}
输出
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.logicbig.example.ConstructorDiExample$ServiceBean' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}  

在Setter注入中检查必需属性

如果我们是通过Setter进行必需依赖的注入,那么有以下几种依赖检查的选项:

使用Setter注入

对于Setter注入,我们不需要使用@Autowired。但对于依赖检查,我们需要明确使用这个注解。@Autowired注解的required属性默认为true。因此,如果Setter没有提供依赖项,Spring会抛出UnsatisfiedDependencyException

package com.logicbig.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Configuration
@ComponentScan(useDefaultFilters = false,            includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "SetterAutowiredExample"))
public class SetterAutowiredExample {
    public static void main(String... strings) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                SetterAutowiredExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }
    @Component
    public static class ClientBean {            private ServiceBean serviceBean;
        public void setServiceBean(ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }
        public void doSomething() {
            System.out.println("doing something with : " + serviceBean);
        }
    }
    //uncomment following to  get rid of UnsatisfiedDependencyException
    //@Service
    public static class ServiceBean {
    }
}
输出
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.logicbig.example.SetterAutowiredExample$ClientBean': Unsatisfied dependency expressed through method 'setServiceBean' parameter 0: No qualifying bean of type 'com.logicbig.example.SetterAutowiredExample$ServiceBean' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}  

PostConstruct方法中手动执行验证

PostConstruct方法中手动执行验证:

package com.logicbig.example;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import jakarta.annotation.PostConstruct;

public class PostConstructExample {
    public ClientBean clientBean (ServiceBean serviceBean) {
        ClientBean clientBean = new ClientBean();
        //uncomment following to get rid of IllegalArgumentException
        //clientBean.setServiceBean(serviceBean);
        return clientBean;
    }
    public ServiceBean serviceBean () {
        return new ServiceBean();
    }
    public static void main (String... strings) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(
                        PostConstructExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }
    public static class ClientBean {
        private ServiceBean serviceBean;
        public void myPostConstructMethod () throws Exception {
            // we can do more validation than just checking null values here
            if (serviceBean == null) {
                throw new IllegalArgumentException("ServiceBean not set");
            }
        }
        public void setServiceBean (ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }
        public void doSomething () {
            System.out.println("doing something with: " + serviceBean);
        }
    }
    public static class ServiceBean {
    }
}
输出
Caused by: java.lang.IllegalArgumentException: ServiceBean not set  

使用InitializingBean接口

InitializingBean定义

(版本:spring-framework 6.1.2)

package org.springframework.beans.factory;
........
public interface InitializingBean {
    void afterPropertiesSet() throws Exception; 1
}
| 1| Invoked by the Spring container after it has set all bean properties.
This method allows the bean instance to perform validation of its overall
configuration and final initialization when all bean properties have been set.  
示例
package com.logicbig.example;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class InitializingBeanExample {
    public ClientBean clientBean() {
        return new ClientBean();
    }
    //remove following comment to fix java.lang.IllegalArgumentException: ServiceBean not set
    //        public ServiceBean serviceBean() {
        return new ServiceBean();
    }
    public static void main(String... strings) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(
                        InitializingBeanExample.class);
        ClientBean bean = context.getBean(ClientBean.class);
        bean.doSomething();
    }
    private static class ClientBean implements InitializingBean {
        private ServiceBean serviceBean;
        public void setServiceBean(ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }
        public void doSomething() {
            System.out.println("doing something with: " + serviceBean);
        }
        public void afterPropertiesSet() throws Exception {
            if (serviceBean == null) {
                throw new IllegalArgumentException("ServiceBean not set");
            }
        }
    }
    private static class ServiceBean {
    }
}
输出
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientBean' defined in com.logicbig.example.InitializingBeanExample: ServiceBean not set  
    Caused by: java.lang.IllegalArgumentException: ServiceBean not set  

示例项目

使用的依赖和技术:

  • spring-context 6.1.2 (Spring Context)
    版本兼容性:4.3.0.RELEASE - 6.1.2版本列表
    ×
    spring-context的版本兼容性与此示例:
    • 4.3.0.RELEASE
    • 4.3.1.RELEASE
    • …(省略中间版本)
    • 6.1.2
      绿色版本已测试。
  • jakarta.jakartaee-api 10.0.0 (Eclipse Foundation)
  • JDK 17
  • Maven 3.8.1

兼容的Java版本:17+

此博客文章详细介绍了如何在Spring框架中进行依赖检查,包括构造器注入、Setter注入以及通过PostConstruct方法和InitializingBean接口进行手动验证。通过这些机制,可以确保在应用启动时或编译时就发现并处理依赖问题,从而避免运行时错误。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

t0_54coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值