17、SpringBoot 启动流程
17.1、Boot 代码示例
public class Test1_1 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// ConfigurableApplicationContext context = SpringApplication.run(Test1_1.class, args);
// 上面调用的 SpringApplication.run() 中做了如下几件事:
// 1、演示 获取 Bean Definition 源
System.out.println("---------------------------------");
System.out.println("1、演示获取 Bean Definition 源");
SpringApplication springApp = new SpringApplication(Test1_1.class);
// springApp.setSources(Collections.singleton("classpath:b01.xml")); // 添加 .xml 的来源
// 2、演示 推断应用类型
System.out.println("---------------------------------");
System.out.println("2、演示推断应用类型");
Method deduceFromClasspathMethod = WebApplicationType.class.getDeclaredMethod("deduceFromClasspath"); // 静态方法
deduceFromClasspathMethod.setAccessible(true);
System.out.println("\t应用类型为:" + deduceFromClasspathMethod.invoke(null));
// 3、演示 ApplicationContext 初始化器
System.out.println("---------------------------------");
System.out.println("3、演示 ApplicationContext 初始化器");
// 添加 自定义初始化器
springApp.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
// 方法参数:刚刚创建,但尚未 refresh() 的 ApplicationContext
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
if (applicationContext instanceof GenericApplicationContext) {
GenericApplicationContext context = (GenericApplicationContext) applicationContext;
context.registerBean("bean3", Bean3.class);
}
}
});
// 4、演示 监听器与事件
System.out.println("---------------------------------");
System.out.println("4、演示监听器与事件");
springApp.addListeners(new ApplicationListener<ApplicationEvent>() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("\t事件为:" + event.getClass());
}
});
// 5、演示 主类推断
System.out.println("---------------------------------");
System.out.println("5、演示主类推断");
Method deduceMainApplicationClassMethod = SpringApplication.class.getDeclaredMethod("deduceMainApplicationClass");
deduceMainApplicationClassMethod.setAccessible(true);
System.out.println("\t主类是:" + deduceMainApplicationClassMethod.invoke(springApp));
// 创建 ApplicationContext
ConfigurableApplicationContext context = springApp.run(args);
// 调用 初始化器 对 ApplicationContext 做扩展
// ApplicationContext.refresh()
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println("[ bean name: " + beanDefinitionName +
"] ----> [ 来源:" + context.getBeanFactory().getBeanDefinition(beanDefinitionName).getResourceDescription()
+ " ]"
);
}
context.close();
}
static class Bean1 {
}
static class Bean2 {
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
static class Bean3 {
}
// 补充 web 容器工厂
@Bean
public TomcatServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
结果:
---------------------------------
1、演示获取 Bean Definition 源
---------------------------------
2、演示推断应用类型
应用类型为:SERVLET
---------------------------------
3、演示 ApplicationContext 初始化器
---------------------------------
4、演示监听器与事件
---------------------------------
5、演示主类推断
主类是:class com.clp.test1.Test1_1
事件为:class org.springframework.boot.context.event.ApplicationStartingEvent
事件为:class org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
......
事件为:class org.springframework.boot.context.event.ApplicationContextInitializedEvent
......
事件为:class org.springframework.boot.context.event.ApplicationPreparedEvent
......
事件为:class org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent
事件为:class org.springframework.context.event.ContextRefreshedEvent
......
事件为:class org.springframework.boot.context.event.ApplicationStartedEvent
事件为:class org.springframework.boot.availability.AvailabilityChangeEvent
事件为:class org.springframework.boot.context.event.ApplicationReadyEvent
事件为:class org.springframework.boot.availability.AvailabilityChangeEvent
[ bean name: org.springframework.context.annotation.internalConfigurationAnnotationProcessor] ----> [ 来源:null ]
[ bean name: org.springframework.context.annotation.internalAutowiredAnnotationProcessor] ----> [ 来源:null ]
[ bean name: org.springframework.context.annotation.internalCommonAnnotationProcessor] ----> [ 来源:null ]
[ bean name: org.springframework.context.event.internalEventListenerProcessor] ----> [ 来源:null ]
[ bean name: org.springframework.context.event.internalEventListenerFactory] ----> [ 来源:null ]
[ bean name: bean3] ----> [ 来源:null ]
[ bean name: test1_1] ----> [ 来源:null ]
[ bean name: org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory] ----> [ 来源:null ]
[ bean name: bean2] ----> [ 来源:com.clp.test1.Test1_1 ]
[ bean name: servletWebServerFactory] ----> [ 来源:com.clp.test1.Test1_1 ]
事件为:class org.springframework.boot.availability.AvailabilityChangeEvent
事件为:class org.springframework.context.event.ContextClosedEvent
......
17.2、Boot 启动过程
1、创建 SpringApplication 对象:
- 记录 BeanDefinition 源;
- 推断应用类型;
- 记录 ApplicationContext 初始化器;
- 记录监听器;
- 推断主启动类。
2、执行 run() 方法:
- 得到 SpringApplicationRunListeners,名字取得不好,实际是事件发布器,发布 application starting 事件;
- 封装启动 args;
- 准备 Environment 添加命令行参数 (*);
- ConfigurationPropertySources 处理 (*):发布 application environment 已准备 事件;
- 通过 EnvironmentPostProcessorApplicationListener 进行 env 后处理 (*):① application.properties,由 StandardConfigDataLocationResolver 解析;② spring.application.json。
- 绑定 spring.main 到 SpringApplication 对象 (*)。
代码演示1:
public class Test1_2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
InstantiationException, IllegalAccessException {
// 添加 app 监听器
SpringApplication springApp = new SpringApplication();
springApp.addListeners(e -> System.out.println(e.getClass()));
// 获取事件发布器(SpringApplicationRunListener)的 实现类名
List<String> names = SpringFactoriesLoader.loadFactoryNames(SpringApplicationRunListener.class, Test1_2.class.getClassLoader());
for (String name : names) {
System.out.println(name);
Class<?> clazz = Class.forName(name);
Constructor<?> constructor = clazz.getConstructor(SpringApplication.class, String[].class);
SpringApplicationRunListener publisher = (SpringApplicationRunListener) constructor.newInstance(springApp, args);
// 发布事件
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
publisher.starting(bootstrapContext); // spring boot 开始启动
publisher.environmentPrepared(bootstrapContext, new StandardEnvironment()); // 当环境信息准备完毕
GenericApplicationContext applicationContext = new GenericApplicationContext();
publisher.contextPrepared(applicationContext); // 在 spring 容器创建,并调用初始化器之后,发布此事件
publisher.contextLoaded(applicationContext); // 所有 bean definition 加载完毕,发布此事件
applicationContext.refresh();
publisher.started(applicationContext); // spring 容器初始化完成(refresh()调用后)
publisher.failed(applicationContext, new Exception("出错了")); // spring boot 启动过程中出现错误,发布此事件
publisher.running(applicationContext); // spring boot 启动完毕
}
}
}
org.springframework.boot.context.event.EventPublishingRunListener
class org.springframework.boot.context.event.ApplicationStartingEvent
class org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent
class org.springframework.boot.context.event.ApplicationContextInitializedEvent
class org.springframework.boot.context.event.ApplicationPreparedEvent
class org.springframework.context.event.ContextRefreshedEvent
class org.springframework.boot.context.event.ApplicationFailedEvent
代码演示2:
/**
* springApplication.run() 方法的执行流程
*/
public class Test1_3 {
@SuppressWarnings("all")
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication();
System.out.println(">>>>>>>>>>>>>>>>>>>> 1、获取事件发布器,添加初始化器");
EventPublishingRunListener publisher = new EventPublishingRunListener(app, args); // 事件发布器
app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("执行初始化器增强...");
}
});
System.out.println(">>>>>>>>>>>>>>>>>>>> 2、封装启动命令行参数 args,并作为PropertySource添加到环境变量中");
DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);
System.out.println(">>>>>>>>>>>>>>>>>>>> 3、封装环境变量(添加PropertySource)");
// 属性源的属性查找根据属性源加入的先后顺序查找,如命令行来源优先于application.properties来源
ApplicationEnvironment env = new ApplicationEnvironment();
for (PropertySource<?> propertySource : env.getPropertySources()) {
// PropertiesPropertySource、SystemEnvironmentPropertySource ...
System.out.println(propertySource.getClass().getSimpleName() + " {name='" + propertySource.getName() + "'}");
}
System.out.println(env.getProperty("JAVA_HOME")); // 打印: D:\jdks\jdk1.8
// 添加属性源 - 系统环境变量
env.getPropertySources().addFirst(new SimpleCommandLinePropertySource(args)); // 命令行来源
System.out.println(">>>>>>>>>>>>>>>>>>>> 4、添加特殊的PropertySource");
ConfigurationPropertySources.attach(env); // 添加 ConfigurationPropertySources ,统一不规范的名字
for (PropertySource<?> propertySource : env.getPropertySources()) {
System.out.println(propertySource.getClass().getSimpleName() + " {name='" + propertySource.getName() + "'}");
}
System.out.println(">>>>>>>>>>>>>>>>>>>> 5、进一步补充新的PropertySource (通过EnvironmentPostProcessor)");
System.out.println("增强前...");
for (PropertySource<?> propertySource : env.getPropertySources()) {
System.out.println(propertySource.getClass().getSimpleName() + " {name='" + propertySource.getName() + "'}");
}
// 当第4步的属性源环境加载完毕后会触发下面的事件(通过事件发布器)
// 事件发布器,发布事件后会调用对应的监听器,监听器会从 spring.factories 中加载 EnvironmentPostProcessor 实现
app.addListeners(new EnvironmentPostProcessorApplicationListener()); // 添加 环境准备好 事件的监听器
publisher.environmentPrepared(new DefaultBootstrapContext(), env); // 发布事件
// 下面注释的代码就是上面的大致过程:
// env.getPropertySources().addLast(new ResourcePropertySource(new ClassPathResource("application.properties"))); // application.properties 来源
// // processor1 补充 application.properties 的 PropertySource
// ConfigDataEnvironmentPostProcessor processor1 = new ConfigDataEnvironmentPostProcessor(new DeferredLogs(), new DefaultBootstrapContext());
// processor1.postProcessEnvironment(env, app);
// // processor2 补充 随机属性值的 PropertySource
// RandomValuePropertySourceEnvironmentPostProcessor processor2 = new RandomValuePropertySourceEnvironmentPostProcessor(new DeferredLog());
// processor2.postProcessEnvironment(env, app); // env.getProperty("random.int") 获取随机整数
// System.out.println("----- spring.factories...");
// // 一般 EnvironmentPostProcessor 接口的实现类不写死在代码中,而是写在 spring.factories 中,通过 SpringFactoriesLoader 加载
// List<String> names = SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, Test1_3.class.getClassLoader());
// for (String name : names) {
// System.out.println(name);
// }
System.out.println("增强后...");
for (PropertySource<?> propertySource : env.getPropertySources()) {
System.out.println(propertySource.getClass().getSimpleName() + " {name='" + propertySource.getName() + "'}");
}
System.out.println(">>>>>>>>>>>>>>>>>>>> 6、将 环境属性、配置文件 中的键值绑定到对象属性中");
/**
* resources/user.properties 内容:
* user.first-name=George
* user.middle-name=Walker
* user.last-name=Bush
*/
// 即 @ConfigurationProperties 相同的功能
env.getPropertySources().addLast(new ResourcePropertySource("user", new ClassPathResource("user.properties")));
BindResult<User> bindResult = Binder.get(env).bind("user", User.class); // 可以处理不规范命名
System.out.println(bindResult.get());
// // 也可以绑定到已有的对象
// User user = new User();
// BindResult<User> bindResult = Binder.get(env).bind("user", Bindable.ofInstance(user));
// System.out.println(bindResult);
// // 可以通过该方式修改环境属性值,比如 SpringApplication 中的属性
// // step6.properties : spring.main.banner-mode=off
// env.getPropertySources().addLast(new ResourcePropertySource("step6", new ClassPathResource("step6.properties")));
// BindResult<SpringApplication> bindResult = Binder.get(env).bind("spring.main", Bindable.ofInstance(app));
// System.out.println(bindResult);
System.out.println(">>>>>>>>>>>>>>>>>>>> 7、输出 SpringBoot 的 banner 信息");
SpringApplicationBannerPrinter printer = new SpringApplicationBannerPrinter(new DefaultResourceLoader(), new SpringBootBanner());
// 测试文字banner
env.getPropertySources().addLast(new MapPropertySource("custom", Collections.singletonMap("spring.banner.location", "banner1.txt")));
// // 测试图片banner
// env.getPropertySources().addLast(new MapPropertySource("custom", Collections.singletonMap("spring.banner.image.location", "banner2.jpg")));
// 版本号的获取
System.out.println(SpringBootVersion.getVersion());
printer.print(env, Test1_3.class, System.out);
System.out.println(">>>>>>>>>>>>>>>>>>>> 8、创建容器");
GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);
System.out.println(">>>>>>>>>>>>>>>>>>>> 9、准备容器(会执行添加的初始化器)");
for (ApplicationContextInitializer initializer : app.getInitializers()) {
initializer.initialize(context); // 回调初始化器
}
System.out.println(">>>>>>>>>>>>>>>>>>>> 10、从各种来源加载 bean 定义");
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context.getDefaultListableBeanFactory()); // 注解来源
// XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context.getDefaultListableBeanFactory()); // xml 来源
// ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context.getDefaultListableBeanFactory()); // 组件扫描来源
reader.register(Config.class); // 解析 Config 配置类里的 bean 定义并加入 bean 工厂
System.out.println(">>>>>>>>>>>>>>>>>>>> 11、调用 refresh()");
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println("name: " + name + " 来源:" + context.getBeanFactory().getBeanDefinition(name).getResourceDescription());
}
System.out.println(">>>>>>>>>>>>>>>>>>>> 12、执行 runner 对象的 run()方法");
for (CommandLineRunner commandLineRunner : context.getBeansOfType(CommandLineRunner.class).values()) {
commandLineRunner.run(args);
}
for (ApplicationRunner applicationRunner : context.getBeansOfType(ApplicationRunner.class).values()) {
applicationRunner.run(arguments);
}
}
private static GenericApplicationContext createApplicationContext(WebApplicationType type) {
GenericApplicationContext context = null;
switch (type) {
case SERVLET:
context = new AnnotationConfigServletWebServerApplicationContext();
break;
case REACTIVE:
context = new AnnotationConfigReactiveWebServerApplicationContext();
break;
case NONE:
context = new AnnotationConfigApplicationContext();
break;
}
return context;
}
static class Bean4 {}
static class Bean5 {}
static class Bean6 {}
@Data
static class User {
private String firstName;
private String middleName;
private String lastName;
}
@Configuration
static class Config {
@Bean
public Bean5 bean5() {
return new Bean5();
}
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
public CommandLineRunner commandLineRunner() {
return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception {
System.out.println("commandLineRunner()..." + Arrays.toString(args));
}
};
}
@Bean
public ApplicationRunner applicationRunner() {
return new ApplicationRunner() {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("applicationRunner()..." + Arrays.toString(args.getSourceArgs()));
}
};
}
}
}
结果:
>>>>>>>>>>>>>>>>>>>> 1、获取事件发布器,添加初始化器
>>>>>>>>>>>>>>>>>>>> 2、封装启动命令行参数 args,并作为PropertySource添加到环境变量中
>>>>>>>>>>>>>>>>>>>> 3、封装环境变量(添加PropertySource)
PropertiesPropertySource {name='systemProperties'}
SystemEnvironmentPropertySource {name='systemEnvironment'}
......
D:\jdks\jdk1.8
>>>>>>>>>>>>>>>>>>>> 4、添加特殊的PropertySource
ConfigurationPropertySourcesPropertySource {name='configurationProperties'}
SimpleCommandLinePropertySource {name='commandLineArgs'}
PropertiesPropertySource {name='systemProperties'}
SystemEnvironmentPropertySource {name='systemEnvironment'}
>>>>>>>>>>>>>>>>>>>> 5、进一步补充新的PropertySource (通过EnvironmentPostProcessor)
增强前...
ConfigurationPropertySourcesPropertySource {name='configurationProperties'}
SimpleCommandLinePropertySource {name='commandLineArgs'}
PropertiesPropertySource {name='systemProperties'}
SystemEnvironmentPropertySource {name='systemEnvironment'}
......
增强后...
ConfigurationPropertySourcesPropertySource {name='configurationProperties'}
SimpleCommandLinePropertySource {name='commandLineArgs'}
PropertiesPropertySource {name='systemProperties'}
OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}
RandomValuePropertySource {name='random'}
OriginTrackedMapPropertySource {name='Config resource 'class path resource [application.properties]' via location 'optional:classpath:/''}
>>>>>>>>>>>>>>>>>>>> 6、将 环境属性、配置文件 中的键值绑定到对象属性中
Test1_3.User(firstName=George, middleName=Walker, lastName=Bush)
>>>>>>>>>>>>>>>>>>>> 7、输出 SpringBoot 的 banner 信息
2.6.13
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> this is a banner >>>>>>>>>>>>>>>>
?????????????????????????????????????????????????
>>>>>>>>>>>>>>>>>>>> 8、创建容器
>>>>>>>>>>>>>>>>>>>> 9、准备容器(会执行添加的初始化器)
执行初始化器增强...
>>>>>>>>>>>>>>>>>>>> 10、从各种来源加载 bean 定义
>>>>>>>>>>>>>>>>>>>> 11、调用 refresh()
......
name: org.springframework.context.annotation.internalConfigurationAnnotationProcessor 来源:null
name: org.springframework.context.annotation.internalAutowiredAnnotationProcessor 来源:null
name: org.springframework.context.annotation.internalCommonAnnotationProcessor 来源:null
name: org.springframework.context.event.internalEventListenerProcessor 来源:null
name: org.springframework.context.event.internalEventListenerFactory 来源:null
name: test1_3.Config 来源:null
name: org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory 来源:null
name: bean5 来源:org.springframework.boot.Test1_3$Config
name: servletWebServerFactory 来源:org.springframework.boot.Test1_3$Config
name: commandLineRunner 来源:org.springframework.boot.Test1_3$Config
name: applicationRunner 来源:org.springframework.boot.Test1_3$Config
>>>>>>>>>>>>>>>>>>>> 12、执行 runner 对象的 run()方法
commandLineRunner()...[]
applicationRunner()...[]
18、Tomcat 内嵌容器
18.1、内嵌容器的基本使用
代码演示:
/**
* Tomcat 结构:
* Server
* Service
* Connector - 协议、端口 信息
* Engine
* Host - 虚拟主机 localhost
* Context1 - 应用1,可以设置虚拟路径(一般设为 / ),即 url 起始路径;项目磁盘路径,即 docBase
* index.html
* WEB_INF
* web.xml (配置 servlet、filter、listener) 3.0
* classes (servlet、controller、service ...)
* jsp
* lib (第三方 jar 包)
* Context2 - 应用2
* index.html
* WEB_INF
* web.xml
* classes
* jsp
* lib
* ......
*/
public class TestTomcat {
public static void main(String[] args) throws IOException, LifecycleException {
// 1、创建 Tomcat 对象
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("tomcat"); // 相对于 工作目录
// 2、创建项目文件夹,即 docBase 文件夹
File docBase = Files.createTempDirectory("boot.").toFile();
docBase.deleteOnExit();
// 3、创建 Tomcat 项目,在 Tomcat 中称为 Context
Context context = tomcat.addContext("", docBase.getAbsolutePath());
// 4、编程方式添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
HelloServlet helloServlet = new HelloServlet();
ctx.addServlet("aaa", helloServlet).addMapping("/hello"); // 设置servlet名称、映射路径
}
}, Collections.emptySet());
// 5、启动 Tomcat
tomcat.start();
// 6、创建连接器,设置监听端口
Connector connector = new Connector(new Http11Nio2Protocol());
connector.setPort(8080);
tomcat.setConnector(connector);
}
}
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print(
"<h3>hello</h3>");
}
}
结果(访问 localhost:8080/hello):
hello
18.2、内嵌 Tomcat 与 Spring 整合
代码演示:
public class TestTomcat {
public static void main(String[] args) throws IOException, LifecycleException {
// 1、创建 Tomcat 对象
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("tomcat"); // 相对于 工作目录
// 2、创建项目文件夹,即 docBase 文件夹
File docBase = Files.createTempDirectory("boot.").toFile();
docBase.deleteOnExit();
// 3、创建 Tomcat 项目,在 Tomcat 中称为 Context
Context context = tomcat.addContext("", docBase.getAbsolutePath());
// 创建 Spring 容器
WebApplicationContext springContext = getApplicationContext();
// 4、编程方式添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
// 手动添加 HelloServlet
HelloServlet helloServlet = new HelloServlet();
ctx.addServlet("aaa", helloServlet).addMapping("/hello"); // 设置servlet名称、映射路径
// // 添加 DispatcherServlet
// DispatcherServlet dispatcherServlet = springContext.getBean(DispatcherServlet.class);
// ctx.addServlet("dispatcherServlet", dispatcherServlet).addMapping("/");
// 上面的添加实际上是通过 ServletRegistrationBean 给 context 注册 servlet 的
for (ServletRegistrationBean registrationBean : springContext.getBeansOfType(ServletRegistrationBean.class).values()) {
registrationBean.onStartup(ctx);
}
}
}, Collections.emptySet());
// 5、启动 Tomcat
tomcat.start();
// 6、创建连接器,设置监听端口
Connector connector = new Connector(new Http11Nio2Protocol());
connector.setPort(8080);
tomcat.setConnector(connector);
}
public static WebApplicationContext getApplicationContext() {
// AnnotationConfigServletWebServerApplicationContext : 支持内嵌 Tomcat 的 Spring 容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); // 不支持内嵌 Tomcat 的 容器,方便我们使用自己的 tomcat
context.register(Config.class);
context.refresh();
return context;
}
@Configuration
static class Config {
@Bean
// 该注册bean用于注册 DispatcherServlet
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean
// 这个例子中必须为 DispatcherServlet 提供 AnnotationConfigWebApplicationContext,否则会选择 XmlWebApplicationContext 实现
public DispatcherServlet dispatcherServlet(WebApplicationContext applicationContext) {
return new DispatcherServlet(applicationContext);
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter();
handlerAdapter.setMessageConverters(Collections.singletonList(new MappingJackson2HttpMessageConverter()));
return handlerAdapter;
}
@RestController
static class MyController {
@GetMapping("hello2")
public Map<String, Object> hello2() {
return Collections.singletonMap("hello2", "hello2, spring!");
}
}
}
}
结果(访问 localhost:8080/hello2):
hello2:"hello2, spring!"
19、自动配置类
19.1、自动配置类原理
代码演示:
spring.factories 内容:
com.clp.test3.Test3$MyImportSelector=\
com.clp.test3.Test3.AutoConfiguration1,\
com.clp.test3.Test3.AutoConfiguration2
public class Test3 {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
// 设置是否允许覆盖bean (设为true:后注册的bean会覆盖先注册的bean,设为false:不允许覆盖)
context.getDefaultListableBeanFactory().setAllowBeanDefinitionOverriding(false);
context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(context.getBean(Bean1.class));
}
// 本项目的配置类
@Configuration
@Import(MyImportSelector.class)
static class Config {
// @Bean // 使用第三方自动配置(@ConditionalOnMissingBean注解生效)
public Bean1 bean1() {
return new Bean1("本项目bean1");
}
}
// 实现 ImportSelector 会 先解析 这个并导入,自己定义的bean后添加
// DeferredImportSelector 是 ImportSelector 的子接口,实现该接口不会先解析导入这个,而是先添加自己定义的bean
static class MyImportSelector implements DeferredImportSelector {
// 方法的返回值就是要导入的配置类的类名
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> classNames = SpringFactoriesLoader.loadFactoryNames(MyImportSelector.class, null);
return classNames.toArray(new String[0]);
}
}
// 第三方配置类1
@Configuration
static class AutoConfiguration1 {
@Bean
@ConditionalOnMissingBean // 当缺失了这个bean则添加
public Bean1 bean1() {
return new Bean1("第三方bean1");
}
}
@Data
@AllArgsConstructor
static class Bean1 {
private String name;
}
// 第三方配置类2
@Configuration
static class AutoConfiguration2 {
}
static class Bean2 {}
}
结果:
config
org.springframework.context.annotation.ConfigurationClassPostProcessor
com.clp.test3.Test3$AutoConfiguration1
bean1
com.clp.test3.Test3$AutoConfiguration2
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Test3.Bean1(name=第三方bean1)
19.2、AopAutoConfiguration
代码演示:
public class Test4 {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
StandardEnvironment env = new StandardEnvironment();
// 模拟命令行属性源
env.getPropertySources().addLast(new SimpleCommandLinePropertySource("--spring.aop.auto=true"));
context.setEnvironment(env);
// 利用注册工具向bean工厂注册常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
context.registerBean(Config.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 最终目的是创建并添加 代理创建器 bean
InfrastructureAdvisorAutoProxyCreator creator = context.getBean(
"org.springframework.aop.config.internalAutoProxyCreator", InfrastructureAdvisorAutoProxyCreator.class);
System.out.println(creator.isProxyTargetClass());
}
@Configuration
@Import(MyImportSelector.class)
static class Config {
}
static class MyImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{AopAutoConfiguration.class.getName()};
}
}
}
结果:
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
com.clp.test4.Test4$Config
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration
forceAutoProxyCreatorToUseClassProxying
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.aop.config.internalAutoProxyCreator
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
true
19.3、DataSource 自动配置
代码演示:
@SpringBootApplication
public class Test4_2 {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
StandardEnvironment env = new StandardEnvironment();
// 模拟命令行属性源
env.getPropertySources().addLast(new SimpleCommandLinePropertySource(
"--spring.datasource.url=jdbc:mysql://localhost:3306/test",
"--spring.datasource.username=root",
"--spring-datasource=password=123456"
));
context.setEnvironment(env);
// 利用注册工具向bean工厂注册常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
context.registerBean(Config.class);
// Mybatis 自动配置类要求加 @Mapper 注解
String packageName = Test4_2.class.getPackage().getName();
AutoConfigurationPackages.register(context.getDefaultListableBeanFactory(), packageName); // 在本类的包以及子包扫描 mapper(加@Mapper的接口)
System.out.println("当前包名:" + packageName);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
String resourceDescription = context.getBeanDefinition(name).getResourceDescription();
if (resourceDescription != null) {
System.out.println(name + " 来源:" + resourceDescription);
}
}
}
@Configuration
@Import(MyImportSelector.class)
static class Config {
}
static class MyImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
DataSourceAutoConfiguration.class.getName(), // 数据源自动配置(必不可少,下面三个都要用到这个)
MybatisAutoConfiguration.class.getName(), // mybatis 相关bean 自动配置
DataSourceTransactionManagerAutoConfiguration.class.getName(), // 数据源事务管理器 自动配置
TransactionAutoConfiguration.class.getName() // 声明式事务管理 自动配置
};
}
}
}
19.4、MVC 自动配置
代码演示:
public class Test4_3 {
public static void main(String[] args) {
AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();
context.registerBean(Config.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
String resourceDescription = context.getBeanDefinition(name).getResourceDescription();
if (resourceDescription != null) {
System.out.println(name + " 来源:" + resourceDescription);
}
}
context.close();
}
@Configuration
@Import(MyImportSelector.class)
static class Config {}
static class MyImportSelector implements DeferredImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
ServletWebServerFactoryAutoConfiguration.class.getName(),
DispatcherServletAutoConfiguration.class.getName(),
WebMvcAutoConfiguration.class.getName(),
ErrorMvcAutoConfiguration.class.getName()
};
}
}
}
20、条件装配底层
代码演示:
public class Test5 {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
context.registerBean(ConfigurationClassPostProcessor.class);
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
}
// 本项目的配置类
@Configuration
@Import(MyImportSelector.class)
static class Config {
}
// 实现 ImportSelector 会 先解析 这个并导入,自己定义的bean后添加
// DeferredImportSelector 是 ImportSelector 的子接口,实现该接口不会先解析导入这个,而是先添加自己定义的bean
static class MyImportSelector implements DeferredImportSelector {
// 方法的返回值就是要导入的配置类的类名
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
AutoConfiguration1.class.getName(), AutoConfiguration2.class.getName()
};
}
}
// 第三方配置类1
@Configuration
@ConditionOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = true)
static class AutoConfiguration1 {
@Bean
public Bean1 bean1() {
return new Bean1();
}
}
// 第三方配置类2
@Configuration
@ConditionOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = false)
static class AutoConfiguration2 {
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnClassCondition.class)
@interface ConditionOnClass {
boolean exists(); // true 判断存在; false 判断不存在
String className(); // 要判断的类的名称
}
static class OnClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
String className = attributes.get("className").toString();
boolean exists = (boolean) attributes.get("exists");
boolean isPresent = ClassUtils.isPresent(className, null);
return exists == isPresent;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
static class Bean1 {
private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
static class Bean2 {
private String name;
}
}
结果:
config
org.springframework.context.annotation.ConfigurationClassPostProcessor
com.clp.test5.Test5$AutoConfiguration2
bean2
21、FactoryBean
代码演示:
/**
* 一个在 Spring 发展阶段中需要,但目前已经很鸡肋的接口 FactoryBean 的使用要点:
* 1、它的作用是用制造创建过程较为复杂的产品,如 SqlSessionFactory,但 @Bean 已具备等价功能;
* 2、使用上较为古怪,一不留神就会用错:
* 1)被 FactoryBean 创建的产品:
* - 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责,这些流程都不会走;
* - 唯有后初始化的流程会走,也就是产品可以被代理增强;
* - 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中,而是另一个 factoryBeanObjectCache 成员中。
* 2)按名称去获取时,拿到的是产品对象,名字前面加 & 获取的是工厂对象
* 目前此接口的实现仍被大量使用,想被全面废弃很难。
*/
@ComponentScan
public class Test6 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test6.class);
Bean1 bean1 = (Bean1) context.getBean("bean1");
System.out.println(bean1);
Bean1FactoryBean bean1FactoryBean = (Bean1FactoryBean) context.getBean("&bean1");
System.out.println(bean1FactoryBean);
context.close();
}
@Slf4j
@Component("bean1")
static class Bean1FactoryBean implements FactoryBean<Bean1> {
@Override // 决定了根据 【类型】 获取或依赖注入能否成功
public Class<?> getObjectType() {
return Bean1.class;
}
@Override // 决定了 getObject() 方法被调用一次还是多次
public boolean isSingleton() {
return true;
}
@Override
public Bean1 getObject() throws Exception {
Bean1 bean1 = new Bean1();
log.debug("create bean: {}", bean1);
return bean1;
}
}
@Slf4j
static class Bean1 implements BeanFactoryAware {
private Bean2 bean2;
@Autowired
public void setBean2(Bean2 bean2) {}
public Bean2 getBean2() {
return bean2;
}
@PostConstruct
public void init() {
log.debug("init");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.debug("setBeanFactory({})", beanFactory);
}
}
@Slf4j
@Component
static class Bean1PostProcessor implements BeanPostProcessor {
@Override // 不会走进来
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("bean1") && bean instanceof Bean1) {
log.debug("before [{}] init", beanName);
}
return bean;
}
@Override // 会走进来
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("bean1") && bean instanceof Bean1) {
log.debug("after [{}] init", beanName);
}
return bean;
}
}
static class Bean2 {}
}
结果:
......
16:26:08.919 [main] DEBUG com.clp.test06.Test6$Bean1FactoryBean - create bean: com.clp.test06.Test6$Bean1@6ee12bac
16:26:08.920 [main] DEBUG com.clp.test06.Test6$Bean1PostProcessor - after [bean1] init
com.clp.test06.Test6$Bean1@6ee12bac
......
com.clp.test06.Test6$Bean1FactoryBean@400cff1a
22、@Indexed 的原理
代码演示:
/**
* @Indexed 的原理,在编译时就根据 @Indexed 生成 META-INF/spring.components 文件
* 扫描时:
* 1、如果发现 META-INF /spring.components 存在,以它为准加载 bean definition
* 2、否则,会遍历包下所有 class 资源(包括 jar 内的)
*/
public class Test7 {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
scanner.scan(Test7.class.getPackage().getName());
for (String name : beanFactory.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
23、Spring 代理的特点
代码演示:
/**
* 演示 spring 代理的设计特点:
* 1、依赖注入和初始化影响的是原始对象;
* 2、代理与目标是两个对象,二者成员变量并不公用数组。因此只能调用代理对象的方法,而不能访问成员变量
* 3、static、final、private 方法均无法增强
*/
@Slf4j
@SpringBootApplication
public class Test8 {
public static void main(String[] args) throws Exception {
log.info("----------------------------------------------------");
ConfigurableApplicationContext context = SpringApplication.run(Test8.class, args);
Bean1 proxy = context.getBean(Bean1.class);
log.info("----------------------------------------------------");
proxy.setBean2(new Bean2()); // 此时调用代理对象的增强方法
log.info("----------------------------------------------------");
showProxyAndTarget(proxy);
log.info("----------------------------------------------------");
proxy.publicMethod();
log.info("----------------------------------------------------");
proxy.finalMethod();
log.info("----------------------------------------------------");
proxy.staticMethod();
log.info("----------------------------------------------------");
proxy.privateMethod();
context.close();
}
@Slf4j
@Aspect
@Component
static class MyAspect {
// 故意对所有方法增强
@Before("execution(* com.clp.test08.Test8.Bean1.*(..))")
public void before() {
log.info("++++++++++ before");
}
}
@Data
@Slf4j
@Component
static class Bean1 {
protected Bean2 bean2;
protected boolean isInitialized;
@Autowired // 没有被增强,但是通过代理对象调用时还是增强方法
public void setBean2(Bean2 bean2) {
log.info("---------- setBean2(Bean2 bean2)");
this.bean2 = bean2;
}
@PostConstruct // 没有被增强
public void init() {
log.info("---------- init");
isInitialized = true;
}
public void publicMethod() {
log.info("调用 public 方法");
}
final void finalMethod() {
log.info("调用 final 方法");
}
static void staticMethod() {
log.info("调用 static 方法");
}
private void privateMethod() {
log.info("调用 private 方法");
}
}
@Component
static class Bean2 {}
public static void showProxyAndTarget(Bean1 proxy) throws Exception {
log.info(">>>>>> 代理中的成员变量");
log.info("\tisInitialized=" + proxy.isInitialized); // 直接通过属性获取值获取的是代理自己的属性值,而自己的属性并不使用
log.info("\tbean2=" + proxy.bean2);
if (proxy instanceof Advised) {
Advised advised = (Advised) proxy;
log.info(">>>>>> 目标中的成员变量");
Bean1 target = (Bean1) advised.getTargetSource().getTarget();
log.info(target.toString());
log.info("\tinitialized=" + target.isInitialized);
log.info("\tbean2=" + target.bean2);
}
}
}
结果:
17:14:18.377 [main] INFO com.clp.test08.Test8 - ----------------------------------------------------
......
2023-05-16 17:14:19.878 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : ---------- setBean2(Bean2 bean2)
2023-05-16 17:14:19.878 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : ---------- init
......
2023-05-16 17:14:20.130 INFO 8648 --- [ main] com.clp.test08.Test8 : ----------------------------------------------------
2023-05-16 17:14:20.132 INFO 8648 --- [ main] com.clp.test08.Test8$MyAspect : ++++++++++ before
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : ---------- setBean2(Bean2 bean2)
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8 : ----------------------------------------------------
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8 : >>>>>> 代理中的成员变量
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8 : isInitialized=false
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8 : bean2=null
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8 : >>>>>> 目标中的成员变量
2023-05-16 17:14:20.141 INFO 8648 --- [ main] com.clp.test08.Test8 : Test8.Bean1(bean2=com.clp.test08.Test8$Bean2@78c1a023, isInitialized=true)
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8 : initialized=true
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8 : bean2=com.clp.test08.Test8$Bean2@78c1a023
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8 : ----------------------------------------------------
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8$MyAspect : ++++++++++ before
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : 调用 public 方法
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8 : ----------------------------------------------------
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : 调用 final 方法
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8 : ----------------------------------------------------
2023-05-16 17:14:20.142 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : 调用 static 方法
2023-05-16 17:14:20.143 INFO 8648 --- [ main] com.clp.test08.Test8 : ----------------------------------------------------
2023-05-16 17:14:20.143 INFO 8648 --- [ main] com.clp.test08.Test8$Bean1 : 调用 private 方法
......
24、@Value 注入底层
代码演示:
public class Test9 {
public static void main(String[] args) throws NoSuchFieldException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test9.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
// 获取 @Value 的内容
System.out.println("-------------------------------------------------------------");
Field field1 = Bean1.class.getDeclaredField("home");
DependencyDescriptor descriptor1 = new DependencyDescriptor(field1, false);
String value1 = resolver.getSuggestedValue(descriptor1).toString();
System.out.println(value1); // ${JAVA_HOME} : String
// 解析 ${}
value1 = context.getEnvironment().resolvePlaceholders(value1);
System.out.println(value1); // D:\jdks\jdk1.8 : String
// 获取 @Value 的内容
System.out.println("-------------------------------------------------------------");
Field field2 = Bean1.class.getDeclaredField("age");
DependencyDescriptor descriptor2 = new DependencyDescriptor(field2, false);
String value2 = resolver.getSuggestedValue(descriptor2).toString();
System.out.println(value2);
// 解析 ${}
value2 = context.getEnvironment().resolvePlaceholders(value2);
System.out.println(value2);
// 类型转换 - 基本数据类型
Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value2, descriptor2.getDependencyType());
System.out.println("age=" + age + ", class=" + age.getClass());
// 获取 @Value 的内容
System.out.println("-------------------------------------------------------------");
context.registerBean("bean3", Bean3.class);
Field field3 = Bean2.class.getDeclaredField("bean3");
DependencyDescriptor descriptor3 = new DependencyDescriptor(field3, false);
String value3 = resolver.getSuggestedValue(descriptor3).toString();
System.out.println(value3);
// 解析 ${}
value3 = context.getEnvironment().resolvePlaceholders(value3);
// 解析 #{} (在解析 ${} 之后)
Object bean3Obj = context.getBeanFactory().getBeanExpressionResolver().evaluate(value3, new BeanExpressionContext(context.getBeanFactory(), null));
// 类型转换
Object bean3 = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3Obj, descriptor3.getDependencyType());
System.out.println(bean3);
// 获取 @Value 的内容
System.out.println("-------------------------------------------------------------");
Field field4 = Bean4.class.getDeclaredField("value");
DependencyDescriptor descriptor4 = new DependencyDescriptor(field4, false);
String value4 = resolver.getSuggestedValue(descriptor4).toString();
System.out.println(value4);
// 解析 ${}
value4 = context.getEnvironment().resolvePlaceholders(value4);
System.out.println(value4);
// 解析 #{} (在解析 ${} 之后)
Object bean4Obj = context.getBeanFactory().getBeanExpressionResolver().evaluate(value4, new BeanExpressionContext(context.getBeanFactory(), null));
// 类型转换
Object bean4 = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean4Obj, descriptor4.getDependencyType());
System.out.println(bean4);
}
static class Bean1 {
@Value("${JAVA_HOME}")
private String home;
@Value("18")
private int age;
}
static class Bean2 {
@Value("#{@bean3}") // 类似于 @Autowire,但是需要配置 SpringEL 表达式使用,@表示要根据bean的名字找
private Bean3 bean3;
}
static class Bean3 {}
static class Bean4 {
@Value("#{'hello, ' + '${JAVA_HOME}'}")
private String value;
}
}
结果:
-------------------------------------------------------------
${JAVA_HOME}
09:08:23.571 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
D:\jdks\jdk1.8
-------------------------------------------------------------
18
18
age=18, class=class java.lang.Integer
-------------------------------------------------------------
#{@bean3}
09:08:23.612 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean3'
com.clp.test09.Test9$Bean3@4d339552
-------------------------------------------------------------
#{'hello, ' + '${JAVA_HOME}'}
09:08:23.615 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'JAVA_HOME' in PropertySource 'systemEnvironment' with value of type String
#{'hello, ' + 'D:\jdks\jdk1.8'}
hello, D:\jdks\jdk1.8
25、@Autowire 注入底层
代码演示1:
@Configuration
public class Test10 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test10.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
// 1、根据成员变量的类型注入
System.out.println("------------------------------------------------------------");
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
Object bean2 = beanFactory.doResolveDependency(dd1, "bean1", null, null);
System.out.println(bean2);
// 2、根据参数的类型注入
System.out.println("------------------------------------------------------------");
Method setBean2Method = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2Method, 0), false);
bean2 = beanFactory.doResolveDependency(dd2, "bean1", null, null);
System.out.println(bean2);
// 3、结果包装为 Optional<Bean2>
System.out.println("------------------------------------------------------------");
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
System.out.println(dd3.getDependencyType());
dd3.increaseNestingLevel();
System.out.println(dd3.getDependencyType());
// 4、结果包装为 ObjectProvider
System.out.println("------------------------------------------------------------");
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"), false);
if (dd4.getDependencyType() == ObjectFactory.class) {
dd4.increaseNestingLevel();
ObjectFactory factory = new ObjectFactory() {
@Override
public Object getObject() throws BeansException {
return beanFactory.doResolveDependency(dd4, "bean1", null, null);
}
};
System.out.println(factory.getObject());
}
// 5、对 @Lazy 的处理
System.out.println("------------------------------------------------------------");
DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
System.out.println(proxy);
System.out.println(proxy.getClass());
}
static class Bean1 {
@Autowired @Lazy
private Bean2 bean2;
@Autowired
private void setBean2(@Lazy Bean2 bean2) {
this.bean2 = bean2;
}
@Autowired
private Optional<Bean2> bean3;
@Autowired
private ObjectFactory<Bean2> bean4;
}
@Component("bean2")
static class Bean2 {
@Override
public String toString() {
return super.toString();
}
}
}
结果:
------------------------------------------------------------
com.clp.test10.Test10$Bean2@6b19b79
------------------------------------------------------------
com.clp.test10.Test10$Bean2@6b19b79
------------------------------------------------------------
class java.util.Optional
class com.clp.test10.Test10$Bean2
------------------------------------------------------------
com.clp.test10.Test10$Bean2@6b19b79
------------------------------------------------------------
com.clp.test10.Test10$Bean2@6b19b79
class com.clp.test10.Test10$Bean2$$EnhancerBySpringCGLIB$$b860d359
代码演示2:
/**
* 优先级顺序:
* 1、@Qualifier
* 2、@Primary
* 3、成员变量名字
*/
@Configuration
public class Test10_2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test10_2.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
System.out.println("---------------------------------------------------------------");
testArray(beanFactory);
System.out.println("---------------------------------------------------------------");
testList(beanFactory);
System.out.println("---------------------------------------------------------------");
testConfigurableApplicationContext(beanFactory);
System.out.println("---------------------------------------------------------------");
testGeneric(beanFactory);
System.out.println("---------------------------------------------------------------");
testQualifier(beanFactory);
System.out.println("---------------------------------------------------------------");
testPrimary(beanFactory);
System.out.println("---------------------------------------------------------------");
testDefault(beanFactory);
}
private static void testArray(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);
if (dd1.getDependencyType().isArray()) {
Class<?> componentType = dd1.getDependencyType().getComponentType();
System.out.println(componentType);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);
List<Object> beans = new ArrayList<>();
for (String name : names) {
System.out.println(name);
Object bean = dd1.resolveCandidate(name, componentType, beanFactory);
beans.add(bean);
}
Object array = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
System.out.println(array);
}
}
private static void testList(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
if (dd2.getDependencyType() == List.class) {
Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
System.out.println(resolve);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
List<Object> beans = new ArrayList<>();
for (String name : names) {
Object bean = dd2.resolveCandidate(name, resolve, beanFactory);
beans.add(bean);
}
System.out.println(beans);
}
}
@SuppressWarnings("unchecked")
private static void testConfigurableApplicationContext(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException, IllegalAccessException {
DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);
Field resolvableDependenciesField = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");
resolvableDependenciesField.setAccessible(true);
Map<Class<?>, Object> dependencies = (Map<Class<?>, Object>) resolvableDependenciesField.get(beanFactory);
for (Map.Entry<Class<?>, Object> entry : dependencies.entrySet()) {
// class1.isAssignableFrom(class2) :class1 是否可以继承 class2
if (entry.getKey().isAssignableFrom(dd3.getDependencyType())) {
System.out.println(entry.getValue());
break;
}
}
}
private static void testGeneric(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);
Class<?> type = dd4.getDependencyType(); // Dao.class
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
// 对比 BeanDefinition 中的泛型与 DependencyDescriptor 是否相同
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd4)) {
System.out.println(name);
Object bean = dd4.resolveCandidate(name, type, beanFactory);
System.out.println(bean);
}
}
}
private static void testQualifier(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);
Class<?> type = dd5.getDependencyType(); // Service.class
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
// 对比 BeanDefinition 中的泛型与 DependencyDescriptor 是否相同
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd5)) {
System.out.println(name);
Object bean = dd5.resolveCandidate(name, type, beanFactory);
System.out.println(bean);
}
}
}
private static void testPrimary(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd6 = new DependencyDescriptor(Target2.class.getDeclaredField("service"), true);
Class<?> type = dd6.getDependencyType(); // Service.class
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
System.out.println(name);
}
}
}
private static void testDefault(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd7 = new DependencyDescriptor(Target3.class.getDeclaredField("service3"), true);
Class<?> type = dd7.getDependencyType(); // Service.class
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
if (name.equals(dd7.getDependencyName())) {
System.out.println(name);
}
}
}
static class Target {
@Autowired
private Service[] serviceArray;
@Autowired
private List<Service> serviceList;
@Autowired
private ConfigurableApplicationContext applicationContext;
@Autowired
private Dao<Teacher> dao;
@Autowired @Qualifier("service2")
private Service service;
}
static class Target2 {
@Autowired
private Service service; // 测试 : 根据 @Primary 注解匹配注入
}
static class Target3 {
@Autowired
private Service service3; // 测试 : 根据名字匹配注入
}
interface Service {}
@Component("service1")
static class Service1 implements Service {}
@Component("service2") @Primary // 用于 Target2 的默认注入,只能加一个
static class Service2 implements Service {}
@Component("service3")
static class Service3 implements Service {}
interface Dao<T> {}
static class Student {}
static class Teacher {}
@Component("dao1")
static class Dao1 implements Dao<Student> {}
@Component("dao2")
static class Dao2 implements Dao<Teacher> {}
}
结果:
---------------------------------------------------------------
interface com.clp.test10.Test10_2$Service
service3
service2
service1
[Lcom.clp.test10.Test10_2$Service;@4278a03f
---------------------------------------------------------------
interface com.clp.test10.Test10_2$Service
[com.clp.test10.Test10_2$Service3@7a4ccb53, com.clp.test10.Test10_2$Service2@309e345f, com.clp.test10.Test10_2$Service1@56a6d5a6]
---------------------------------------------------------------
org.springframework.context.annotation.AnnotationConfigApplicationContext@626b2d4a, started on Wed May 17 11:11:07 CST 2023
---------------------------------------------------------------
dao2
com.clp.test10.Test10_2$Dao2@6dbb137d
---------------------------------------------------------------
service2
com.clp.test10.Test10_2$Service2@309e345f
---------------------------------------------------------------
service2
---------------------------------------------------------------
service3
26、事件 - 监听器
代码演示:
@Configuration
public class Test11 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test11.class);
context.getBean(MyService.class);
context.close();
}
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
@Slf4j
@Component
static class MyService {
@Autowired
private ApplicationEventPublisher publisher; // 事件发布器,实际就是 ApplicationContext
public void doBusiness() {
log.debug("主线业务");
// // 主线业务完成后需要做一些支持业务,下面是问题代码
// log.debug("发送短信");
// log.debug("发送邮件");
// 将上面问题代码修改为 事件监听 机制
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
@PostConstruct
private void init() {
doBusiness();
}
}
// ---------------------------- 监听器实现方式1 --------------------------------- //
@Slf4j
@Component
static class SmsApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送短信");
}
}
@Slf4j
@Component
static class EmailApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送邮件");
}
}
// ---------------------------- 监听器实现方式2 --------------------------------- //
@Slf4j
@Component
static class SmsService {
@EventListener
public void listener(MyEvent event) {
log.debug("发送短信");
}
}
@Slf4j
@Component
static class EmailService {
@EventListener
public void listener(MyEvent event) {
log.debug("发送邮件");
}
}
@Bean
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
return executor;
}
@Bean // 默认的广播器为单线程,我们设置为多线程并覆盖
public SimpleApplicationEventMulticaster applicationEventMulticaster(ThreadPoolTaskExecutor executor) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(executor);
return multicaster;
}
}
结果:
11:28:36.583 [main] DEBUG com.clp.test11.Test11$MyService - 主线业务
11:28:36.595 [executor-1] DEBUG com.clp.test11.Test11$EmailApplicationListener - 发送邮件
11:28:36.599 [executor-2] DEBUG com.clp.test11.Test11$SmsApplicationListener - 发送短信
代码演示2:
@Configuration
public class Test12 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test12.class);
context.getBean(MyService.class).doBusiness();
context.close();
}
// 该接口的方法会在 初始化单例 后被回调
@Bean
public SmartInitializingSingleton smartInitializingSingleton(ConfigurableApplicationContext context) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
for (String name : context.getBeanDefinitionNames()) {
Object bean = context.getBean(name);
for (Method method : bean.getClass().getMethods()) {
if (method.isAnnotationPresent(MyEventListener.class)) {
ApplicationListener listener = new ApplicationListener() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
try {
Class<?> eventType = method.getParameterTypes()[0];// 监听器方法需要的事件类型
if (eventType.isAssignableFrom(event.getClass())) {
method.invoke(bean, event);
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
};
context.addApplicationListener(listener);
}
}
}
}
};
}
@Slf4j
@Component
static class MyService {
@Autowired
private ApplicationEventPublisher publisher; // 事件发布器,实际就是 ApplicationContext
public void doBusiness() {
log.debug("主线业务");
// // 主线业务完成后需要做一些支持业务,下面是问题代码
// log.debug("发送短信");
// log.debug("发送邮件");
// 将上面问题代码修改为 事件监听 机制
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
}
@Slf4j
@Component
static class SmsService {
@MyEventListener
public void listener(MyEvent event) {
log.debug("发送短信");
}
}
@Slf4j
@Component
static class EmailService {
@MyEventListener
public void listener(MyEvent event) {
log.debug("发送邮件");
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyEventListener {
}
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
}
结果:
11:54:53.371 [main] DEBUG com.clp.test12.Test12$MyService - 主线业务
11:54:53.372 [main] DEBUG com.clp.test12.Test12$EmailService - 发送邮件
11:54:53.372 [main] DEBUG com.clp.test12.Test12$SmsService - 发送短信
27、事件 - 发布器
代码演示:
@Configuration
public class Test11 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Test11.class);
context.getBean(MyService.class);
context.close();
}
static class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
@Slf4j
@Component
static class MyService {
@Autowired
private ApplicationEventPublisher publisher; // 事件发布器,实际就是 ApplicationContext
public void doBusiness() {
log.debug("主线业务");
// // 主线业务完成后需要做一些支持业务,下面是问题代码
// log.debug("发送短信");
// log.debug("发送邮件");
// 将上面问题代码修改为 事件监听 机制
publisher.publishEvent(new MyEvent("MyService.doBusiness()"));
}
@PostConstruct
private void init() {
doBusiness();
}
}
// ---------------------------- 监听器实现方式1 --------------------------------- //
@Slf4j
@Component
static class SmsApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送短信");
}
}
@Slf4j
@Component
static class EmailApplicationListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
log.debug("发送邮件");
}
}
@Bean
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
return executor;
}
@Bean
public ApplicationEventMulticaster applicationEventMulticaster(ConfigurableApplicationContext context, ThreadPoolTaskExecutor executor) {
return new AbstractApplicationEventMulticaster(){
private List<GenericApplicationListener> listeners = new ArrayList<>();
@Override // 收集监听器
public void addApplicationListenerBean(String listenerBeanName) {
ApplicationListener listener = context.getBean(listenerBeanName, ApplicationListener.class);
System.out.println(listener);
// 获取该监听器支持的事件类型
ResolvableType type = ResolvableType.forClass(listener.getClass()).getInterfaces()[0].getGeneric();
System.out.println(type);
// 将原始的 listener 封装为支持类型检查的listener(GenericApplicationListener)
GenericApplicationListener genericApplicationListener = new GenericApplicationListener() {
@Override // 是否支持某事件类型,参数为真实的事件类型
public boolean supportsEventType(ResolvableType eventType) {
return type.isAssignableFrom(eventType);
}
@Override // 调用原始 listener 的 onApplicationEvent()
public void onApplicationEvent(ApplicationEvent event) {
executor.submit(() -> listener.onApplicationEvent(event));
}
};
listeners.add(genericApplicationListener);
}
@Override // (发)广播事件
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
for (GenericApplicationListener listener : listeners) {
if (listener.supportsEventType(ResolvableType.forClass(event.getClass()))) {
listener.onApplicationEvent(event);
}
}
}
};
}
static class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster {
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
}
@Override
public void addApplicationListenerBean(String listenerBeanName) {
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
}
@Override
public void removeApplicationListenerBean(String listenerBeanName) {
}
@Override
public void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate) {
}
@Override
public void removeApplicationListenerBeans(Predicate<String> predicate) {
}
@Override
public void removeAllListeners() {
}
@Override
public void multicastEvent(ApplicationEvent event) {
}
@Override
public void multicastEvent(ApplicationEvent event, ResolvableType eventType) {
}
}
}
结果:
com.clp.test11.Test11$EmailApplicationListener@4c1d9d4b
com.clp.test11.Test11$MyEvent
......
com.clp.test11.Test11$SmsApplicationListener@d706f19
com.clp.test11.Test11$MyEvent
......
13:58:05.160 [main] DEBUG com.clp.test11.Test11$MyService - 主线业务
13:58:05.161 [main] DEBUG com.clp.test11.Test11$EmailApplicationListener - 发送邮件
13:58:05.161 [main] DEBUG com.clp.test11.Test11$SmsApplicationListener - 发送短信
......
标签:System,Spring,高级,public,context,new,部分,class,out From: https://www.cnblogs.com/aoe1231/p/17347255.html