Spring Boot的项目一般都会有*Application的入口类,入口类中会有main方法,这是一个标准的Java应用程序的入口方法。
@SpringBootApplication注解是Spring Boot的核心注解,它其实是一个组合注解:
1. @SpringBootConfiguration:这是Spring Boot项目的配置注解,这也是一个组合注解:
2. 在Spring Boot项目中推荐使用@SpringBootConfiguration替代@Configuration
所谓的替代,我们可以简单地理解,SpringBoot里面@SpringBootConfiguration就是@Configuration换了一个名字而已
源代码
https://gitee.com/gaoxinfu_admin/demo-spring-boot/tree/master/demo-spring-boot-example-04/src/main/java/com/gaoxinfu/demo/springboot/componentscan
1.Configuration 这个注解大家应该有用过,它是 JavaConfig形式的基于Spring IOC容器的配置类使用的一种注解。
因为SpringBoot 本质上就是一个spring 应用,所以通过这个注解来加载 IOC 容器的配置是很正常的。所以在启动类
里面标注了@Configuration,意味着它其实也是一个IoC容器的配置类。
2.传统意义上的 spring 应用都是基于 xml 形式来配置 bean的依赖关系。然后通过 spring 容器在启动的时候,把bean
进行初始化并且,如果 bean 之间存在依赖关系,则分析这些已经在 IoC 容器中的 bean 根据依赖关系进行组装。
3.直到 Java5 中,引入了 Annotations 这个特性,Spring 框架也紧随大流并且推出了基于Java代码和 Annotation元
信息的依赖关系绑定描述的方式。也就是JavaConfig。
从spring3 开始,spring 就支持了两种 bean 的配置方式,一种是基于 xml 文件方式、另一种就是 JavaConfig
package com.gaoxinfu.demo.springboot.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 16:56
*/
public class ConfigurationBean {
public void say(){
System.out.println("say() = Hello");
}
}
package com.gaoxinfu.demo.springboot.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 16:55
*/
@Configuration
public class ConfigurationDemo {
@Bean
public ConfigurationBean configurationBean(){
return new ConfigurationBean();
}
}
package com.gaoxinfu.demo.springboot.configuration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 16:56
*/
public class ConfigurationMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext AnnotationConfigApplicationContext=new AnnotationConfigApplicationContext(ConfigurationDemo.class);
ConfigurationBean configurationBean= AnnotationConfigApplicationContext.getBean(ConfigurationBean.class);
if (configurationBean!=null){
configurationBean.say();
}else{
System.out.println("configurationBean = "+configurationBean);
}
}
}
1. @EnableAutoConfiguration:启用自动配置,
2. 该注解会使Spring Boot根据项目中依赖的jar包自动配置项目的配置项:
例如:
我们添加了spring-boot-starter-web的依赖,项目中也就会引入SpringMVC的依赖,
Spring Boot就会自动配置tomcat和SpringMVC
EnableAutoConfiguration该注解包含两块 @AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
源代码
https://gitee.com/gaoxinfu_admin/demo-spring-boot/tree/master/demo-spring-boot-example-04/src/main/java/com/gaoxinfu/demo/springboot/enableautoconfiguration/importdemo
FirstBean.java
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.first;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 20:40
*/
public class FirstBean {
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.first;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.second.SecondBean;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.second.SecondConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
**FirstConfig.java**
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 20:40
*/
@Configuration
public class FirstConfig {
@Bean
public FirstBean firstBean(){
return new FirstBean();
}
}
FirstMain.java
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.first;
import com.gaoxinfu.demo.springboot.configuration.ConfigurationBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 20:42
*/
public class FirstMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext AnnotationConfigApplicationContext=new AnnotationConfigApplicationContext(FirstConfig.class);
String[] beanDefinitionNames=AnnotationConfigApplicationContext.getBeanDefinitionNames();
for (String beanDefinitionName:beanDefinitionNames){
System.out.println("BeanDefinitionName = "+beanDefinitionName);
}
}
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.second;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 20:42
*/
public class SecondBean {
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.second;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 20:42
*/
@Configuration
public class SecondConfig {
@Bean
public SecondBean secondBean(){
return new SecondBean();
}
}
直接运行上面的FirstMain.main方法,只会出现first文件夹下的,second下面的bean不会加载进来
FirstConfig.java
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.first;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.second.SecondBean;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importdemo.second.SecondConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 20:40
*/
@Configuration
@Import(SecondConfig.class)
public class FirstConfig {
@Bean
public FirstBean firstBean(){
return new FirstBean();
}
}
再次运行FirstMain.main()方法,second文件夹bean引入
源代码
https://gitee.com/gaoxinfu_admin/demo-spring-boot/tree/master/demo-spring-boot-example-04/src/main/java/com/gaoxinfu/demo/springboot/enableautoconfiguration/importselectordemo
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 22:05
*/
public class UserLoginService {
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 22:06
*/
public class UserBusinessService {
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* @Description: 启动用户定义的Service
* @Author: gaoxinfu
* @Date: 2020-04-18 22:07
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({UserImportSelector.class})
public @interface EnableUserDefineService {
Class<?>[] exclude() default {};
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 22:06
*/
public class UserImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
Map<String,Object> attributes=
annotationMetadata.getAnnotationAttributes(EnableUserDefineService.class.getName());
//动态注入bean :自己去实现判断逻辑实现动态配置
Class<?>[] excludeCLass= (Class<?>[]) attributes.get("exclude");
//TODO 这里可以做判断,拉出UserBusinessService和UserLoginService等所有的(匹配到)
//根据exclude 然后删除UserLoginService
return new String[]{UserBusinessService.class.getName()}; //返回的是一个固定的UserBusinessService
}
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 22:11
*/
@SpringBootApplication
@EnableUserDefineService(exclude = {UserLoginService.class})
public class UserMain {
public static void main(String[] args) {
ConfigurableApplicationContext configurableApplicationContext
=SpringApplication.run(UserMain.class,args);
System.out.println(configurableApplicationContext.getBean(UserBusinessService.class));
}
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.ImportBeanDefinitionRegistrarDemo;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo.UserLoginService;
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;
import org.springframework.util.StringUtils;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-19 11:16
*/
public class UserLogginDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Class beanClass= UserLoginService.class;
RootBeanDefinition beanDefinition=new RootBeanDefinition(beanClass);
String beanName= StringUtils.uncapitalize(beanClass.getSimpleName());
registry.registerBeanDefinition(beanName,beanDefinition);
}
}
package com.gaoxinfu.demo.springboot.enableautoconfiguration.ImportBeanDefinitionRegistrarDemo;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo.EnableUserDefineService;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo.UserBusinessService;
import com.gaoxinfu.demo.springboot.enableautoconfiguration.importselectordemo.UserLoginService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 22:11
*/
@SpringBootApplication
@Import(UserLogginDefinitionRegistrar.class)
public class UserMain {
public static void main(String[] args) {
ConfigurableApplicationContext configurableApplicationContext
=SpringApplication.run(UserMain.class,args);
System.out.println(configurableApplicationContext.getBean(UserLoginService.class));
}
}
**对应类所在的包下面的 spring-autoconfigure-metadata.properties文件 主要是一些spring中的大部分的Configuration,先扫到,后面用那个再说
**
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
META-INF/spring.factories样例
这里注意下,上面的key是可以进行扩展的,在别的地方定义的同样的key,其value也会被增加扩展加载进来
源码地址
https://gitee.com/gaoxinfu_admin/demo-spring-boot/tree/master/demo-spring-boot-example-05
package com.gaoxinfu.demo.spring.boot.example05.bean;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-19 14:19
*/
public class MyBean {
}
package com.gaoxinfu.demo.spring.boot.example05.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-19 14:19
*/
@Configuration
public class MyConfig {
@Bean
public MyBean myBean(){
return new MyBean();
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.gaoxinfu.demo.spring.boot.example05.bean.MyConfig
package com.gaoxinfu.demo.springboot.enableautoconfiguration.spi;
import com.gaoxinfu.demo.spring.boot.example05.bean.MyBean;
import com.gaoxinfu.demo.spring.boot.example05.bean.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-19 14:24
*/
@SpringBootApplication
public class SpiMain {
public static void main(String[] args) {
ConfigurableApplicationContext ConfigurableApplicationContext
=SpringApplication.run(SpiMain.class,args);
System.out.println(ConfigurableApplicationContext.getBean(MyBean.class));
}
}
1.可以看得出来,demo-spring-boot-example-05中的spring.factories中我们配置的MyBean这个类已经被加载IOC容器中了
spring-autoconfigure-metadata.properties配置内容
即当com.gaoxinfu.demo.springboot.enableautoconfiguration.spi.MyTest这个类存在的时候,
才会加载MyConfig中的相关bean到IOC中
ConditionalOnClass
com.gaoxinfu.demo.spring.boot.example05.bean.MyConfig.ConditionalOnClass=com.gaoxinfu.demo.springboot.enableautoconfiguration.spi.MyTest
package com.gaoxinfu.demo.springboot.enableautoconfiguration.spi;
import com.gaoxinfu.demo.spring.boot.example05.bean.MyConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-19 14:24
*/
@SpringBootApplication
public class SpiMain {
public static void main(String[] args) {
ConfigurableApplicationContext ConfigurableApplicationContext
=SpringApplication.run(SpiMain.class,args);
System.out.println(ConfigurableApplicationContext.getBean(MyConfig.class));
}
}
因为spi文件夹下面没有MyTest类,导致MyConfig将Bean注入的IOC容器中
package com.gaoxinfu.demo.springboot.enableautoconfiguration.spi;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-19 16:48
*/
public class MyTest {
}
@ComponentScan:默认扫描@SpringBootApplication所在类的同级目录以及它的子目录。
package com.gaoxinfu.demo.springboot.componentscan;
import org.springframework.stereotype.Service;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 16:56
*/
@Service
public class ComponentScanBean {
public void say(){
System.out.println("say() = Hello");
}
}
package com.gaoxinfu.demo.springboot.componentscan;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* @Description:
* @Author: gaoxinfu
* @Date: 2020-04-18 16:56
*/
@ComponentScan
public class ComponentScanMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext AnnotationConfigApplicationContext=new AnnotationConfigApplicationContext(ComponentScanMain.class);
String[] definitionNames= AnnotationConfigApplicationContext.getBeanDefinitionNames();
for(int i=0;i< definitionNames.length;i++){
System.out.println("definitionName = "+definitionNames[i]);
}
}
}
会自动扫面到@Service的类ComponentScanBean
1.也可以通过
@ComponentScan(basePackages = "com.gaoxinfu.demo.springboot.componentscan")
设置扫描的路径
多个路径的话,可以用逗号分隔开
@ComponentScan(basePackages = "com.gaoxinfu.demo.springboot.componentscan,com.gaoxinfu.demo.springboot.configuration")
通过上述,我们得知,Spring Boot会根据项目中的jar包依赖,自动做出配置,
Spring Boot支持的自动配置如下(非常多):
如果我们不需要Spring Boot自动配置,想关闭某一项的自动配置,该如何设置呢?
比如:我们不想自动配置Redis,想手动配置。
这个图片其实是可以自定义的:
http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20
拷贝生成的字符到一个文本文件中,并且将该文件命名为banner.txt
将banner.txt拷贝到项目的resources目录中:
重新启动程序,查看效果,会有新的图案显示
如果不想看到任何的banner,也是可以将其关闭的:
xxxx-autoconfigure-xxx.jar包下
有可能多个,下面是其中一个 spring-boot-autoconfigure-xxx.jar
Spring Boot对各种日志框架都做了支持,我们可以通过配置来修改默认的日志的配置:
#设置日志级别
logging.level.org.springframework=DEBUG
格式:
logging.level.*= # Log levels severity mapping. For instance `logging.level.org.springframework=DEBUG`