Spring手动获取指定Bean
来源:互联网 发布:美国最高法院知乎 编辑:程序博客网 时间:2024/06/08 16:35
起因
由于项目需要把一个项目的某个功能移植到另一个项目中,但是两个项目结构不同,新写的接口不是被Spring容器管理的,没办法在接口中使用@Autowired注解自动注入Serivice(Ps.我这里说的接口是对外接口,不是Java中的interface,实际上是一个类),只能尝试手动注入。在网上查了查最终尝试了三种方式,对于我的问题前两种手动注入bean的方式都无法获取到实例,有效的只有方法三,先列出方法,问题分析在后面。
方法
方法一:使用BeanFactory
BeanFactory factory = new ClassPathXmlApplicationContext()("applicationContext.xml"); ac.getBean("beanName");
方法二:使用ApplicationContext
ApplicationContext ac = new ClassPathXmlApplicationContext()("applicationContext.xml"); ac.getBean("beanName");
方法三:实现ApplicationContextAware接口
写一个工具类去实现ApplicationContextAware接口,保存ApplicationContext为静态实例供全局调用。
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.util.Assert;public class BeanUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量. */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { BeanUtil.applicationContext = applicationContext; } /** * 取得存储在静态变量中的ApplicationContext. */ public static ApplicationContext getContext() { checkApplicationContext(); return applicationContext; } /** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { checkApplicationContext(); return (T) applicationContext.getBean(name); } /** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(Class<T> clazz) { checkApplicationContext(); System.out.println(clazz); return (T) applicationContext.getBeansOfType(clazz); } /** * 清除applicationContext静态变量. */ public static void cleanApplicationContext() { applicationContext = null; } private static void checkApplicationContext() { Assert.notNull(applicationContext, "applicationContext未注入,请在applicationContext.xml中定义BeanUtil"); }}
还需要在Spring的配置文件中application.xml中手动注册一下这个工具类
<bean id="beanUtil" class="com.xxx.util.BeanUtil" lazy-init="false"></bean>
然后在需要的地方就可以直接调用
TestService testService = BeanUtil.getBean("testService");
问题分析
一开始在使用@Autowired注解无法注入之后,先后尝试了前两种方案,打断点发现service同样是null,没有成功获取到bean,多方尝试之后最终仅有第三种方法成功了。至于问题的成因有过几种猜测:
猜测一: 看到网上有人说由于自己把自动扫包的配置全部放在的SpringMVC的配置文件里,而Spring上下文访问不到SpringMVC的上下文(反之可以),所以get不到bean。
我看了看项目的配置文件,不大可能是这种情况。
猜测二: 在多线程环境下,由于web容器不能感知线程的启动,所以Spring无法向线程中注入。Ps.如果由Spring管理线程池,似乎是可以自动注入的,这部分暂时没有细看,以后再做补充吧。
但是因为不清楚新的项目我做的这部分是否涉及到多线程,无法确定是否该原因。
猜测三: 这部分类没有被Spring管理,所以在类中也无法由Spring去注入,或者采取前两种方案时,由于不在同一个线程中所以获取到的context不是最开始的context,而是new了一个新的。
后两种猜想在本质上是有相似之处的,因为不管是线程还是类,同样都不是由Spring容器去管理,而是在需要的地方去new。经过与人探讨,认为大概率是这种情况。
其他
在上面的解决办法中还有一些需要注意的小细节
1. applicationContext获取bean的时候是可以通过byName或者byType的方式去获取到bean,在我们的工具类中可以看到分别调用了applicationContext的getBean和getBeansOfType方法,这里有一点需要注意,通过byName方式获取到的bean是直接返回的bean的实例,而byType方式则会返回一个Map集合,其中的key是bean的name,value则是bean的实例。我之前没注意到这一点,直接把byType方式的返回结果赋给了bean,结果出现了类型不能转换的错误。
2. BeanFactory和ApplicationContext加载bean的时候有一点不太一样的地方,BeanFactory采用的是延迟加载的方式,第一次用到bean的时候才会加载,而ApplicationContext则是在容器启动的时候一次性创建了所有的bean。它们还有很多其他不同之处,可以参考Spring中ApplicationContext和beanfactory区别。
3. 在手动加载bean的时候,需要注意关闭容器,否则容易造成数据库连接不能释放。推荐使用AbstractApplicationContext,使用完之后调用close方法释放资源
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");context.close();//释放资源
- Spring手动获取指定Bean
- spring手动注册bean,移除bean,获取bean
- 手动从spring WebApplicationContext 获取bean (一)
- 手动从spring BeanFactory 获取bean (二)
- servlet中手动获取spring的bean
- 手动获取Spring上下文和Bean对象
- spring手动初始化bean
- 手动注册 spring bean
- 手动获取spring的ApplicationContext和bean对象
- 手动获取spring的ApplicationContext和bean对象
- 通过spring手动获取bean报空指针问题
- 手动获取spring的application和bean属性
- BeanFactory作为Spring容器,程序需要手动获取Bean后处理器,然后手动注册!
- 在Servlet中获取Spring的指定bean
- Spring boot 手动注入bean
- Spring -- 手动调用spring托管BEAN
- 关于spring 的一些常见中手动获取bean 的 操作
- Spring手动扫描包路径及容器外获取Bean实例
- 算法作业_40(2017.6.22第十八周)
- CentOS安装GCC-4.8.5
- TCP/IP通信和UDP通信之间的区别
- 移动端拖动惯性
- Linux新手必备:8个实用的Linux终端命令
- Spring手动获取指定Bean
- Java Socket套接字
- Python3 BeautifulSoup爬虫 POJ自动提交
- kafka数据在zookeeper的存储结构(基于kafka0.8版本)
- 后台常见报错
- Tomcat单独可以启动,在Eclipse中启动访问404
- Ubuntu14.04 启动terminal进入命令行之前有log信息输出
- Android读写SD卡中的txt文件
- 微信获取code和openid