Spring源码(五):深入了解ApplicationContext

前面都是基于Spring的bean模块的BeanFactory接口及其默认实现类DefaultListableBeanFactory为例进行分析的,这次我们看下context模块的另一个重要的接口ApplicationContext。

一、类结构

ApplicationContext和BeanFactory两者都是用于加载bean的,但是相比之下,ApplicationContext提供了更多的扩展功能,简单一点说:ApplicationContext包含BeanFactory的所有功能。通常建议比BeanFactory优先使用。

我们先从类结构出发,如图

ApplicationContext类图

代码如下

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

	// 唯一标识id
	String getId();

	String getApplicationName();


	String getDisplayName();

	long getStartupDate();

	// ApplicationContext天生具有继承关系
	ApplicationContext getParent();

	// 天生兼容BeanFactory,且是可以支持注入的BeanFactory
	AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

下面对其父级进行说明。

二、父接口

1、MessageSource

实现信息资源国际化的接口。

// 天然支持多语言、国际化
public interface MessageSource {

	String getMessage(String code, Object[] args, String defaultMessage, Locale locale);

	String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;

	String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

2、ApplicationEventPublisher

事件发布的接口。

// 支持事件发布,可以在spring启动中,触发响应的事件监听
public interface ApplicationEventPublisher {

	void publishEvent(ApplicationEvent event);

}

3、ResourcePatternResolver

资源模式解析器的接口,继承自ResourceLoader接口。

// 加载类及类资源文件接口
public interface ResourcePatternResolver extends ResourceLoader {

	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

	Resource[] getResources(String locationPattern) throws IOException;

}

public interface ResourceLoader {

	/** Pseudo URL prefix for loading from the class path: "classpath:" */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;


	Resource getResource(String location);

	ClassLoader getClassLoader();

}

4、EnvironmentCapable

Spring环境获取的接口。

// 支持spring环境变量、配置获取
public interface EnvironmentCapable {

	/**
	 * Return the {@link Environment} associated with this component.
	 */
	Environment getEnvironment();

}

5、继承自BeanFactory的接口

还有两个接口分别是

  • ListableBeanFactory:可列举的bean工厂接口,定义了大量获取bean的方法。
  • HierarchicalBeanFactory:分层的bean工厂接口。

三、子接口

ApplicationContext只有三个子接口,而两个子接口下面有众多的子孙接口及实现类(Ctrl + h 可以查看类自上而下继承结构)。

1、ConfigurableApplicationContext

可配置的ApplicationContext接口。

// 主要是服务于ApplicationContext的全生命周期,加载配置、环境变量、应用BeanFactoryPostProcessor
// 发布spring事件、刷新ApplicationContext、销毁ApplicationContext
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {

	String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

	String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

	String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";

	String ENVIRONMENT_BEAN_NAME = "environment";

	String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";

	String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

	void setId(String id);

	void setParent(ApplicationContext parent);

	ConfigurableEnvironment getEnvironment();

	void setEnvironment(ConfigurableEnvironment environment);

	void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

	void addApplicationListener(ApplicationListener<?> listener);

	void refresh() throws BeansException, IllegalStateException;

	void registerShutdownHook();

	void close();

	boolean isActive();

	ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

2、WebApplicationContext

适用于Web环境的ApplicationContext接口,常见于比较原始Spring MVC场景。

// 与web环境相结合,适配web协议 javax.servlet.ServletContext
public interface WebApplicationContext extends ApplicationContext {

	String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

    // 各种web作用域
	String SCOPE_REQUEST = "request";

	String SCOPE_SESSION = "session";

	String SCOPE_GLOBAL_SESSION = "globalSession";

	String SCOPE_APPLICATION = "application";

	String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

	String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

	String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";

    // 想起servlet了吗?
    // 想起xml了吗?
	ServletContext getServletContext();
}

3、WebServerApplicationContext

WebServerApplicationContext是Spring Boot专用ApplicationContext。

// 支持内嵌tomcat
// 这是一条广告,欢迎关注公众号:好看的HK
public interface WebServerApplicationContext extends ApplicationContext {

	WebServer getWebServer();

    // 支持多服务多端口部署
	String getServerNamespace();
}

// 服务器接口
public interface WebServer {

	void start() throws WebServerException;

	void stop() throws WebServerException;

	int getPort();
}

4、ApplicationContextAware

@Component
public class Test implements ApplicationContextAware {

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// 真正干活的是 AnnotationConfigServletWebServerApplicationContext
        System.out.println(applicationContext.getClass());
        // true
        System.out.println(applicationContext instanceof WebServerApplicationContext);
        // true
        System.out.println(applicationContext instanceof WebApplicationContext);
    }
}

四、重要实现类

ApplicationContext接口功能远比BeanFactory接口强大,因此如果我们想要一个精简版的Spring环境(比如只想要IoC、不想要AOP或Web环境等特殊情况下),可以使用这些开箱即用的ApplicationContext。

先回忆一下远古的xml配置方式(这个配置文件后面还会出现)。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="testBean" class="xiaokui1.TestBean"/>
    <bean class="xiaokui1.AspectJTest"/>
</beans>

啊,这该死的回忆又涌上了心头!

1、ClassPathXmlApplicationContext

public static void main(String[] args) {
    // 使用相对类路径 ClassPathXmlApplicationContext
    // 固定文件路径的话,可以用 FileSystemXmlApplicationContext
    // 区别在 Resource 接口实现的不同
    ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("xiaokui1/xiaokui.xml");
    TestBean testBean = (TestBean)application.getBean("testBean");
    testBean.test();
}

2、AnnotationConfigApplicationContext

@SpringBootApplication
public class TestApp {

    public static void main(String[] args) {
        // web环境可以考虑用AnnotationConfigWebApplicationContext,但单独使用会有环境配置问题,不能建议直接使用
        // AnnotationConfigApplicationContext相对来说轻量级一点
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 扫描特定包下面类
        context.scan("site.xiaokui.app");
        // 刷新,触发bean的加载
        context.refresh();
        Object bean1 = context.getBean(TestController.class);
        // 正常输出 class site.xiaokui.app.controller.TestController
        System.out.println(bean1.getClass());
        Object bean2 = context.getBean(InitPrometheusData.class);
        // 正常输出 class site.xiaokui.app.task.InitPrometheusData$$EnhancerBySpringCGLIB$$ae07d98f
        System.out.println(bean2.getClass());

//        SpringApplication.run(TestApp.class, args);
//        log.info("========== web服务已成功启动!!! ==========");
    }
}
  • 25
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值