专栏名称: 程序员鱼皮
鹅厂全栈开发,持续分享编程技法和实用项目
目录
相关文章推荐
半月谈  ·  品读 | 少用极端字眼吓孩子 ·  17 小时前  
瞭望智库  ·  马斯克要买OpenAI,图啥? ·  17 小时前  
半月谈  ·  “望宇”“探索”,定了! ·  昨天  
半月谈  ·  送戏下乡活动遇冷,莫让现场变秀场 ·  2 天前  
51好读  ›  专栏  ›  程序员鱼皮

关于 Bean 容器的注入方式,99 % 的人都答不全!

程序员鱼皮  · 公众号  ·  · 2024-06-05 12:23

正文

引言:在使用 Spring 框架开发应用程序时,依赖注入是一个至关重要的概念。而对于 Bean 容器的注入方式,虽然我们可能都有一定的了解,但实际上很多人在被问及这个问题时可能并不能完整地回答。本文将深入探讨 Spring 中 Bean 容器的注入方式,包括 XML 配置方式、基于注解方式、Java 配置方式以及自动扫描方式,并提供了详细的代码示例和解析,以便读者全面了解并掌握这些方式。

题目

关于 Bean 容器的注入方式,99 % 的人都答不全!

更多题目请见 面试刷题 小程序

推荐解析

1)XML配置方式

a) 基于属性注入

通过 元素的属性来注入依赖。主要有以下几种方式:

  • 构造器注入 使用 元素配置构造函数参数。

    "exampleBean" class="com.example.ExampleBean">
        "dependencyBean" />

  • Setter方法注入:使用 元素配置Setter方法注入的属性。

    "exampleBean" class="com.example.ExampleBean">
        "dependencyBean" ref="dependencyBean" />

  • 直接量注入:使用 元素配置基本类型或字符串等直接值。

    "exampleBean" class="com.example.ExampleBean">
        "exampleValue" />

b) 基于注解方式

使用 @Autowired @Inject @Resource 注解在类或字段上进行依赖注入。

  • 构造器注入:在类的构造器上使用 @Autowired 注解。

    @Component
    public class ExampleBean {
        private DependencyBean dependency;

        @Autowired
        public ExampleBean(DependencyBean dependency) {
            this.dependency = dependency;
        }
    }
  • Setter方法注入:在Setter方法上使用 @Autowired 注解。

    
    
    
    
    
        
    @Component
    public class ExampleBean {
        private DependencyBean dependency;

        @Autowired
        public void setDependency(DependencyBean dependency) {
            this.dependency = dependency;
        }
    }

2)Java配置方式

通过Java类来配置Bean,并使用 @Bean 注解将Bean注册到Spring容器。

@Configuration
public class AppConfig {

    @Bean
    public ExampleBean exampleBean() {
        return new ExampleBean(dependencyBean());
    }

    @Bean
    public DependencyBean dependencyBean() {
        return new DependencyBean();
    }
}

3)自动扫描方式

使用 @ComponentScan 注解来自动扫描和注册带有 @Component 及其衍生注解(如 @Service @Repository @Controller 等)的Bean。

package="com.example" />

或者在Java配置类中使用:

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // 配置其他Bean
}

4)注册BeanPostProcessor

实现 BeanPostProcessor 接口来在Bean初始化前后进行自定义处理,也可以用来动态注入Bean。

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ExampleBean) {
            // 自定义处理逻辑,如动态注入其他依赖
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

基于条件的 Bean 注册

import




    
 org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    @Conditional(WindowsCondition.class) // 注册条件:Windows 操作系统
    public OSInfo windowsInfo() 
{
        return new OSInfo("Windows");
    }

    @Bean
    @Conditional(LinuxCondition.class) // 注册条件:Linux 操作系统
    public OSInfo linuxInfo() 
{
        return new OSInfo("Linux");
    }
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String osName = System.getProperty("os.name");
        return osName.toLowerCase().contains("windows");
    }
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String osName = System.getProperty("os.name");
        return osName.toLowerCase().contains("linux");
    }
}

其他补充

鱼聪明 AI 的回答:

鱼聪明 AI 地址:https://www.yucongming.com/

初始化阶段的回调

  1. InitializingBean 接口 InitializingBean 是 Spring 提供的一个接口,当 Bean 实现该接口时,Spring 容器在实例化 Bean 后会自动调用其 afterPropertiesSet() 方法,用于执行初始化逻辑。

    import org.springframework.beans.factory.InitializingBean;

    public class MyBean implements InitializingBean {
        @Override
        public void afterPropertiesSet() throws Exception {
            // 执行初始化逻辑
        }
    }
  2. @PostConstruct 注解 @PostConstruct 是一个标准的 Java 注解,用于在 Bean 初始化之后执行特定的方法。当一个方法被 @PostConstruct 注解标记时,Spring 容器会在实例化 Bean 后立即调用该方法。

    import javax.annotation.PostConstruct;

    public class MyBean {
        @PostConstruct
        public void init() {
            // 执行初始化逻辑
        }
    }

销毁阶段的回调

  1. DisposableBean 接口 DisposableBean 是 Spring 提供的一个接口,当 Bean 实现该接口时,Spring 容器在销毁 Bean 之前会自动调用其 destroy() 方法,用于执行销毁逻辑。

    import org.springframework.beans.factory.DisposableBean;

    public class MyBean implements DisposableBean {
        @Override
        public void destroy() throws Exception {
            // 执行销毁逻辑
        }
    }
  2. @PreDestroy 注解 @PreDestroy 是一个标准的 Java 注解,用于在 Bean 销毁之前执行特定的方法。当一个方法被 @PreDestroy 注解标记时,Spring 容器会在销毁 Bean 之前调用该方法。

    import javax.annotation.PreDestroy;

    public class MyBean {
        @PreDestroy
        public void cleanup() {
            // 执行销毁逻辑
        }
    }

作用域(Scope)

在 Spring 中,Bean 的作用域决定了在容器中创建的 Bean 的可见范围和生命周期。Spring 框架提供了以下几种标准的作用域:

  1. Singleton(默认) :在整个应用程序中只创建一个 Bean 实例,并在容器启动时就进行创建。所有对该 Bean 的请求都将返回同一个实例。
  2. Prototype :每次请求该 Bean 时都会创建一个新的实例。这意味着每次通过容器获取该 Bean 时,都会返回一个新的实例。
  3. Request :在每个 HTTP 请求中创建一个新的 Bean 实例,仅在 Web 应用程序上下文中有效。每个 HTTP 请求都会有自己的 Bean 实例,并且该实例仅在当前请求内有效。
  4. Session :在每个 HTTP Session 中创建一个新的 Bean 实例,也仅在 Web 应用程序上下文中有效。每个 HTTP Session 都会有自己的 Bean 实例,并且该实例仅在当前 Session 内有效。
  5. GlobalSession :在一个全局的 HTTP Session 中创建一个 Bean 实例,通常在分布式应用程序中使用。与 Session 作用域类似,但是在集群环境中只有一个 Bean 实例,仅在当前全局 Session 内有效。







请到「今天看啥」查看全文