BeanFactory 与 ApplicationContext 关系的分析
BeanFactory 是 Spring 中最基本的接口,它是 Spring IoC 容器中最底层的接口,提供了 IoC 容器最基本的形式,它具有最基本的 IoC 功能,负责管理 Spring Bean 的生命周期,通过 BeanFactory 可以获取指定 Bean 的实例。 ApplicationContext 是 BeanFactory 的子接口,ApplicationContext 继承了 BeanFactory 接口的全部功能,同时还提供了其他的一些功能。ApplicationContext 是 Spring 中最重要的接口之一,它是 Spring 容器的具体实现,在 BeanFactory 的基础上添加了一些更加实用的功能,比如资源加载、事件发布、AOP 和事务等。 因此,可以认为 ApplicationContext 继承了 BeanFactory,拥有了更多的功能和扩展性。
ApplicationContext 继承的接口与功能
ResourceLoader:加载资源文件
MessageSource:国际化消息的源头
ApplicationEventPublisher:应用事件发布
EnvironmentCapable:获取当前应用的环境信息
ListableBeanFactory:提供了批量操作 Bean 的方法
HierarchicalBeanFactory:层次性的 BeanFactory,支持子容器
AutowireCapableBeanFactory:Bean 自动装配的 BeanFactory
BeanDefinitionRegistry:定义和注册 BeanDefinition 的接口
ConfigurableApplicationContext:ApplicationContext 可配置的接口,对外提供了修改 bean 定义、激活环境、注册 shut-down hook 等能力。
BeanFactory 应用代码示例
public class TestBean {
private String name;
public TestBean() {
System.out.println("constructor of TestBean is invoked");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class BeanFactoryExample {
public static void main(String[] args) {
Resource resource = new ClassPathResource("spring-config.xml");
BeanFactory factory = new XmlBeanFactory(resource);
TestBean testBean = (TestBean) factory.getBean("testBean");
System.out.println("The name is : " + testBean.getName());
}
}
复制代码
复制代码
其中,ClassPathResource 是一个用于从 classpath 中加载资源文件的类。XmlBeanFactory 是 Spring 提供的一个实现了 BeanFactory 接口的 IoC 容器实例。在实例化 XmlBeanFactory 时,需要提供一个 Resource 对象,这里传入的是 spring-config.xml 文件。
ApplicationContext 各功能的应用代码示例
ResourceLoader 接口的示例
public class ResourceLoaderExample {
public static void main(String[] args) throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
ResourceLoader loader = context;
Resource resource = loader.getResource("classpath:test.txt");
InputStream inputStream = resource.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
}
复制代码
复制代码
这段示例代码通过ApplicationContext
实例化了一个ResourceLoader
对象,然后通过getResource
方法加载了"classpath:test.txt"
文件。这个文件在 classpath 路径下,所以可以使用 classpath:
前缀来定位文件。
MessageSource 接口的示例
首先,需要在 Spring 配置文件中定义一个资源文件:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
复制代码
复制代码
然后,在 Java 代码中使用注入方式获取 MessageSource
实例:
public class MessageSourceExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
MessageSource messageSource = (MessageSource) context.getBean("messageSource");
String message = messageSource.getMessage("test", null, Locale.getDefault());
System.out.println("The message is : " + message);
}
}
复制代码
复制代码
这个示例代码中,我们通过 messageSource.getMessage("test", null, Locale.getDefault())
方法根据当前默认的语言获取了 messages.properties
中 test
属性的值。
ApplicationEventPublisher 接口的示例
我们可以在启动时发布一个事件:
public class MyApplicationEvent extends ApplicationEvent {
public MyApplicationEvent(Object source) {
super(source);
}
}
public class PublishEventExample {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
context.addApplicationListener(new ApplicationListener<MyApplicationEvent>() {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println("MyApplicationEvent received!");
}
});
context.publishEvent(new MyApplicationEvent("Hello World!"));
context.close();
}
}
复制代码
复制代码
当程序成功运行时,我们可以看到输出了 MyApplicationEvent received!
的信息。
EnvironmentCapable 接口的示例
这个接口用于获取当前运行的环境信息:
public class EnvironmentExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
Environment environment = context.getEnvironment();
System.out.println("The environment is : " + environment.getProperty("os.name"));
}
}
复制代码
复制代码
ListableBeanFactory 接口示例
这个接口中提供了一些批量操作 Bean 的方法:
public class ListableBeanFactoryExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
ListableBeanFactory beanFactory = context.getBeanFactory();
String[] beanNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
复制代码
复制代码
AutowireCapableBeanFactory 接口示例
这个接口用于完成 Bean 的自动装配:
public class AutowireCapableBeanFactoryExample {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
TestBean testBean = new TestBean();
beanFactory.autowireBean(testBean);
System.out.println("The name is : " + testBean.getName());
}
}
复制代码
复制代码
BeanDefinitionRegistry 接口示例
这个接口用于注册 Bean:
public class BeanDefinitionRegistryExample {
public static void main(String[] args) {
XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
BeanDefinition beanDefinition = new RootBeanDefinition(TestBean.class);
registry.registerBeanDefinition("testBean", beanDefinition);
TestBean testBean = (TestBean) beanFactory.getBean("testBean");
System.out.println("The name is : " + testBean.getName());
}
}
复制代码
复制代码
这个示例代码中,我们通过 BeanDefinitionRegistry
接口实现了向容器注册 TestBean
的过程。
ConfigurableApplicationContext 接口示例
这个接口用于修改 bean 定义、激活环境、注册 shut-down hook 等能力:
public class ConfigurableApplicationContextExample {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
ConfigurableEnvironment environment = context.getEnvironment();
environment.setActiveProfiles("dev");
context.refresh();
TestBean testBean = (TestBean) context.getBean("testBean");
System.out.println("The name is : " + testBean.getName());
}
}
复制代码
复制代码
在这个示例代码中,我们通过 ConfigurableApplicationContext
接口修改了当前的运行环境,激活了 dev 配置文件并重新刷新了容器,然后获取了 testBean
的实例并输出它的名称。
评论