Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中不通过注解的形式(@Resource、@Autowired)获取Spring配置的bean呢?
Bean工厂(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制。BeanFactory使管理不同类型的Java对象成为可能,应用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用。我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。但有时为了行文方便,我们也将ApplicationContext称为Spring容器。
对于两者的用途,我们可以进行简单划分:BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合我们都直接使用ApplicationContext而非底层的BeanFactory。
工厂方式:
Resource resource = new ClassPathResource("applicationContext.xml"); BeanFactory factory = new XmlBeanFactory(resource); factory.getBean(strName);
ApplicationContext的初始化和BeanFactory有一个重大的区别:BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例目标Bean;而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。因此ApplicationContext的初始化时间会比BeanFactory稍长一些
附加信息,简要说明Spring什么时候实例化bean,首先要分2种情况
第一:如果你使用BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化
第二:如果你使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况:
(1):如果bean的scope是singleton的,并且lazy-init为false(默认是false,所以可以不用设置),则 ApplicationContext启动的时候就实例化该Bean,并且将实例化的Bean放在一个map结构的缓存中,下次再使用该Bean的时候, 直接从这个缓存中取
(2):如果bean的scope是singleton的,并且lazy-init为true,则该Bean的实例化是在第一次使用该Bean的时候进行实例化
(3):如果bean的scope是prototype的,则该Bean的实例化是在第一次使用该Bean的时候进行实例化
方法一:获取ApplicationContext的方法(多用于java工程)
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" );
ApplicationContext context = new FileSystemXmlApplicationContext("D:/Workspaces/MyEclipse Professional 2014/dubbo-customer/src/main/resources/applicationContext.xml" );
ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。
方法二:获取ApplicationContext的方法(多用于web项目)
ServletContext sc = request.getSession().getServletContext(); ApplicationContext ac1 = WebApplicationContextUtils .getRequiredWebApplicationContext(sc) ApplicationContext ac2 = WebApplicationContextUtils .getWebApplicationContext(sc) ac1.getBean("beanId"); ac2.getBean("beanId");
其中,获取ServletContext对象时的request.getSession().getServletContext()可以改成this.getServletContext()。
注意:当使用WebApplicationContextUtils获取ApplicationContext实例时,需要在web.xml配置文件中添加org.springframework.web.context.ContextLoaderListener监听器,否则获取不到ApplicationContext对象,返回Null。
web.xml配置:
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
方法三:继承自抽象类ApplicationObjectSupport
说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取到ApplicationContext。
Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。
方法四:继承自抽象类WebApplicationObjectSupport
通过继承org.springframework.web.context.support.WebApplicationObjectSupport使用getWebApplicationContext() 获取到org.springframework.web.context.WebApplicationContext
由于Web应用比一般的应用拥有更多的特性,因此WebApplicationContext扩展了ApplicationContext。WebApplicationContext定义了一个常量ROOT_WEB_APPLICATION_ CONTEXT_ATTRIBUTE,在上下文启动时,WebApplicationContext实例即以此为键放置在ServletContext的属性列表中,因此我们可以在java类中直接通过以下语句从Web容器中获取WebApplicationContext:
ServletContext sc = this.getServletContext(); WebApplicationContext wac = (WebApplicationContext)sc.getAttribute( WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); DemoService demoService = (DemoService)wac.getBean("demoService");
方法五:实现接口ApplicationContextAware(推荐)
实现该接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 对象。Spring初始化时,会通过该方法将ApplicationContext 对象注入。
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class AppContext implements ApplicationContextAware{ private static ApplicationContext applicationContext; /** * 当继承了ApplicationContextAware类之后,那么程序在调用 * getBean(String)的时候会自动调用该方法,不用自己操作 */ @Override public void setApplicationContext( org.springframework.context.ApplicationContext applicationContext) throws BeansException { this.applicationContext= applicationContext; } public Object getBean(String beanName){ return this.applicationContext.getBean(beanName); } }
需要在配置文件中注入该类的bean
<bean class="com.cn.customer.AppContext"/>
AppContext aContext = new AppContext(); DemoService demoService = (DemoService)aContext.getBean("demoService");