SpringBoot之普通类获取Spring容器中的bean

本文介绍在Spring Boot环境中,如何在任意类中全局获取Spring管理的Bean对象,包括在Spring Boot扫描包内和包外的两种情况,提供实用的SpringUtil工具类实现。

我们知道如果我们要在一个类使用spring提供的bean对象,我们需要把这个类注入到spring容器中,交给spring容器进行管理,但是在实际当中,我们往往会碰到在一个普通的Java类中,想直接使用spring提供的其他对象或者说有一些不需要交给spring管理,但是需要用到spring里的一些对象。如果这是spring框架的独立应用程序,我们通过

ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
ac.getBean("beanId"); 

这样的方式就可以很轻易的获取我们所需要的对象。

但是往往我们所做的都是Web Application,这时我们启动spring容器是通过在web.xml文件中配置,这样就不适合使用上面的方式在普通类去获取对象了,因为这样做就相当于加载了两次spring容器,而我们想是否可以通过在启动web服务器的时候,就把Application放在某一个类中,我们通过这个类在获取,这样就可以在普通类获取spring bean对象了,让我们接着往下看

1.在Spring Boot可以扫描的包下

写的工具类为SpringUtil,实现ApplicationContextAware接口,并加入Component注解,让spring扫描到该bean

springutil:

package me.shijunjie.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
        System.out.println("---------------------------------------------------------------------");

        System.out.println("---------------------------------------------------------------------");

        System.out.println("---------------me.shijunjie.util.SpringUtil------------------------------------------------------");

        System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringUtil.applicationContext+"========");

        System.out.println("---------------------------------------------------------------------");
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }

}

为了测试,我们再启动的时候先通过代码方式给spring容器中注入一个bean,入下所示

package me.shijunjie.config;

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

import me.shijunjie.entity.Demo2;

@Configuration
public class BeanConfig {
    @Bean(name="testDemo")
    public Demo2 generateDemo() {
        Demo2 demo = new Demo2();
        demo.setId(12345);
        demo.setName("test");
        return demo;
    }
}

然后我们编写测试controller,并从刚才写的springutil中获取这个bean

package me.shijunjie.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import me.shijunjie.util.SpringUtil;

@RestController
@RequestMapping("/application")
public class TestApplicationController {
    
    @RequestMapping("/test1")
    public Object testSpringUtil1() {
        return SpringUtil.getBean("testDemo");
    }
    
}

测试

启动web应用,打开浏览器输入http://localhost:8080/application/test1,测试成功

2 不在Spring Boot的扫描包下方式一

这种情况处理起来也很简单,先编写SpringUtil类,同样需要实现接口:ApplicationContextAware,具体编码如下:

package me.shijunjie.util;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringUtil2 implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil2.applicationContext == null) {
            SpringUtil2.applicationContext = applicationContext;
        }
        System.out.println("---------------------------------------------------------------------");

        System.out.println("---------------------------------------------------------------------");

        System.out.println("---------------me.shijunjie.util.SpringUtil------------------------------------------------------");

        System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringUtil2.applicationContext+"========");

        System.out.println("---------------------------------------------------------------------");
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }

}

使用@Bean注解,在App.java类中将SpringUtil2注解

package me.shijunjie.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;

import me.shijunjie.util.SpringUtil2;

@ComponentScan(basePackages={"me.shijunjie"}) // 扫描该包路径下的所有spring组件
/*@EnableJpaRepositories("me.shijunjie.dao") // JPA扫描该包路径下的Repositorie
*//*@EntityScan("me.shijunjie.entity") // 扫描实体类
*/@SpringBootApplication
@EnableScheduling
public class App extends SpringBootServletInitializer{
    @Bean
    public SpringUtil2 getSpringUtil2() {
        return new SpringUtil2();
    }
    
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

测试(使用热部署的需要重启服务器)

启动web应用,打开浏览器输入http://localhost:8080/application/test2,测试成功

除此以外,也可以在App.java中使用@Import进行导入。

package me.shijunjie.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling;

import me.shijunjie.util.SpringUtil2;

@ComponentScan(basePackages={"me.shijunjie"}) // 扫描该包路径下的所有spring组件
/*@EnableJpaRepositories("me.shijunjie.dao") // JPA扫描该包路径下的Repositorie
*//*@EntityScan("me.shijunjie.entity") // 扫描实体类
*/@SpringBootApplication
@EnableScheduling
@Import(SpringUtil2.class)
public class App extends SpringBootServletInitializer{
    /*@Bean
    public SpringUtil2 getSpringUtil2() {
        return new SpringUtil2();
    }*/
    
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

跑出结果和上面相同

注意:需要在被加载的bean上添加@DependsOn("springUtil")注解,保证springUtil在其之前被加载,防止加载依赖springUtil的bean时报空指针异常

<think>好的,我现在需要帮助用户解决在Spring Boot普通类获取Bean实例的问题。用户已经提供了一些引用资料,我需要结合这些信息来整理出一个清晰的回答步骤。 首先,根据引用1和引用2,用户提到了通过实现ApplicationContextAware接口来获取ApplicationContext。这是常见的方法,我记得ApplicationContextAware接口有一个setApplicationContext方法,可以用来注入ApplicationContext实例。然后,通过这个上下文就可以获取Bean了。需要创建一个工具类,比如SpringContextUtil,来保存ApplicationContext,并提供静态方法获取Bean。 然后引用3中的例子展示了如何从工具类中根据类名获取Bean实例。用户的问题是在普通类中如何调用这些方法,所以可能需要演示如何在普通类中调用SpringContextUtil.getBean()方法。 接下来,我需要考虑其他方法,比如使用@PostConstruct注解或者@Autowired静态变量,但可能这些方法有局限性或者需要额外的配置。比如,@Autowired需要Spring管理该类,而普通类可能没有被Spring管理,所以这种方法可能不适用。另外,用户提到的启动类设置ApplicationContext也是一种方式,但可能不如工具类方便。 还要注意线程安全问题,确保ApplicationContext的初始化正确。另外,要提醒用户避免在非Spring管理的类中频繁获取Bean,因为这可能违反IoC原则,导致代码耦合。 可能需要分步骤说明,首先介绍实现ApplicationContextAware接口的方法,然后提供工具类代码示例,再展示如何在普通类中使用这个工具类获取Bean。同时,指出其他方法,并比较它们的优缺点,最后给出注意事项。 需要检查代码示例是否正确,比如工具类的实现,静态变量和方法的正确性。确保ApplicationContext在set的时候正确赋值,并且工具类的方法能够正确获取Bean实例。 最后,生成相关问题,比如如何注入Bean到非Spring管理的类,或者ApplicationContextAware的工作原理,以及如何解决可能的空指针问题。</think>在Spring Boot项目中,从普通类(非Spring管理的类)中获取Bean实例,可以通过以下两种主要方法实现: ### 一、通过实现ApplicationContextAware接口(推荐方法) 1. **创建工具类**:定义实现`ApplicationContextAware`接口的上下文工具类 ```java @Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext context) { if (applicationContext == null) { applicationContext = context; } } // 根据名称获取Bean public static Object getBean(String name) { return applicationContext.getBean(name); } // 根据类型获取Bean public static <T> T getBean(Class<T> clazz) { return applicationContext.getBean(clazz); } // 根据名称+类型获取Bean public static <T> T getBean(String name, Class<T> clazz) { return applicationContext.getBean(name, clazz); } } ``` 2. **普通类中调用**:在任意普通类中通过静态方法获取Bean ```java public class CommonClass { public void doSomething() { // 通过类型获取 UserService userService = SpringContextUtil.getBean(UserService.class); // 通过名称获取 JWTConfig jwtConfig = (JWTConfig) SpringContextUtil.getBean("jwtConfig"); } } ``` ### 二、通过启动类设置上下文(备用方案) 在Spring Boot启动类中设置静态变量: ```java @SpringBootApplication public class Application { private static ApplicationContext context; public static void main(String[] args) { context = SpringApplication.run(Application.class, args); } public static ApplicationContext getContext() { return context; } } ``` ### 三、注意事项 1. **初始化时机**:需确保Spring容器初始化完成后再调用获取Bean的方法[^2] 2. **线程安全**:`ApplicationContext`在应用启动后是只读的,多线程访问安全 3. **设计规范**:应优先考虑依赖注入,仅在特殊场景使用该方法[^3] ### 四、性能优化建议 对于高频调用的Bean,建议在工具类中添加缓存机制: ```java private static Map<Class<?>, Object> beanCache = new ConcurrentHashMap<>(); public static <T> T getBeanWithCache(Class<T> clazz) { return (T) beanCache.computeIfAbsent(clazz, k -> applicationContext.getBean(clazz)); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值