@TOC
springboot中的条件注解
@Conditional
当触发特定条件时会装载该bean
该注解下有很多子注解,
@ConditionalOnClass
package org.springframework.boot.autoconfigure.condition;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Conditional;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnClassCondition.class})
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
案例—>>>
@ConditionalOnClass(name="com.mysql.cj.jdbc.Driver")
@Bean(value = "myUser")
public User User1(){
return new User("李四",23);
}
当修改为
com.mysql.cj.jdbc.DriverDatasource时,
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myUser' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:872)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344)
在获取bean时会提示找不到该bean
@ConditionalOnClass(name=“aaa”)注解在类aaa加载时才会装配该bean,其实这也体现在源码中,比如我们导入thmeleaf时,会自动导入相关配置依赖
例如在没有引入freemarker时,
在springbootautoconfig中的配置类信息中可以看到
这说明有一些配置类没有加载进来,如果这时候我们导入freemarker,再次查看
说明当没有导入freemarker时,有关于freemarker的配置信息不会加载
同理其他的一些依赖也是如此;
但是这也会引发一个问题,就是我肯不想
@ConditionalOnProperty配置类:
package com.gavin.config;
import com.gavin.pojo.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author Gavin
*/
@Configuration(proxyBeanMethods = false)
@Import(value = {User.class} )
public class MyConfig {
@Bean(value = "myUser")
@ConditionalOnProperty(name = "server.port" ,havingValue = "8080")
//当配置中有server.port且值为8080时会加载这个bean
public User getUser(){
return new User("张三",23);
}
}
@SpringBootApplication
public class ZzyApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ZzyApplication.class, args);
User getUser = context.getBean("myUser", User.class);
System.out.println(getUser);
}
}
如果类似的注解在类上,那么这表示配置类中的所有bean都会被加载,
@ConditionalOnProperty(name = "server.port" ,havingValue = "8080")
@Configuration(proxyBeanMethods = false)
@Import(value = {User.class} )
public class MyConfig {
那么就会产生一个问题----优先级的问题
类注解上有该注解,方法上也有注解;
发现当注解的信息名相同,但是值不同时,都会报错,即相同的配置只能有一个 ;
@ConfigureProperties
在这个注解案例之前先回顾一下之前装配数据的方式---->>@Value
@AllArgsConstructor
@NoArgsConstructor
@Data
@Component
public class User implements Serializable {
@Value("周三干")
private String uName;
@Value("18")
private Integer uAge;
private static final long serialVersionUID = -1L;
}
通过配置文件进行bean的注入
我们知道,springboot在扫描配置文件的时候会扫描yml,yaml以及properties配置文件,所以我们可以通过.properties的方式来完成bean中属性数据的注入----这就需要依靠@ConfigureProperties来完成,
@Configuration
public class MyConfig {
application.properties文件
user.uName=zzy
user.uAge=29
package com.gavin.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @author Gavin
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@ConfigurationProperties(prefix = "user")//匹配前缀,一般习惯类的小写
@Component//注册bean
public class User implements Serializable {
//@Value("周三干")
private String uName;
//@Value("18")
private Integer uAge;
private static final long serialVersionUID = -1L;
}
当然我们按照习惯会将注解添加到配置类上
则这时需要的注解有所改变---->>
@ EnableConfigurationProperties
package org.springframework.boot.context.properties;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EnableConfigurationPropertiesRegistrar.class})
public @interface EnableConfigurationProperties {
String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
Class<?>[] value() default {};
}
案例
@EnableConfigurationProperties(User.class)
public class MyConfig {
@AllArgsConstructor
@NoArgsConstructor
@Data
@Component
@ConfigurationProperties(prefix = "user")
public class User implements Serializable {
//@Value("周三干")
private String uName;
//@Value("18")
private Integer uAge;
private static final long serialVersionUID = -1L;
}
小结—>>>如果在实体类上注解—>>
@Component//注册bean
@ConfigureProperties(prefix=“指定前缀”),
配置类上注解---->>>@Configuration
如果在配置类上,则实体类上
则只需要将配置类上注解换成@EnableConfigurationProperties(User.class)
在springboot中以xml方式引入bean(了解)
自己定义xml配置文件,在文件中配置bean,这需要在resources目录下准备一个xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.gavin.pojo.User">
<property name="UName" value="李四五"/>
<property name="UAge" value= '18'/>
</bean>
</beans>
配置xml之后,还需要将扫描该文件,因为默认会扫描yml,yaml,properties文件,所以要通过注解来完成对xml文件的导入;
@Configuration
@ImportResource(value = "classpath:beans.xml")
public class MyConfig {
可以添加 @ComponentScan没有任何参数或使用 @SpringBootApplication隐式包含它的注释。 您的所有应用程序组件( @Component, @Service, @Repository, @Controller, and others) 被自动注册为 Spring Beans。
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
如果一个 bean 有多个构造函数,你需要标记你希望 Spring 使用的那个
@Autowired:
import java.io.PrintStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
private final PrintStream out;
@Autowired
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
this.out = System.out;
}
public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
this.riskAssessor = riskAssessor;
this.out = out;
}
// ...
}
springboot的 延迟初始化
SpringApplication允许延迟初始化应用程序。 当启用延迟初始化时,bean 会在需要时创建,而不是在应用程序启动期间创建。 因此,启用延迟初始化可以减少应用程序启动所需的时间。 在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 bean 在收到 HTTP 请求之前不会被初始化。
延迟初始化的一个缺点是它会延迟应用程序问题的发现。 如果配置错误的 bean 被延迟初始化,则在启动期间将不再发生故障,并且只有在 bean 初始化时问题才会变得明显。 还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 bean,而不仅仅是那些在启动期间初始化的 bean。 由于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前对 JVM 的堆大小进行微调。
可以使用以下方式以编程方式启用延迟初始化 lazyInitialization方法 SpringApplicationBuilder或者 setLazyInitialization方法 SpringApplication. 或者,可以使用 spring.main.lazy-initialization属性如下例所示:
特性
yaml
spring.main.lazy-initialization=true
如果禁用某些 bean 的延迟初始化,同时对应用程序的其余部分使用延迟初始化,您可以使用显式将它们的延迟属性设置为 false @Lazy(false)注解。
springboot的热插拔
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.6.3</version>
</dependency>
设置一下idea
设置registry
某些资源在更改时不一定需要触发重新启动。 例如,Thymeleaf 模板可以就地编辑。 默认情况下,更改资源 /META-INF/maven, /META-INF/resources, /resources, /static, /public, 或者 /templates不会触发重新启动,但会触发 实时重新加载 。 如果要自定义这些排除项,可以使用 spring.devtools.restart.exclude财产。 例如,仅排除 /static和 /public您将设置以下属性:
特性
yaml
spring.devtools.restart.exclude=static/,public/
如果要保留这些默认值并 添加 其他排除项,请使用 spring.devtools.restart.additional-exclude而是财产。
Springboot的延迟初始化
SpringApplication允许延迟初始化应用程序。 当启用延迟初始化时,bean 会在需要时创建,而不是在应用程序启动期间创建。 因此,启用延迟初始化可以减少应用程序启动所需的时间。 在 Web 应用程序中,启用延迟初始化将导致许多与 Web 相关的 bean 在收到 HTTP 请求之前不会被初始化。
延迟初始化的一个缺点是它会延迟应用程序问题的发现。 如果配置错误的 bean 被延迟初始化,则在启动期间将不再发生故障,并且只有在 bean 初始化时问题才会变得明显。 还必须注意确保 JVM 有足够的内存来容纳应用程序的所有 bean,而不仅仅是那些在启动期间初始化的 bean。 由于这些原因,默认情况下不启用延迟初始化,建议在启用延迟初始化之前对 JVM 的堆大小进行微调。
可以使用以下方式以编程方式启用延迟初始化 lazyInitialization方法 SpringApplicationBuilder或者 setLazyInitialization方法 SpringApplication. 或者,可以使用 spring.main.lazy-initialization属性如下例所示:
特性
yaml
spring.main.lazy-initialization=true
如果您想禁用某些 bean 的延迟初始化,同时对应用程序的其余部分使用延迟初始化,您可以使用显式将它们的延迟属性设置为 false @Lazy(false)注解。