# Springboot实验二 **Repository Path**: chainsawman/springboot-experiment-2 ## Basic Information - **Project Name**: Springboot实验二 - **Description**: 实验二 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-10-25 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Springboot实验二 | 实验名称: | 利用Spring boot的自动装配特性实现动态注册组件 | 实验序号: | 二 | |-------|---------------------|-------|--------------| | 姓名: | 陈志聪 | 学号: | 201841413203 | | 班级: | 18网工2班 | 实验地点: | 线上 | | 实验日期: | 2020/10/20 | 指导老师: | 黎志雄 | | 成绩: | | 同组同学: | 无 | **一、 实验目的** 1、 掌握Spring Boot的自动配置原理; 2、 掌握Spring框架动态注册Bean的原理; 3、 掌握自动生成元数据文件。 4、 掌握spring框架的事件模型。 **二、实验环境** 1、 JDK 1.8或更高版本 2、 Maven 3.6+ 3、 IntelliJ IDEA **三、实验任务** 1、 通过IntelliJ IDEA的Spring Initializr向导创建Spring Boot项目。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/080525_d4e62044_8165504.png "屏幕截图.png") 添加Spring Configuration Processor依赖 2、创建一个自定义的CommandLineRunner接口的实现类。 ```java import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.core.env.Environment; import java.util.Objects; @SpringBootApplication public class App { public static void main(String []args){ SpringApplication.run(App.class,args); } //@Component @EnableAutoConfiguration static class LocalCommandLineRunner implements CommandLineRunner { Environment env; public LocalCommandLineRunner(Environment env) { this.env=env; } @Override public void run(String... args){ System.out.println(">>>缺少注解EnableAutoConfiguration<<<\n"+">>>This is the Local CommandLineRunner!<<<"); System.out.println(">>>生成一个随机字符串:".concat((Objects.requireNonNull(env.getProperty("random."))))); } } } ``` 3、创建一个自定义的自动配置类。 ```java @Configuration @EnableConfigurationProperties(CustomProperties.class) @ConditionalOnProperty(prefix = "sai.auto",name="enable",havingValue = "true") public class AutoConfig { @Bean public RemoteCommandLineRunner rcr() { return new RemoteCommandLineRunner(); } } ``` 4、 创建spring.factories文件 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/081120_7ebafc78_8165504.png "屏幕截图.png") ```java org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.dgut.autoconfig.AutoConfig ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/081159_8d107357_8165504.png "屏幕截图.png") ```java org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ cn.edu.css.sai.App.LocalCommandLineRunner ``` 5、 给自动配置类添加有效条件。 1) 利用 @ConditionalOnProperty 注解,添加属性条件。 ```java @ConditionalOnProperty(prefix = "sai.auto",name="enable",havingValue = "true") ``` 2) 在application.properties属性文件中添加一个自定义的属性。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/081455_04807f90_8165504.png "屏幕截图.png") ```java sai: auto: enable: true ``` 6、 自定义的一个Bean,绑定属性值,并生成spring配置类的元数据文件。 1) 创建一个类,并在类上加@ConfigurationProperties注解,设置注解的prefix属性指定绑定的属性的前缀。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/081613_d4368501_8165504.png "屏幕截图.png") ```java package com.dgut.autoconfig; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "sai.auto") public class CustomProperties { /* 自动配置是否生效 */ boolean enable; public boolean isEnable() { return enable; } public void setEnable(boolean enable) { this.enable = enable; } } ``` 2) 在某个配置类上添加@EnableConfigurationProperties,并指定装配的属性Bean。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/081737_91a2c3be_8165504.png "屏幕截图.png") 3) 使用spring boot框架提供的注解处理器生成自定义属性的元数据文件。 ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/082055_1532e4b2_8165504.png "屏幕截图.png") 7、 根据阅读框架源码,我们可以自定义一个事件发布器,并设置线程池,实现异步发布事件。 a. 自定义的事件发布器: ```java package com.dgut.autoconfig; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.stereotype.Component; /* 发布类 */ @Slf4j @Component public class MailSender { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void publishEvent(MailSendEvent event) { System.out.println("事件初始化"); applicationEventPublisher.publishEvent(event); } } ``` b. 自定义事件类。 ```java package com.dgut.autoconfig; import ch.qos.logback.classic.Logger; import lombok.Data; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEvent; /* 事件类 */ @Data public class MailSendEvent extends ApplicationEvent { private String to; private String message; public String getTo() { return to; } public String getMessage() { return message; } private static final Logger log= (Logger) LoggerFactory.getLogger(MailSendEvent.class); public MailSendEvent(Object source, String to, String message){ super(source); this.to=to; this.message=message; log.info("添加事件成功!,message:{}",message); } } ``` c. 自定义事件监听器。 ```java package com.dgut.autoconfig; import ch.qos.logback.classic.Logger; import lombok.extern.slf4j.Slf4j; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationListener; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /* 监听器 */ @Component @Slf4j public class MailSendListener implements ApplicationListener { private static final Logger log= (Logger) LoggerFactory.getLogger(MailSendEvent.class); @Async @EventListener(classes ={MailSendEvent.class}) public void onApplicationEvent(MailSendEvent event){ log.info("MailSendEvent事件启动了..."); log.info("向{}发送邮件,邮件内容为:{}",event.getTo(),event.getMessage()); } } ``` d. 编写一个测试用例,检查发布事件时,是否使用了多线程异步处理。 ```java package com.dgut.autoconfig; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; public class MailTest { @Autowired private MailSender mailSender=new MailSender(); private MailSendListener mailSendListener=new MailSendListener(); private MailSendEvent mailSendEvent=new MailSendEvent(this, "tom", "hello world"); @Test public void testMailSender()throws InterruptedException{ System.out.println("运行测试类"); mailSender.publishEvent(mailSendEvent); mailSendListener.onApplicationEvent(mailSendEvent); } } ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/082217_ab916c22_8165504.png "屏幕截图.png") 9、自定义 ApplicationReadyEvent 的事件监听器。 ```java @Bean public ApplicationListener listener(){ return new ApplicationListener() { @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { System.out.println("自定义ApplicationReadyEvent事件监听器!"); } }; } ``` ![输入图片说明](https://images.gitee.com/uploads/images/2020/1025/082332_368a7bf0_8165504.png "屏幕截图.png") **实验总结** 注意事件类之间的交互