# spring boot 实验 2 **Repository Path**: superlgc/spring_boot_experiment_2 ## Basic Information - **Project Name**: spring boot 实验 2 - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-04-14 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

东莞理工学院网络空间安全学院

实验报告模板

课程名称:企业级开发框架专题 学期:2019年秋季
课程名称 利用Spring boot的自动装配特性实现动态注册组件 实验序号
姓   名 李贵超 学   号 201741412214 班   级 17软件工程卓越2班
实验地点 实验日期 2020/4/10 指导老师 黎志雄
教师评语 实验成绩 评阅教师
百分制
同组同学
### 一、实验目的 **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项目。** 添加Spring Configuration Processor依赖。 ![输入图片说明](pic/1.png) **2. 创建一个自定义的CommandLineRunner接口的实现类。** 若加上@Component注解,该CommandLineRunner会执行两次。 ```java @SuppressWarnings("unused") public class MyCommandLineRunner implements CommandLineRunner { Environment env; public MyCommandLineRunner(Environment env) { this.env = env; } @Override public void run(String... args) throws Exception { System.out.println("利用Spring Boot自动装配的CommandLineRunner."); System.out.println("生成一个随机字符串".concat(Objects.requireNonNull(env.getProperty("random.")))); } } ``` **3. 创建一个自定义的自动配置类。** 该配置类加上@Component注解,也可以把自定义bean注册到Spring容器中。 ```java public class MyAutoConfig { @Bean CommandLineRunner createCustomCommandLineRunner(Environment env) { return new MyCommandLineRunner(env); } } ``` **4. 创建spring.factories文件** spring.factories文件必须添加在META-INF目录下 ![输入图片说明](pic/2.png) 添加以下内容,spring.factories文件记录了需要注册的bean的类名,然后由@EnableAutoConfiguration注解进行注册。 ```properties org.springframework.boot.autoconfigure.EnableAutoConfiguration=MyAutoConfig ``` 运行结果 ![输入图片说明](pic/3.png) **5. 给自动配置类添加有效条件。** @ConditionalOnProperty注解从application.properties中读取指定值("prefix"."name"),如果该值为空,则返回false;如果非空,则将该值与havingValue指定的值进行比较,如果相等则返回true;否则返回false。如果返回值为false,则该配置类不生效;为true则生效。 ```java public class MyAutoConfig { @Bean @ConditionalOnProperty(prefix = "test.auto", name = "enable", havingValue = "true") CommandLineRunner createCustomCommandLineRunner(Environment env) { return new MyCommandLineRunner(env); } } ``` 在application.properties属性文件中添加一个自定义的属性。 ```properties test.auto.enable=true ``` 若test.auto.enable=false,则配置类不生效。 ![输入图片说明](pic/4.png) **6. 自定义的一个Bean,绑定属性值,并生成spring配置类的元数据文件。** 创建一个类,并在类上加@ConfigurationProperties注解,设置注解的prefix属性指定绑定的属性的前缀。 ```java @ConfigurationProperties(prefix = "test.auto") public class MyProperties { private boolean enable; public boolean isEnable() { return enable; } public void setEnable(boolean enable) { this.enable = enable; } } ``` 在某个配置类上添加@EnableConfigurationProperties,并指定装配的属性Bean。 ```java @EnableConfigurationProperties(MyProperties.class) public class MyAutoConfig { @Bean @ConditionalOnProperty(prefix = "test.auto", name = "enable", havingValue = "true") CommandLineRunner createCustomCommandLineRunner(Environment env) { return new MyCommandLineRunner(env); } } ``` 使用spring boot框架提供的注解处理器生成自定义属性的元数据文件。 pom文件导入依赖。 ```pom org.springframework.boot spring-boot-configuration-processor true ``` 编译打包项目。target目录下会生成元数据文件。 ![输入图片说明](pic/5.png) 编辑application.properties时,idea出现自动提示。 ![输入图片说明](pic/6.png) **7. 根据阅读框架源码,我们可以自定义一个事件发布器,并设置线程池,实现异步发布事件。但注意:这个自定义的事件发布器的Bean的名称必须是“applicationEventMulticaster”。** 自定义的事件发布器 ```java @Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME) ApplicationEventMulticaster customApplicationEventMulticaster(ThreadPoolTaskExecutor taskExecutor) { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); eventMulticaster.setTaskExecutor(taskExecutor); return eventMulticaster; } ``` 自定义事件类 ```java static 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; } } ``` 自定义事件监听器 ```java @Component static 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()); } } ``` 测试类 ```java @SpringBootTest class SpringBootExperiment02ApplicationTests { @Autowired ApplicationEventMulticaster eventMulticaster; @Test void testAsyncEventMulticaster() throws InterruptedException { eventMulticaster.multicastEvent(new MyAutoConfig.NoticeEvent("hello")); eventMulticaster.multicastEvent(new MyAutoConfig.NoticeEvent("hi")); Thread.sleep(2100); } } ``` **8. 思考题,自定义线程池** 在application.properties中增加以下配置 ```properties thread.pool.corePoolSize=20 thread.pool.maxPoolSize=40 thread.pool.keepAliveSeconds=200 thread.pool.queueCapacity=20 ``` 绑定配置类 ```java @ConfigurationProperties(prefix = "thread.pool") public class MyThreadPoolProperties { private int corePoolSize; private int maxPoolSize; private int keepAliveSeconds; private int queueCapacity; } ``` 自定义线程池 ```java @Bean public ThreadPoolTaskExecutor myTaskPool() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(poolProperties.getCorePoolSize()); executor.setMaxPoolSize(poolProperties.getMaxPoolSize()); executor.setQueueCapacity(poolProperties.getQueueCapacity()); executor.setKeepAliveSeconds(poolProperties.getKeepAliveSeconds()); executor.setThreadNamePrefix("MyTask-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } ``` 使用自定义的线程池 ```java @Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME) ApplicationEventMulticaster customApplicationEventMulticaster(@Qualifier("myTaskPool") ThreadPoolTaskExecutor taskExecutor) { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); eventMulticaster.setTaskExecutor(taskExecutor); return eventMulticaster; } ``` ### 四、实验总结 在老师上课的时候听完感觉很容易,可能是因为老师课讲得太好了,自己动手做的时候出现了各种问题,通过这次实验,我理解了springboot是如何进行自动配置和注册bean的,学会了如何将自己写的bean注册进spring容器。