文章目录
1、Spring容器接口介绍
BeanFactory 接口
- Spring 的核心容器,ApplicationContext 的父接口
- 表面上只有 getBean,实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能, 都由它的实现类提供
ApplicationContext 接口
- 主要的 ApplicationContext 实现都【组合】了它的功能,【组合】是指 ApplicationContext 的一个重要成员变量就是 BeanFactory
- ApplicationContext 新增扩展功能:国际化、通配符方式获取多个Resource资源、事件发布与监听、整合 Environment 环境
2、容器接口功能实现
2.1、BeanFactory单例bean的存储
@SpringBootApplication
public class A01 {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
System.out.println(context);
}
}
- context下的beanFactory实现类DefaultListableBeanFactory对象下的singletonObje的Map成员变量下存储这单例bean对象
…
2.2、ApplicationContext国际化资源获取
- 配置文件设置相同的key,不同的value
- 如下,key都是”hi”,通过匹配不同的语言获取不同的value
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
System.out.println(context.getMessage("hi", null, Locale.CHINA));//你好
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));//Hello
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));//こんにちは
2.3、ApplicationContext通配符获取多资源
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
//classpath*:类路径+jar包类路径
Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
for (Resource resource : resources) {
System.out.println(resource);
}
输出结果:
URL [file:/F:/%e5%ad%a6%e4%b9%a0%e8%b5%84%e6%96%99/spring/%e4%bb%a3%e7%a0%81/show/target/classes/META-INF/spring.factories]
URL [jar:file:/E:/java/maven/mvnrep/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]
URL [jar:file:/E:/java/maven/mvnrep/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]
URL [jar:file:/E:/java/maven/mvnrep/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]
URL [jar:file:/E:/java/maven/mvnrep/org/mybatis/spring/boot/mybatis-spring-boot-autoconfigure/2.2.0/mybatis-spring-boot-autoconfigure-2.2.0.jar!/META-INF/spring.factories]
URL [jar:file:/E:/java/maven/mvnrep/com/alibaba/druid-spring-boot-starter/1.2.8/druid-spring-boot-starter-1.2.8.jar!/META-INF/spring.factories]
URL [jar:file:/E:/java/maven/mvnrep/org/springframework/spring-test/5.3.10/spring-test-5.3.10.jar!/META-INF/spring.factories]
2.4、ApplicationContext读取环境或配置文件信息
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
//环境信息
System.out.println(context.getEnvironment().getProperty("java_home"));
//配置文件信息
System.out.println(context.getEnvironment().getProperty("server.port"));
输出结果:
E:\java\jdk\jdk8\tools
8080
2.5、ApplicationContext发布事件
基本使用
- 创建事件类,source为事件发布对象
public class UserRegisteredEvent extends ApplicationEvent {
public UserRegisteredEvent(Object source) {
super(source);
}
}
- 发布事件,发布者为context
ConfigurableApplicationContext context = SpringApplication.run(A01.class, args);
Object obj = new Object();
context.publishEvent(new UserRegisteredEvent(obj));
- 设置监听方法
@Component
public class Component2 {
private static final Logger log = LoggerFactory.getLogger(Component2.class);
@EventListener
public void aaa(UserRegisteredEvent event) {
log.debug("{}", event);
}
}
输出结果:发布事件为UserRegisteredEvent,发布对象为Object
[DEBUG] 22:33:09.715 [main] com.itheima.a01.Component2
- com.itheima.a01.UserRegisteredEvent[source=java.lang.Object@5b051a5c]
实际应用
- 事件类依然为UserRegisteredEvent
- 发布事件对象this则为Register对象本身
@Component
public class Register {
private static final Logger log = LoggerFactory.getLogger(Register.class);
@Autowired
private ApplicationContext context;
public void register() {
log.debug("用户注册");
context.publishEvent(new UserRegisteredEvent(this));
}
}
- 短信监听类
@Component
public class Message {
private static final Logger log = LoggerFactory.getLogger(Message.class);
@EventListener
public void message(UserRegisteredEvent event) {
log.debug("{}", event);
log.debug("发送短信");
}
}
- 邮件监听类
@Component
public class Mail {
private static final Logger log = LoggerFactory.getLogger(Mail.class);
@EventListener
public void mail(UserRegisteredEvent event) {
log.debug("{}", event);
log.debug("发送邮件");
}
}
- 发布事件
@Autowired
private Register register;
...
//发布事件
register.register();
输出结果:
[DEBUG] 22:50:34.276 [main] com.itheima.a01.Register - 用户注册
[DEBUG] 22:50:34.277 [main] com.itheima.a01.Mail - com.itheima.a01.UserRegisteredEvent[source=com.itheima.a01.Register@341672e]
[DEBUG] 22:50:34.282 [main] com.itheima.a01.Mail - 发送邮件
[DEBUG] 22:50:34.282 [main] com.itheima.a01.Message - com.itheima.a01.UserRegisteredEvent[source=com.itheima.a01.Register@341672e]
[DEBUG] 22:50:34.282 [main] com.itheima.a01.Message - 发送短信
将用户注册后的后续不同的处理方式解耦,添加不同监听,则触发不同的事件操作
3、BeanFactory核心实现类 DefaultListableBeanFactory
- spring核心bean容器实现类
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
- 这个会创建一个GenericBeanDefinition普通bean定义对象返回
- bean definition 描述了这个bean 的创建蓝图:scope 是什么、用构造还是工厂创建、初始化销毁方法是什么,等等
- 此时bean定义只是被创建出来,还没有加入到bean容器中
BeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class)
.setScope("singleton")
.setLazyInit(false)
.getBeanDefinition();
- 被创建为bean definition的类:Config
@Configuration
class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
}
class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
- 将bean定义信息注册添加到容器中,并设置bean的名字
beanFactory.registerBeanDefinition("config", beanDefinition);
- bean定义信息添加bean容器中
- singletonObjes为空,则表明bean定义对应的对象依然没有生成
- 给 BeanFactory 添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
输出结果:这里返回的只是bean定义的名字
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 需要手动调用beanFactory后处理器对它做增强
- ConfigurationClassPostProcessor通过解析 @Bean、@ComponentScan 等注解,来补充一些 bean definition。如:bean1、bean2
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
System.out.println("BeanFactory后置处理器>>>>>>" + beanFactoryPostProcessor);
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
输出结果:
BeanFactory后置处理器>>>>>>org.springframework.context.annotation.ConfigurationClassPostProcessor@2a5c8d3f
BeanFactory后置处理器>>>>>>org.springframework.context.event.EventListenerMethodProcessor@1be2019a
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
bean1
bean2
- Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource
- 如果只是添加到List beanPostProcessors,则是懒加载,获取对象时候才会执行
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
System.out.println("Bean后置处理器>>>>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
@Configuration
class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
class Bean1 {
private static final Logger log = LoggerFactory.getLogger(Bean1.class);
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private Bean2 bean2;
public Bean2 getBean2() {
return bean2;
}
}
class Bean2 {
private static final Logger log = LoggerFactory.getLogger(Bean2.class);
public Bean2() {
log.debug("构造 Bean2()");
}
}
输出结果:
Bean后置处理器>>>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6fe7aac8
Bean后置处理器>>>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@1d119efb
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[DEBUG] 22:38:31.944 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1()
[DEBUG] 22:38:31.981 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2()
com.itheima.a02.TestBeanFactory$Bean2@15a04efb
- 修改以上代码,添加一行(准备好所有单例),由懒加载变为提前准备
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
System.out.println("Bean后置处理器>>>>>>" + beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
beanFactory.preInstantiateSingletons();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
输出结果:
Bean后置处理器>>>>>>org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@6fe7aac8
Bean后置处理器>>>>>>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@1d119efb
[DEBUG] 22:43:38.108 [main] c.itheima.a02.TestBeanFactory$Bean1 - 构造 Bean1()
[DEBUG] 22:43:38.144 [main] c.itheima.a02.TestBeanFactory$Bean2 - 构造 Bean2()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
com.itheima.a02.TestBeanFactory$Bean2@5e21e98f
4、常见ApplicationContext实现
4.1、基于classpath下xml格式的配置文件来创建
配置文件bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 控制反转, 让 bean1 被 Spring 容器管理 -->
<bean id="bean1" class="com.itheima.a02.A02.Bean1"/>
<!-- 控制反转, 让 bean2 被 Spring 容器管理 -->
<bean id="bean2" class="com.itheima.a02.A02.Bean2">
<!-- 依赖注入, 建立与 bean1 的依赖关系 -->
<property name="bean1" ref="bean1"/>
</bean>
</beans>
对象实体:
class Bean1 {
}
class Bean2 {
private Bean1 bean1;
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
public Bean1 getBean1() {
return bean1;
}
}
public class A01 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
}
输出结果:
bean1
bean2
com.xc.Bean1@53ca01a2
ClassPathXmlApplicationContext工作流程
//创建bean容器对象
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("读取之前...");
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println("读取之后...");
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
//读取配置文件
reader.loadBeanDefinitions(new ClassPathResource("bean.xml"));
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
4.2、基于磁盘路径下xml格式的配置文件来创建
public class A02 {
public static void main(String[] args) {
FileSystemXmlApplicationContext context =
new FileSystemXmlApplicationContext(
"D:\\demo\\src\\main\\resources\\bean.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
}
4.3、较为经典的容器, 基于java配置类来创建
配置类:
@Configuration
public class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2(Bean1 bean1) {
Bean2 bean2 = new Bean2();
bean2.setBean1(bean1);
return bean2;
}
}
启动类:
public class A03 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
}
输出结果:
Connected to the target VM, address: '127.0.0.1:58835', transport: 'socket'
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
Config
bean1
bean2
com.xc.Bean1@282cb7c7
Disconnected from the target VM, address: '127.0.0.1:58835', transport: 'socket'
Process finished with exit code 0
4.4、较为经典的容器, 基于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 controller1() {
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
启动类:
public class A03 {
public static void main(String[] args) {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
输出结果:
访问页面:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148606.html