Springboot基础原理

Springboot2基础

https://blog.csdn.net/u011863024/article/details/113667634

入门案例

MAVEN的settings.xml中需要添加如下配置文件:

<mirrors>
	<mirror>
		<id>nexus-aliyun</id>
		<mirrorOf>central</mirrorOf>
		<name>Nexus aliyun</name>
		<url>http://maven.aliyun.com/nexus/content/groups/public</url>
	</mirror>
</mirrors>

<profiles>
	<profile>
		<id>jdk-1.8</id>

		<activation>
			<activeByDefault>true</activeByDefault>
			<jdk>1.8</jdk>
		</activation>

		<properties>
			<maven.compiler.source>1.8</maven.compiler.source>
			<maven.compiler.target>1.8</maven.compiler.target>
			<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
		</properties>
	</profile>
</profiles>

pom依赖

<-- Spring项目必须导入父依赖 版本是所使用的Springboot的版本-->
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.3.4.RELEASE</version>
</parent>
<-- Spring 	Web项目导入这个依赖即可-->
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>

打包部署:使用maven的插件

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

可以直接使用java -jar运行

可见Springboot相对于SpringMVC的优点:

简化配置,Springboot所整合的框架都可以在yml或者properties文件中同一配置,并且所有的配置Springboot都设置了默认值,并且通过maven来管理项目,通过简单的几项配置即可完成所需jar包的导入

简化部署,Springboot内置了Tomcat服务器,可以直接通过main方法启动:

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

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

业务部分兼容SpringMVC的所有功能:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String handle01(){
        return "Hello, Spring Boot 2!";
    }
}

SpringMVC需要打成war包,而Springboot通过MAVEN插件可以直接打成可以运行的jar包

Springboot版本管理

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.3.4.RELEASE</version>
</parent>

父项目可以用于进行版本管理,Springboot的父项目中帮我们定义了平时常用的jar包中匹配的版本号,从而避免一些版本不匹配的问题

这个也成为自动版本仲裁机制,如果不想使用Springboot指定的版本,我们可以自己设定版本(例如Mysql),重写里面的版本号(最近优先原则)

<properties>
	<mysql.version>5.1.43</mysql.version>
</properties>

spring-boot-starter-* : *代表某种场景,只要引入这个场景的starter就代表引入了这个场景所有常规的依赖

*-spring-boot-starter-*:第三方提供的starter

Springboot自动配置

引入并配置好了Tomcat
字符编码拦截器,文件上传解析器,视图解析器等
引入配置好了SpringMVC
SpringbootApplication.run的返回值就是Spring容器,里面有工作的所有组件

@SpringbootApplication

拥有默认包扫描规则:主程序所在的包,以及它的子包中的类都能被扫描,也可以通过配置
@SpringbootApplication(scanBasePackage=“com.demo”)来改变包的扫描路径
@SpringbootApplication等于以下三个注解(三合一注解):
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(“com.demo”)

可以用这三个注解代替@SpringbootApplication

properties中配置的属性最后都会映射到一个配置类上,这个类会在容器中创建对象
Springboot的所有配置功能都在spring-boot-starter-autoconfigure配置中设置
自动配置功能是按需加载的,引入了对应的场景后,对应的场景的自动配置才会生效

@Configuration和@Bean向添加Spring容器添加组件

@Configuration会将这个类申明为Springboot的一个配置类

在配置类中可以通过@Bean注解添加bean

添加的bean的名称就是我们的方法名,添加的bean就是方法的返回值,也可以通过@Bean(“cat”)在括号中设置bean的名称

Springboot.run的返回值就是Spring容器,我们可以在里面拿到容器中注册的所有bean

@SpringBootApplication
public class Demo2Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Demo2Application.class, args);
        for (String name : run.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

如果出现了组件依赖的情况,可以直接调用其他注册组件的方法来设置bean

@Configuration
public class MyConfig {
    @Bean
    Mypage page(){
        Mypage mypage = new Mypage();
        mypage.setUser(user01());
        return mypage;
    }
    @Bean
    User user01(){
        return new User("name","132");
    }
}

设置的bean可以在Spring容器中拿到,并且调用生成bean的方法拿到的bean和在Spring容器中拿到的bean是一样的:

@SpringBootApplication
@MapperScan("com.example.demo.mapper")//检测mapper的包
@MapperScan("com.example.demo.dao")//检测mapper的包
public class Demo2Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Demo2Application.class, args);
        for (String name : run.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        User user01 = run.getBean("user01", User.class);
        Mypage mypage=run.getBean(Mypage.class);
        System.out.println(user01==mypage.getUser());//返回true
    }
}

包括带有@Configuration的类也是Spring容器中组件的一个,也可以拿到这个bean,调用里面生成bean的方法拿到的bean仍然是唯一的,并不会生成一个新的bean:

@SpringBootApplication
@MapperScan("com.example.demo.mapper")//检测mapper的包
@MapperScan("com.example.demo.dao")//检测mapper的包
public class Demo2Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Demo2Application.class, args);
        User user01 = run.getBean("user01", User.class);
        Mypage mypage=run.getBean(Mypage.class);
        MyConfig config = run.getBean(MyConfig.class);
        System.out.println(config.user01()==user01);//true
        System.out.println(config.user01()== mypage.getUser());//true
        System.out.println(user01==mypage.getUser());//true
    }
}

这是因为我们拿到的MyConfig其实是通过CGLIB代理过的对象:

com.example.demo.config.MyConfig$$EnhancerBySpringCGLIB$$a35275ef@6bf54260

这个对象调用组件注册方法前,会先判断这个组件是否出现在Spring容器中,如果出现在了Spring容器中则返回Spring容器中的对象,否则才会new一个对象。

@Configuration(proxyBeanMethods = false)

proxyBeanMethods 默认为true,当这个属性值为true时Spring会帮我们生成上述的代理对象来保证Spring容器中对象的唯一性,用于设置组件之间的依赖关系(如果设置为false则不能在bean中注入其他属性),来容器外多次调用生成组件的方法返回的都是同一个对象。

如果设置为false,则不会生成代理对象,Spring容器可以更快的启动,但此时不能设置组件的依赖关系,外部调用生成组件的方法会生成多个对象。

扫描范围内的@Controller之类的注解的用法和SpringMVC相同

@Import

@Import 导入组件参数是class数组
容器中会自动创建一个这个类型的bean,默认名称是这个类的全限定名

@Condition 满足某些条件时做某些事情(条件装配)

@ConditionalOnBean 容器中有这个bean的时候才在容器启动时执行这个方法,可以通过name和type来指定。可以标注在方法上,也可以标注在类上,表示这个类的方法都需要满足这个条件。
@ConditionalOnMissingBean 没有这个bean的时候执行这个方法
还有其他的条件装配,这里只列举其中几个
@ImportResource(“文件路径”) 这个注解可以加载xml配置文件,往Spring容器中添加组件

配置绑定

原生java 使用Properties类的load方法加载配置文件,然后遍历
Spring方式
需要放在容器中才能使用Spring的功能,即必须加上@Component
@ConfigurationProperties(prefix=“xxx”) 将前缀为这个的配置文件和类中对应名称的属性值进行绑定,然后就可以通过这个类的对象拿到配置文件中的属性值
@EnableConfigurationProperties(xxx.class)将这个注解加在配置类上 开启属性配置功能,用这个注解代替@Component注解(对于一些我们无法修改的第三方的包可以用这种方式来绑定组件)将我们,@ConfigurationProperties也要加在需要绑定的类上,上面这个注解只是帮我们将其注册到容器中并开启指定类的配置绑定功能

自动配置原理

三合一注解:@SpringbootApplication

@SpringbootConfiguration 声明启动类是Spring容器的主配置类,功能和@Configuration一致
@ComponentScan 指定包扫描路径
@EnableAutoConfiguration 开启自动配置这个注解是以下两个注解的合成:
@ConfigurationPackage(指定默认包规则)
自动配置包,里面有@Import注解,用于引入包扫描器,将主类所在的包下面的组件进行批量注册(main方法所在的包)
@Import(AutoConfigurationImportSelector.class)
Springboot会在容器启动时,加载一些必须加载的组件,这些组件被写在各个jar包的META-INFO下的Spring.Factories中,其中有一个名为autoconfigure的jar包里面的这个目录下有这个配置文件,而这个注解就是用于加载这些配置文件(所有场景的jar包)的,这些配置会被全部加载进来,但最后会按需配置(条件装配)

按需加载功能通过使用注解来生效:

@ConditionalOnClass(xxx.class):如果类路径中有这个类就生效(编译时会编译失败,但是我们引入的jar是已经编译好的class文件)

@ConditionalOnMissingBean(value = xxx.class , name=“yyyy”):如果容器中有这个bean才会生效

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L8BzsE8N-1653538120209)(D:/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/picture/image-20220428183847161.png)]

如果这些注解加载类上,必须上面的条件都满足,才会在Spring容器的启动的时候加载这个类里面的方法向容器中添加组件,如果加在方法上,表示满足这些条件后,组件注册方法才会生效(执行)

	@Configuration(proxyBeanMethods = false)
	@Conditional(DefaultDispatcherServletCondition.class)
	@ConditionalOnClass(ServletRegistration.class)
	@EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
	protected static class DispatcherServletConfiguration {

@ConditionalWebApplication(type = Type.SERVLET) 判断当前的应用类型(是基于Servlet还是基于Reator)

@AutoConfigurationOrder() 设置配置的优先级,这里这个配置类的优先级设置为高

@Configuration(proxyBeanMethods = false) 前面说过,声明为组件,并使用轻量级配置

@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) 声明这个类要在ServletWebServerFactoryAutoConfiguration这个类之后配置

上述添加都满足后,我们再看类中注册bean的方法:

		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
			dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
			return dispatcherServlet;
		}

@Bean注解下的方法,如果传入了对象参数,Springboot会自动在Spring容器中找到这个对象并作为参数传入

SpringMVC中我们需要向Spring容器中注入DispatcherServlet类型的对象才能使用SpringMVC的Web功能,而Springboot帮我们在Spring容器中添加了这个对象,因而不需要我们手动去设置。

		@Bean
		@ConditionalOnBean(MultipartResolver.class)
		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
			// Detect if the user has created a MultipartResolver but named it incorrectly
			return resolver;
		}

这个方法负责注入处理文件上传的文件解析器,

@ConditionalOnBean(MultipartResolver.class) :Spring容器中有MultipartResolver这个类的对象

@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME):但是名字不是我们想要的名字

于是我们就执行这个方法,添加一个名字也是我们的想要的bean,@Bean注解添加的bean的名称就是我们的方法名,这样就保证了组件名字的一致性

再举一个例子:用来处理Http请求的编码类,防止出现中文乱码

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HttpProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

注解含义和之前都是类似的

	@Bean
	@ConditionalOnMissingBean
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}

@ConditionalOnMissingBean 如果没有CharacterEncodingFilter类型的bean,就执行下面这个方法,向容器中添加这个类型的bean

通过使用注解@ConditionalOnMissingBean,Spring会向容器中添加所有我们需要的组件,但如果用户自己配置了组件,则以用户配置的组件优先

总结:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XRC5AXG7-1653538120211)(D:/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/picture/image-20220429002822205.png)]

Spring容器会加载指定路径下所有的自动配置类,然后这些配置类会根据@Condition系列注解配置的条件判断是否生效,每个自动配置类在注册组件时,属性值需要从xxxProperties类中拿,xxxProperties中是属性值会有默认值,同时也和我们设置的配置文件绑定在一起。所以我们向修改组件可以通过修改配置文件来做到。容器有有了对应的组件也就有了对应的功能。注册组件前会先判断用户是否注册了对应类型的组件,如果注册了就以用户的优先,所以我们可以通过在配置类中使用@Bean注解来定制化我们自己想要的组件。

debug=true:开启自动配置报告

更多配置信息可以查阅官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties

spring.banner.image.location=xxx.jpg 指定spring加载的图标,默认路径是classpath下的banner.jpg

xxxxCustomize 自定义组件

开发小技巧

Lombok

引入依赖:

		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>

还需要下载Lombok插件

@Data :设置set get方法,设置toString,hashcode,equals方法

@AllArgsConstructor 全参数构造器

@NoArgsConstructor 无参数构造器

@Slf4j 自动添加一个log对象,用于打印日志

detTools

引入依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

调试时,代码的即使更新

修改静态文件时,重新编译即可

Spring Initailzer

帮我们创建全局的包结构和自动引入各种常用依赖,甚至还帮我们创建了.gitignore之类的文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值