在使用注解的架构下做到在未IOC的class中(即普通类中)获取被Spring管理的Bean实例
其实本来可以直接通过加载 Spring 的 XML 配置文件来得到 ApplicationContext 对象,然后就可以直接通过 getBean() 方式来获取 Spring 管理的 Bean 实例。
但是现在都 8102 年了,还用这种方式未免太过不优雅。并且加载 XML 也不是我所喜欢的形式,我目前接触的项目都不用 XML 配置了。用 Annotations 来实现各大框架之间的架构在我看来也确实更加直观。
在开发中,Spring 的 IOC 和 DI 是需要经常用到的,总是会有各种服务、组件中的方法需要在别的类中使用。一般情况下都会通过 @Autowired/@Resource 等注解实现(这里以及下文均忽略 XML 配置)。
但是在使用 Annotations 的情况下想在一个普通的、不想被 Spring 管理的、想过平静生活的 class 中得到 Spring 所管理的类,是不可能直接做到的,由于 Spring DI 的前提就是需要将类的控制权转交到 Spring 手中(IOC)。作为一个普通的 class 并不会被 Spring 扫描并管理。这个时候要是想在普通 class 中得到 Spring 管理的类就需要由我们程序员给他一点小小的帮助。
自然,Spring 也早已有所料到会有这种需求,毕竟使用场景实在是太多了。比如一个Runnable或是Callable线程,在其中需要和数据库进行各种奇怪的交互,一般这种交互都是写到 Service 层被Spring 管理的,但是线程又不能被 Spring 管理,这玩意是得自己创建出的啊。这之间就有一面墙壁挡着,我区区一个线程,用不到 Service 层中的方法啊,这可咋搞?
最lowb的方法就是在创建线程时从线程类的构造方法中将其需要的服务类、工具类传过来,这好了,该线程与他的创建者之间的耦合性无敌爆炸强。并且方法丑陋,一个构造方法指不定多少参数,偏偏这种传过来的被 Spring 管理的类名字都挺长的。看起来更恶心了。
如果普通类能在不和 Spring 这个框架产生任何联系的情况下得到 Spring 所管理的类就好了…
所以,为了实现这个需求,可以通过实现 Spring 编写的 ApplicationContextAware Interface 来做一个工具类,这个工具类交给 Spring 管理,并且将获取 bean 的方法都静态化。从而在普通类中简单的得到想要的 Bean 实例。
Spring 在扫描各大文件时,如果发现有类实现了该接口,则会主动调用其实现的 setApplicationContext() 方法,将 Spring 上下文传入进去。
即在项目启动完成后,该类中就永远的保存了一个 ApplicationContext 对象。
这下,无论是什么类,都可以通过该对象来得到 Spring 所管理的 Bean 实例了。下面是我写的一个工具,可以直接复制使用。
package top.yibobo.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; } } //获取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); } }
这博客还真写的挺久的,代码3分钟,整理语言1小时,所以我才这么摸鱼啊…
能给人带来帮助就好了…
就算给不了别人帮助我以后自个写代码玩的时候也会来这copy一份拿来用…这时间还是消耗的不亏的