# springboot-experiment2
**Repository Path**: lirisheng/springboot-experiment2
## Basic Information
- **Project Name**: springboot-experiment2
- **Description**: 利用Spring boot 的自动装配特性实现动态注册组件
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-04-13
- **Last Updated**: 2020-12-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 实验二 利用Spring boot 的自动装配特性实现动态注册组件
### 一.实验目的
1) 掌握Spring Boot的自动配置原理;
2) 掌握Spring框架动态注册Bean的原理;
3) 掌握自动生成元数据文件。
4) 掌握spring框架的事件模型。
### 二.实验环境
1) JDK 1.8或更高版本
2) Maven 3.6+
3) IntelliJ IDEA
### 三.实验任务
1) 自定义配置类,并配置相应的配置元数据
2) 自定义一个事件发布器
3) 自定义一个线程池
### 四.实验步骤及结果
1) **自定义配置类,并配置相应的配置元数据**
* **核心:其实Spring boot在启动时实现自动配置,原理上就是把自动配置类作为bean注入到Spring container中,然后在合适的情况下这些自动配置的bean起作用**
* **如何添加自定义的自动配置**
步骤:
1) 编写一个自定义要配置的类
```java
public class HelloConfig {
public HelloConfig(){
System.out.println("自定义的HelloConfig自动配置起作用");
}
}
```
2) 编写配置的类,实现上面的类的自动配置功能
```java
package com.lirisheng.experiment.autoConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
public class AutoConfig {
@Bean
HelloConfig helloConfig(){
return new HelloConfig();
}
}
```
3) 使上面的配置类起作用,即在项目中的`resources`目录下创建一个META-INF文件夹,再在该文件夹下创建`spring.factories`文件,该文件的内容如下
```
//注意该key一定是EnableAutoConfiguration,因为跟Spring boot默认的spring.factories里面的key一样
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.lirisheng.experiment.autoConfig.AutoConfig
```
4) 运行具有`@SpringBootApplication`类,查看自动配置的类是否起自动
* **如果我们有条件使自动配置类起作用(即注入到container中)**
步骤
1) 就是在`AutoConfig`类中利用`@ConditionalOnProperty`注解实现即可,代码如下
```java
package com.lirisheng.experiment.autoConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties(CustomProperties.class)
public class AutoConfig {
@Bean
@ConditionalOnProperty(prefix = "lirisheng.auto",name = "enable",havingValue = "true")
HelloConfig helloConfig(){
return new HelloConfig();
}
}
```
2) 运行@SpringBootApplication类,运行结果如下
3) 在`application.properties`中配置如下信息,使其生效
```java
lirisheng.auto.enable=true
```
4) 再次运行结果
* **如何为自动配置类添加配置元数据**
* 方法一:元数据文件可以自己手写
* 方法二:可以使用spring boot官方提供的依赖包自动生成
1) 原理:该依赖包李有spring boot提供的注解处理器,在项目编译是检查项目内所有的@ConfigurationProperties的类,并生成元数据文件
2) 步骤:
1) 在pom.xml文件中引入`spring-boot-configuration-processor`包,代码片段如下
```xml
org.springframework.boot
spring-boot-configuration-processor
true
```
2) 编写`CustomProperties.class`,并使用`@ConfigurationProperties`
```java
package com.lirisheng.experiment.autoConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "lirisheng.auto")
public class CustomProperties {
private boolean enable;
public boolean isEnable(){return enable;}
public void setEnable(boolean enable){this.enable=enable;}
}
```
3) 在`AutoConfig.class`中引入上面的类
```java
package com.lirisheng.experiment.autoConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
//在这里引入该类
@EnableConfigurationProperties(CustomProperties.class)
public class AutoConfig {
@Bean
@ConditionalOnProperty(prefix = "lirisheng.auto",name = "enable",havingValue = "true")
HelloConfig helloConfig(){
return new HelloConfig();
}
}
```
4) 运行项目,在target下就会出现元数据文件
5) 然后在`applicaiton.properties`文件中就会出现相关提示
2) **自定义一个事件发布器**
1) 什么是Springboot的事件发布器
事件发布器发布事件,监听器来捕获事件的发布(如何捕获,就通过发布事件的类型进行匹配),从而对可以对事件做出一下相关操作,或者其他的一些操作
2) 如何自定义事件发布器
* 简述:需要我们自定义自定义事件发布器,为了对自定义的事件发布器进行演示,还有自定义一个事件,以及该该事件的相应的监听器
* 自定义事件发布器的步骤
1) 自定义事件发布器
```java
@Configuration
public class EventConfiguration {
@Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
//把Springboot默认配置的线程池依赖注入
ApplicationEventMulticaster
applicationEventMulticaster(ThreadPoolTaskExecutor taskExecutor)
{
SimpleApplicationEventMulticaster eventMulticaster =new SimpleApplicationEventMulticaster();
//事件发布器设置该线程池,从而使得其异步发布事件
eventMulticaster.setTaskExecutor(taskExecutor);
return eventMulticaster;
}
}
```
2) 自定义事件
```java
public class NoticeEvent extends ApplicationEvent {
private static final Logger logger = LoggerFactory.getLogger(NoticeEvent.class);
private final String message;
public NoticeEvent(String message){
super(message);
this.message=message;
logger.info("添加事件成功!message:{}",message);
}
public String getMessage(){
return message;
}
}
```
3) 自定义监听器
```java
@Component
public class NoticeListener implements ApplicationListener {
private static final Logger logger = LoggerFactory.getLogger(NoticeListener.class);
@Override
public void onApplicationEvent(NoticeEvent noticeEvent) {
logger.info("事件监听器获取到 NoticeEvent,睡眠当前线程 2 秒....");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
logger.info("NoticeEvent 的 message 属性是:{}",noticeEvent.getMessage());
}
}
```
4) 编写一个测试用例,进行测试
```java
@Test
void testAsynMulticaster()throws InterruptedException{
eventMulticaster.multicastEvent(new NoticeEvent("东莞理工学院"));
eventMulticaster.multicastEvent(new NoticeEvent("网络计算机与安全学院"));
Thread.sleep(2000);
}
```
5) 测试结果
3) **扩展,如何自定义线程池,并把该线程池作为依赖注入到事件发布器中**
1) 总体思路
自定义一个线程池,然后把该线程池作为自动配置类加入到Springboot中
2) 如何自定义一个线程池,并作为自动配置类
```java
@EnableConfigurationProperties({CustomHelloProperties.class,CustomPoolTaskProperties.class})
public class AutoConfig {
@Bean
@ConditionalOnProperty(prefix = "lirisheng.auto",name = "enable",havingValue = "true")
HelloConfig helloConfig(){
return new HelloConfig();
}
@Bean("customPoolTask")
ThreadPoolTaskExecutor threadPoolTaskExecutor(CustomPoolTaskProperties customPoolTaskProperties){
ThreadPoolTaskExecutor threadPoolTaskExecutor=new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(customPoolTaskProperties.getCorePoolSize());
threadPoolTaskExecutor.setMaxPoolSize(customPoolTaskProperties.getMaxPoolSize());
System.out.println("自动配置的自定义线程池customPoolTask其作用");
return threadPoolTaskExecutor;
}
}
```
3) 配置该线程池的元数据,并利用该元数据来定制该线程池的corePoolSize,maxPoolSize属性
```java
@ConfigurationProperties(prefix = "lirisheng.taskpool")
public class CustomPoolTaskProperties {
private int corePoolSize=20;
private int maxPoolSize=20;
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
}
```
4) 使用自定义线程池,即其依赖注入到上面的自定义的发布器中
```java
@Configuration
public class EventConfiguration {
@Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
ApplicationEventMulticaster applicationEventMulticaster(@Qualifier("customPoolTask") ThreadPoolTaskExecutor taskExecutor){
SimpleApplicationEventMulticaster eventMulticaster =new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(taskExecutor);
return eventMulticaster;
}
}
```
5) 编写一个测试类,测试自定义的线程池
```java
@SpringBootTest
class ExperimentApplicationTests {
@Autowired
ApplicationEventMulticaster eventMulticaster;
@Test
void contextLoads() {
}
@Test
void testAsynMulticaster()throws InterruptedException{
eventMulticaster.multicastEvent(new NoticeEvent("东莞理工学院"));
eventMulticaster.multicastEvent(new NoticeEvent("网络计算机与安全学院"));
Thread.sleep(2000);
}
}
```
6) 测试结果
### 五.实验总结
1) 知道Springboot提供的自动配置的原理实质上就是把自定义的类在Spring容器初始化的时候作为bean注入到容器中,但为了对这些自定义的配置类的集中管理,所以就有了`spring.factories`文件的发明
2) 事件发布器发布事件,监听器来捕获事件的发布(如何捕获,即可通过发布事件的类型进行匹配),从而对可以对事件做出一下相关操作,或者其他的一些操作