跳至主要內容

AutoConfig与Starter

wangdx大约 8 分钟

自动装配简介

SpringBoot 服务整合

  • 项目的开发要求是不断进化的,而随着时间以及技术的推移,一个项目中除了基本的编程语言之外,还需要进行大量的应用服务整合,例如:在项目中会使用到 MYSQL 数据库进行持久化存储,同时会利用 Redis 实现分布式缓存,以及使用 RabbitMO 实现导松系统整合服务,这些都需要通过 Gradle 构建工具引入相关的依赖库之后才可以整合到项目之中,为项目提供应有的服务支持。

Spring 自动装配

  • 在进行这些组件整合时,开发者只需要通过“xx-starter-xx”的依赖库就可以轻松实现各个服务的整合,这些程序组件在引入之后可以自动的实现装配,开发者只需要定义出核心的配置项即可使用
1、
project('microboot-web') { // 子模块
    dependencies { // 配置子模块依赖
        compile(project(':microboot-common')) // 引入其他子模块
        compile('org.springframework.boot:spring-boot-starter-actuator')
        compile(libraries.'spring-boot-starter-data-redis')
    }
}

@EnableConfigurationProperties

自定义自动装配类

  • 在 SpringBoot 开发框架中开发者可以直接基于“application.yml"配置文件实现某-个 Bean 对象的属性配置,注解定义配置的同时便用“@ConfigurationProperties”前缀信息,注解实现配置,而在 SpringBoot 自传统的做法是通过“@Component"动装配中,也可以通过自动配置类中的“@EnableConfigurationProperties({类.class 类.class...})”注解进行配置启用,这样就可以实现一个 Bean 对象的创建
1、
project('microboot-autoconfig-starter') { // 子模块
    dependencies { // 配置子模块依赖
        implementation('org.springframework.boot:spring-boot-starter-web')// 引入SpringBoot依赖
    }
}

2、
package com.yootk.vo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "muyan.yootk.dept")
public class Dept {
    private Long deptno;
    private String dname;
    private String loc;
}


3、
package com.yootk.config;

import com.yootk.vo.Dept;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration // 需要进行Bean的注册
@EnableConfigurationProperties({Dept.class}) // Bean注册
public class YootkAutoConfiguration { // 自动装配类
}


4、
package com.yootk;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StartAutoConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(StartAutoConfigApplication.class, args); // 运行SpringBoot程序
    }
}


5、
package com.yootk.test;

import com.yootk.StartAutoConfigApplication;
import com.yootk.vo.Dept;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;

@ExtendWith(SpringExtension.class) // 使用JUnit5测试工具
@WebAppConfiguration // 启动WEB运行环境
@SpringBootTest(classes = StartAutoConfigApplication.class) // 配置程序启动类
public class TestAutoConfig { // 编写测试类
    @Autowired
    private Dept dept;

    @Test
    public void testDept() {    // 进行响应测试
        System.out.println(this.dept);
    }
}


6、

muyan:
  yootk:
    dept:
      deptno: 10
      dname: 沐言科技(www.yootk.com)
      loc: 北京
7、
package com.yootk.test;

import com.yootk.StartAutoConfigApplication;
import com.yootk.vo.Dept;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;

@ExtendWith(SpringExtension.class) // 使用JUnit5测试工具
@WebAppConfiguration // 启动WEB运行环境
@SpringBootTest(classes = StartAutoConfigApplication.class) // 配置程序启动类
public class TestAutoConfig { // 编写测试类
    @Autowired
    @Qualifier("muyan.yootk.dept-com.yootk.vo.Dept") // “前缀 + 类名称”
    private Dept dept;

    @Test
    public void testDept() {    // 进行响应测试
        System.out.println(this.dept);
    }
}


8、
package com.yootk.test;

import com.yootk.StartAutoConfigApplication;
import com.yootk.config.YootkAutoConfiguration;
import com.yootk.vo.Dept;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;

@ExtendWith(SpringExtension.class) // 使用JUnit5测试工具
@WebAppConfiguration // 启动WEB运行环境
@SpringBootTest(classes = StartAutoConfigApplication.class) // 配置程序启动类
public class TestSpringContextBeanInfo { // 编写测试类
    @Test
    public void testBeanInfo() {    // 进行响应测试
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(YootkAutoConfiguration.class);
        String names[] = context.getBeanDefinitionNames(); // 获取Bean名称
        for (String name : names) {
            System.out.println("【"+name+"】" + context.getBean(name).getClass().getName());
        }
    }
}

@Import 注解

1、
package com.yootk.config;

import com.yootk.vo.Dept;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration // 需要进行Bean的注册
@Import({Dept.class}) // Bean注册
public class YootkAutoConfiguration { // 自动装配类
}


2、
package com.yootk.selector;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class DefaultImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.yootk.vo.Dept"}; // 导入类的名称
    }
}


3、
package com.yootk.config;

import com.yootk.selector.DefaultImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration // 需要进行Bean的注册
@Import({DefaultImportSelector.class}) // Bean注册
public class YootkAutoConfiguration { // 自动装配类
}


4、
package com.yootk.regist;

import com.yootk.vo.Dept;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class DefaultImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBean = new RootBeanDefinition(Dept.class); // 配置Bean
        registry.registerBeanDefinition("deptInstance", rootBean); // Bean注册
    }
}


5、
package com.yootk.config;

import com.yootk.regist.DefaultImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration // 需要进行Bean的注册
@Import({DefaultImportBeanDefinitionRegistrar.class}) // Bean注册
public class YootkAutoConfiguration { // 自动装配类
}

application.yml 配置提示

application.yml 配置提示

  • 当用户在项目中引入了某些“spring-boot-starter-xx”模块后除了会引入相关的依赖库之外,实际上也会引入一些配置提示的支持,这样开发者在配置 application.yml 文件时就可以根据给出的配置项进行组件定义,而这样的配置提示,开发者也可以根据自己的需要来实现
1、
project('microboot-autoconfig-starter') { // 子模块
    dependencies { // 配置子模块依赖
        annotationProcessor('org.springframework.boot:spring-boot-configuration-processor')
        implementation('org.springframework.boot:spring-boot-starter-web')// 引入SpringBoot依赖
    }
}

2、
jar {enabled = true} // 允许当前的模块打包为“*.jar”文件
javadocTask {enabled = false} // 不启用javadoc任务
javadocJar {enabled = false} // 不生成javadoc的“*.jar”文件
bootJar {enabled = false} // 不执行SpringBoot的打包命令

3、
gradle build

自定义 Starter 组件

自动配置 Bean

  • 利用自动配置类可以在容器启动时自动的进行 Bean 实例注册,由于不同的项目会存在有不同的自动配置类,所以为了便于其他模块的引用,就需要将配置类在'spring.factories”文件之中进行注册管理
1、
package com.yootk.config;

import com.yootk.regist.DefaultImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.util.List;

@Configuration // 需要进行Bean的注册
@Import({DefaultImportBeanDefinitionRegistrar.class}) // Bean注册
public class YootkAutoConfiguration { // 自动装配类
    @Bean(name = "books")
    public List<String> getBookList() { // 自定义一个注册Bean对象
        return List.of("Java面向对象编程", "Java就业编程实战",
                "JavaWEB就业编程实战", "Spring就业编程实战",
                "SpringBoot就业编程实战", "SpringCloud就业编程实战");
    }
}

package com.yootk.config;

import com.yootk.vo.Dept;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration // 需要进行Bean的注册
@EnableConfigurationProperties(value={Dept.class}) // Bean注册
public class YootkAutoConfiguration { // 自动装配类
    @Bean(name = "books")
    public List<String> getBookList() { // 自定义一个注册Bean对象
        return List.of("Java面向对象编程", "Java就业编程实战",
                "JavaWEB就业编程实战", "Spring就业编程实战",
                "SpringBoot就业编程实战", "SpringCloud就业编程实战");
    }
}


2、
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yootk.config.YootkAutoConfiguration

3、
project('microboot-web') { // 子模块
    dependencies { // 配置子模块依赖
        compile(project(':microboot-common')) // 引入其他子模块
        compile(project(':microboot-autoconfig-starter')) // 引入其他子模块
        compile('org.springframework.boot:spring-boot-starter-actuator')
    }
}

4、
muyan:
  yootk:
    dept:
      deptno: 10
      dname: 沐言科技(www.yootk.com) —— 教学研发部
      loc: 北京

5、
package com.yootk.test;

import com.yootk.StartSpringBootApplication;
import com.yootk.vo.Dept;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;

import java.util.List;

@ExtendWith(SpringExtension.class) // 使用JUnit5测试工具
@WebAppConfiguration // 启动WEB运行环境
@SpringBootTest(classes = StartSpringBootApplication.class) // 配置程序启动类
public class TestAutoConfig { // 编写测试类
    @Autowired // 是由Spring容器提供的
    private Dept dept;
    @Autowired
    private List<String> books;
    @Test
    public void testConfig() {    // 进行响应测试
        System.out.println(this.dept);
        System.out.println(this.books);
    }
}

SpringBoot 启动核心类

SpringBoot 基本运行结构

  • 在传统的 Spring & SpringMVC 开发之中,项目的启动都极大的依赖于容器,例如:JavaSE 容器、JavaEE 容器,随后所有的组件都需要依据 XML 或 Bean 的方式进行配置然而在 SpringBoot 开发项目中,只需要引入相关的组件依赖,并编写核心的程序功能最后通过一个简单的 Java 类即可启动一个 Spring 容器,为用户提供服务

package com.yootk; // 父包,这个包中的所有子包的类会被自动扫描

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication // 一个注解解决所有的问题
public class StartSpringBootApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(StartSpringBootApplication.class,args); // 运行SpringBoot程序
    }
}

SpringApplication 构造方法

SpringBoot 应用启动

  • SpringBoot 的核心应用之中需要提供有相关的应用注解之外,最为核心的就是 SpringApplication 程序类,该类实现了容器的启动、Bean 注册、WEB 容器的配置等核心功能,而在程序启动时往往会采用如下语句:
    • SpringApplication.run(StartSpringBootApplication.class, args);
  • 在 SpringBoot 应用程序启动时,一般会通过 SpringApplication 类中的 run()方法完成随后还需要传入程序启动类的 Class 实例,下面打开 SpringApplication.run()方法的源代码进行逐步观察。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

SpringApplication.run()方法

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

启动内置 WEB 容器

SpringBoot 运行

  • SpringBoot 的程序存在有 WEB 以及 Reactive 两种运行模式,所以在进行应用上下文创建时,就需要动态的判断当前的应用环境,而在 SpringApplication 类的构造方法中已经获取了 WebApplicationType 枚举实例,这样就可以依据此实例获取通过 createApplicationContext()方法获取 ConfiqurableApplicationContext 接囗实例 SpringApplication.createApplicationContext()方法源代码
ServletWebServerApplicationContext

AbstractApplicationContext.refresh()方法

SpringBootCLl 配置

1、
auto-configuration、starters、cli、actuator

2、
https://spring.io/projects/spring-boot#learn
https://docs.spring.io/spring-boot/docs/current/reference/html/

3、
https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/2.4.3/spring-boot-cli-2.4.3-bin.zip

使用 Groovy 开发 SpringBoot 应用

1、
@RestController // Rest响应
class HelloAction {
	@RequestMapping("/")
	String home() {
		"www.yootk.com"
	}
}

2、
spring run hello.groovy -- --server.port=80

SpringBootCLl 工具管理

1、
spring init --dependencies=web,thymeleaf yootk-boot

2、
spring init --build=gradle --java-version=11 --dependencies=web,thymeleaf --packaging=war muyan-boot


3、
spring install org.springframework.boot:spring-boot-configuration-processor:2.4.5

4、
spring uninstall org.springframework.boot:spring-boot-configuration-processor:2.4.5

5、
spring uninstall --all

6、
spring shell

demo


上次编辑于: