目录
一、BeanFactory与ApplicationContext的区别
五、通过继承ApplicationObjectSupport
六、通过继承WebApplicationObjectSupport
七、通过WebApplicationContextUtils
一、BeanFactory与ApplicationContext的区别
BeanFactory是Spring框架的基础设施,面向Spring本身。ApplicationContext则面向使用Spring框架的开发者,几乎所有的应用场景都可以直接使用ApplicationContext,而非底层的BeanFactory。
ApplicationContext的初始化和BeanFactory有一个重大的区别:
BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例目标Bean。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean,相对应的,ApplicationContext的初始化时间会比BeanFactory长一些。
二、通过BeanFactory获取
通过BeanFactory来获取Bean。
基于xml配置文件:(不推荐使用)
java
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
User user = (User) beanFactory.getBean("user");
三、通过BeanFactoryAware获取
获取BeanFactory实例最简单的方式就是实现BeanFactoryAware接口。
BeanFactoryAware接口源码:
java
public interface BeanFactoryAware extends Aware {
/**
* 初始化回调方法,Spring会自动将BeanFactory注入进去,接收之后即可使用BeanFactory
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
BeanFactoryAware属于org.springframework.beans.factory.Aware根标记接口,使用setter注入来在应用程序上下文启动期间获取对象。Aware接口是回调,监听器和观察者设计模式的混合,它表示Bean有资格通过回调方式被Spring容器通知。
示例如下:
java
@Component
public class BeanFactoryHelper implements BeanFactoryAware {
private static BeanFactory beanFactory;
/**
* 重写 BeanFactoryAware 接口的方法
* @param beanFactory :参数赋值给本地属性之后即可使用 BeanFactory
* @throws BeansException BeansException
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
BeanFactoryHelper.beanFactory = beanFactory;
}
/**
* 根据名称获取容器中的对象实例
* @param beanName :注入的实例必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
* @return Object
*/
public static Object getBean(String beanName) {
return beanFactory.getBean(beanName);
}
/**
* 根据 class 获取容器中的对象实例
* @param requiredType :被注入的必须已经存在容器中,否则抛异常:NoSuchBeanDefinitionException
* @param <T> Class
* @return 对象
*/
public static <T> T getBean(Class<T> requiredType) {
return beanFactory.getBean(requiredType);
}
/**
* 判断 spring 容器中是否包含指定名称的对象
* @param beanName bean名称
* @return 是否存在
*/
public static boolean containsBean(String beanName) {
return beanFactory.containsBean(beanName);
}
//其它需求皆可参考 BeanFactory 接口和它的实现类
}
上述基于BeanFactoryAware的特性,获得了BeanFactory,然后再通过BeanFactory来获得指定的Bean。
四、启动获取ApplicationContext
在项目启动时先获取ApplicationContext对象,然后将其存储在一个地方,以便后续用到时进行使用。
这里提供两种场景的获取:
1.基于xml配置bean的形式,适用于比较古老的项目,已经很少使用了;
2.基于SpringBoot启动时获取ApplicationContext对象;
基于xml的形式实现:
java
// 其中applicationContext.xml 为配置容器的xml,不过现在一般很少使用了
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
基于SpringBoot启动实现:
java
@SpringBootApplication
public class ExampleApplication {
public static void main(String[] args) {
// 启动时,保存上下文,并保存为静态
ConfigurableApplicationContext ac = SpringApplication.run(ExampleApplication.class, args);
SpringContextUtil.setApplicationContext(ac);
}
}
对应的SpringContextUtil类如下:
java
public class SpringContextUtil1 {
private static ApplicationContext ac;
public static <T> T getBean(String beanName, Class<T> clazz) {
T bean = ac.getBean(beanName, clazz);
return bean;
}
public static void setApplicationContext(ApplicationContext applicationContext){
ac = applicationContext;
}
}
五、通过继承ApplicationObjectSupport
此种方式依旧是先获得ApplicationContext容器,然后从中获取Bean对象,只不过是基于继承ApplicationObjectSupport类实现的。
具体实现代码:SpringContextUtil类需要实例化。
java
@Component
public class SpringContextUtil extends ApplicationObjectSupport {
public <T> T getBean(Class<T> clazz) {
ApplicationContext ac = getApplicationContext();
if(ac == null){
return null;
}
return ac.getBean(clazz);
}
}
ApplicationObjectSupport类图入下,我们看到它实现了ApplicationContextAware接口,在Spring容器初始化过程中回调方法setApplicationContext来完成ApplicationContext的赋值。
六、通过继承WebApplicationObjectSupport
WebApplicationObjectSupport是ApplicationObjectSupport的一个实现类,提供了Web相关的支持。实现原理与ApplicationObjectSupport一样。
具体实现代码如下:
java
@Component
public class SpringContextUtil extends WebApplicationObjectSupport {
public <T> T getBean(Class<T> clazz) {
ApplicationContext ac = getApplicationContext();
if(ac == null)
return null;
}
return ac.getBean(clazz);
}
}
通过类图我们可以看到它是ApplicationObjectSupport的实现子类,此方式除了继承对象不同外,没有其他区别,都是基于getApplicationContext方法来获取。
七、通过WebApplicationContextUtils
Spring提供了工具类WebApplicationContextUtils,通过该类可获取WebApplicationContext对象。
具体实现代码如下:
java
public class SpringContextUtil2 {
public static <T> T getBean(ServletContext request, String name, Class<T> clazz){
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request);
// 或者
WebApplicationContext webApplicationContext1 = WebApplicationContextUtils.getWebApplicationContext(request);
// webApplicationContext1.getBean(name, clazz)
T bean = webApplicationContext.getBean(name, clazz);
return bean;
}
}
这个方法很常见于SpringMVC构建的Web项目中,适用于Web项目的B/S结构。
八、通过ApplicationContextAware
通过实现ApplicationContextAware接口,在Spring容器启动时将ApplicationContext注入进去,从而获取ApplicationContext对象,这种方法也是常见的获取Bean的一种方式,推荐使用。
具体实现代码如下:
java
@Component
public class SpringContextUtil3 implements ApplicationContextAware {
private static ApplicationContext ac;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ac = applicationContext;
}
public static <T> T getBean(Class<T> clazz) {
T bean = ac.getBean(clazz);
return bean;
}
}
九、通过ContextLoader
使用ContextLoader提供的getCurrentWebApplicationContext方法,也是常用的获取WebApplicationContext的一种方法。
具体实现代码如下:
java
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
wac.getBean(beanID);
该方法常见于SpringMVC实现的Web项目中。该方式是一种不依赖于Servlet,不需要注入的方式。但是需要注意一点,在服务器启动时和Spring容器初始化时,不能通过该方法获取Spring容器。
十、通过BeanFactoryPostProcessor
Spring工具类,方便在非Spring管理环境中获取Bean。
java
@Component
public final class SpringUtils implements BeanFactoryPostProcessor{
/** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException{
SpringUtilsS.beanFactory = beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException{
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException{
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name){
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
*
* @param name
* @return boolean
* @throws NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException{
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException{
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
*
* @param name
* @return
* @throws NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException{
return beanFactory.getAliases(name);
}
/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker){
return (T) AopContext.currentProxy();
}
}
其中ConfigurableListableBeanFactory接口,也属于BeanFactory的子接口。
十一、通过工具类获取
RequestContextUtils.findWebApplicationContext(HttpServletRequest request)
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)
controller中获取:
java
public String test(HttpServletRequest request,HttpServletRequest response) {
WebApplicationContext wc = RequestContextUtils.findWebApplicationContext(request);
wc.getBean("beanName");
WebApplicationContext wc2 = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
wc2.getBean("beanName");
}
在service中或者其他后端服务中获取:
java
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
WebApplicationContext wc = RequestContextUtils.findWebApplicationContext(request);
WebApplicationContext wc2 = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
wc.getBean("beanName");
wc2.getBean("beanName");