BeanFactory与ApplicationContext
到底什么是BeanFactory 1.他是ApplicationContext的父接口 2.他才是Spring的核心容器,主要的ApplicationContext实现都组合了它的功能 3.ctrl+alt+u看一下关系图
看一下BeanFactory1.ctrl+f12看一下方法
2.可以看到BeanFactory没有特别多常用的方法,这里我们要认识到实际上一些功能,控制反转、依赖注入、直到Bean的生命周期等功能都是由BeanFactory的实现类提供的
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//引导类中的context就是我们的spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
System.out.println(context);
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjects.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.forEach((k, v) -> {
System.out.println(k + "=" +v);
});
}
}
ApplicationContext功能
MessageSource翻译国际化:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
//引导类中的context就是我们的spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
//可以从配置的翻译文本中读取不同的翻译信息,web开发时中文或者英文条件从浏览器的请求头中携带过来
context.getMessage("hello", null, Locale.CHINA);//输出hello
context.getMessage("hello", null, Locale.ENGLISH);//输出你好
}
}
ResourcePatternResolver
获取源路径
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
//引导类中的context就是我们的spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
//可以从配置的翻译文本中读取不同的翻译信息
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
}
}
获取环境变量信息EnvironmentCapable:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
//引导类中的context就是我们的spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
System.out.println(context.getEnvironment().getProperty("spring.messages.basename"));
}
}
事件发布器ApplicationEventPublisher:
定义事件
import org.springframework.context.ApplicationEvent;
public class StudentRegisteredEvent extends ApplicationEvent {
public StudentRegisteredEvent(Object source) {
super(source);
}
@Override
public String toString() {
return super.toString();
}
}
发布事件
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
//引导类中的context就是我们的spring容器
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
context.publishEvent(new StudentRegisteredEvent(123));
}
}
接收事件
import com.rlw.demo.event.StudentRegisteredEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Service
public class StudentService {
@EventListener
public void ask(StudentRegisteredEvent event){
System.out.println(event);
}
}
容器实现
BeanFactory实现的特点:beanFactory不会帮我们主动调用beanFactory的后处理器,也不会主动帮助我们调用bean的后处理器,也不会初始化单例,也不会解析${}、#{},所以ApplicationContext都帮助我们做了,接下来看ApplicationContext
package com.rlw.demo.TestBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class TestBeanFactory {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//bean的定义(class, scope, 初始化, 销毁)
AbstractBeanDefinition singleton =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config", singleton);
//给BeanFactory添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
// System.out.println(beanDefinitionName);
/**
* 还需要让这些后处理器去工作,不然不会解析config下的bean1,bean2
* config
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
* org.springframework.context.event.internalEventListenerProcessor
* org.springframework.context.event.internalEventListenerFactory
*/
// }
//beanFactory后处理器主要功能,补充了一些bean定义
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(postProcessor -> { postProcessor.postProcessBeanFactory(beanFactory); });
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
/**
* config
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor ->解析@Configuration的后处理器
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor ->解析@Autowired的后处理器
* org.springframework.context.annotation.internalCommonAnnotationProcessor ->解析@Resource的后处理器
* org.springframework.context.event.internalEventListenerProcessor ->
* org.springframework.context.event.internalEventListenerFactory
* bean1
* bean2
*/
}
// System.out.println(beanFactory.getBean(Bean1.class).getBean2() + "扩展bean处理器前"); //输出null
//Bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource
beanFactory.preInstantiateSingletons();//提前创建好单例bean,如果没有此行代码,都是懒惰式创建,什么时候用什么时候创建实例,工厂中只是存储了bean的名称
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);//假如一个接口存在多个实现类,我们依赖注入这个接口,能否依赖注入成功?答案是一般不行,除非依赖注入的接口名称 == 要注入的实例,或者使用@Qualifier限制,假如依赖注入同时使用了@Resource与@Aotowred,@Aotowred的优先级要高,在添加bean的后处理器代码顺序@Aotowred在前,可以手动调整
System.out.println(beanFactory.getBean(Bean1.class).getBean2() + "扩展bean处理器后"); //输出bean2对象
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {return new Bean1();}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
static class Bean1 {
public Bean1() {
System.out.println("bean1");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
}
static class Bean2 {
public Bean2() {
System.out.println("bean2");
}
}
}
ApplicationContext实现:
通过类路径下的xml的方式去注入bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean1" class="com.rlw.demo.TestBean.Bean1"></bean>
<bean id="bean2" class="com.rlw.demo.TestBean.Bean2"></bean>
//beanfactory的后处理器
<context:annotation-config/>
</beans>
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context1 = new ClassPathXmlApplicationContext("b01.xml");
for (String beanDefinitionName : context1.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
FileSystemXmlApplicationContext fileSystemXmlApplicationContext = new FileSystemXmlApplicationContext("D:\\spring29\\src\\main\\resources\\b01.xml");
for (String beanDefinitionName : fileSystemXmlApplicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
读取xml的原理,我们都知道ApplicationContext是基于BeanFactory去注入bean的,也就是基于BeanFactory去组合的功能
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取xml之前");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);//输出null
}
System.out.println("读取xml之后");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("b01.xml");
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);//输出bean1,bean2
}
}
}
基于java配置类:
@Configuration
public class Config2 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config2.class);
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
/**
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
* org.springframework.context.event.internalEventListenerProcessor
* org.springframework.context.event.internalEventListenerFactory
* config2
* bean1
* bean2
*/
}
}
基于java配置类来创建,用于web环境
@Configuration
public class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller() {
return ((request, response) -> {
response.getWriter().printf("hello");
return null;
}
);
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) throws Exception {
AnnotationConfigServletWebServerApplicationContext annotationConfigServletWebServerApplicationContext = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
}
Bean的生命周期
生命周期的各个阶段:在各个阶段都可以使用bean后处理进行相应的增强功能
@Component
public class LifeCycleBean {
public LifeCycleBean() {
System.out.println("构造方法");
}
@Autowired
public void autowired(@Value("${JAVA_HOME}") String name) {
System.out.println("依赖注入:" + name);
}
@PostConstruct
public void init() {
System.out.println("初始化");
}
@PreDestroy
public void destroy(){
System.out.println("销毁");
}
}
构造方法
依赖注入:C:\Program Files\Java\jdk1.8.0_201
初始化
bean1…
bean2…
2022-09-30 16:57:53.452 INFO 352996 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ‘’
2022-09-30 16:57:53.461 INFO 352996 — [ main] com.rlw.demo.A01Application : Started A01Application in 1.993 seconds (JVM running for 2.902)
2022-09-30 16:57:53.615 INFO 352996 — [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
销毁
待续