网站做防篡改,红酒网站制作,购买空间后怎么上传网站,旅游网页首页SpringBoot 自动配置
Condition
Condition 是在Spring 4.0 增加的条件判断功能#xff0c;通过这个可以功能可以实现选择性的创建 Bean 操作
思考#xff1a;SpringBoot是如何知道要创建哪个Bean的#xff1f;比如SpringBoot是如何知道要创建RedisTemplate的#xff1f;…SpringBoot 自动配置
Condition
Condition 是在Spring 4.0 增加的条件判断功能通过这个可以功能可以实现选择性的创建 Bean 操作
思考SpringBoot是如何知道要创建哪个Bean的比如SpringBoot是如何知道要创建RedisTemplate的
演示1:
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
1. 没有添加坐标前发现为空报错ConfigurableApplicationContext context SpringApplication.run(SpringbootCondition01Application.class, args);Object redisTemplate context.getBean(redisTemplate);System.out.println(redisTemplate);
2. 有添加坐标前发现有对象ConfigurableApplicationContext context SpringApplication.run(SpringbootCondition01Application.class, args);Object redisTemplate context.getBean(redisTemplate);System.out.println(redisTemplate);
疑问他怎么知道的配置哪个类案例1案例1
Spring的IOC容器中有一个User的Bean现要求导入Jedis坐标后加载该Bean没导入则不加载
代码实现 POJO实体类User public class User {
}现在对User的加载有条件不能直接用Component注入需要写配置类通过Bean的方式注入 Configuration
public class UserConfig {BeanConditional(value ClassCondition.class) // 注入条件public User user(){return new User();}
}Conditional中的ClassCondition.class的matches方法返回true执行以下代码否则反之 创建ClassCondition类实现Condition接口重写matches方法 public class ClassCondition implements Condition {Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {boolean falg true;try {Class? cls Class.forName(redis.clients.jedis.Jedis);} catch (ClassNotFoundException e) {falgfalse;}return falg;}
}启动类 SpringBootApplication
public class SpringbootCondition01Application {public static void main(String[] args) {//启动SpringBoot的应用返回Spring的IOC容器ConfigurableApplicationContext context SpringApplication.run(SpringbootCondition01Application.class,args);//获取BeanredisTemplate//情况1 没有添加坐标前发现为空//情况2 有添加坐标前发现有对象Object user context.getBean(user);System.out.println(user);}
}测试通过pom文件中对Jedis坐标是否注释 Jedi坐标未注释可以打印出User对象地址 Jedis坐标被注释掉报错不打印User对象地址
案例二
在 Spring 的 IOC 容器中有一个 User 的 Bean现要求将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定
实现步骤
不使用Conditional(ClassCondition.class)注解自定义注解ConditionOnClass,因为他和之前Conditional注解功能一直所以直接复制编写ClassCondition中的matches方法
代码实现 POJO实体类User和案例1相同 User的注入条件需要改变使用ConditionOnClass Configuration
public class UserConfig {Bean
// ConditionOnClass(value redis.clients.jedis.Jedis) 有jedis坐标注入UserConditionOnClass(value {redis.clients.jedis.Jedis,com.alibaba.fastjson.JSON}) //jedis和json都有才注入 public User user(){return new User();}
}重写matches方法 public class ClassCondition implements Condition {Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {MapString, Object map metadata.getAnnotationAttributes(ConditionOnClass.class.getName());System.out.println(map:map);String[] value (String[]) map.get(value);boolean isok true;try {for(String val : value){Class? cls Class.forName(val);}}catch (ClassNotFoundException e){isok false;}return isok;}
}自定义注解 Target({ElementType.TYPE,ElementType.METHOD})//可以修饰在类与方法上
Retention(RetentionPolicy.RUNTIME)//注解生效节点runtime
Documented//生成文档
Conditional(value ClassCondition.class)
public interface ConditionOnClass {String[] value(); //设置此注解的属性redis.clients.jedis.Jedis
}启动类 SpringBootApplication
public class SpringbootCondition02Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootCondition02Application.class, args);Object user context.getBean(user);System.out.println(user);}
}测试通过pom文件中的Jedis和JSON坐标测试 Jedis和JSON坐标都有打印User对象地址只有一个坐标或者都没有报错不打印User对象地址
Condition总结
自定义条件
定义条件类自定义类实现Condition接口重写 matches 方法在 matches 方法中进行逻辑判断返回boolean值 。matches 方法两个参数 context上下文对象可以获取属性值获取类加载器获取BeanFactory等。metadata元数据对象用于获取注解属性。 判断条件 在初始化Bean时使用 Conditional(条件类.class)注解
SpringBoot提供的常用条件注解
一下注解在springBoot-autoconfigure的condition包下
ConditionalOnProperty判断配置文件中是否有对应属性和值才初始化BeanConditionalOnClass判断环境中是否有对应字节码文件才初始化BeanConditionalOnMissingBean判断环境中没有对应Bean才初始化BeanConditionalOnBean判断环境中有对应Bean才初始化Bean
Enable注解
SpringBoot中提供了很多Enable开头的注解这些注解都是用于动态启用某些功能的。而其底层原理是使用Import注 解导入一些配置类实现Bean的动态加载
思考 SpringBoot 工程是否可以直接获取jar包中定义的Bean
Enable的底层核心Import
Enable底层依赖于Import注解导入一些类使用Import导入的类会被Spring加载到IOC容器中。而Import提供4中用法
导入Bean导入配置类导入 ImportSelector 实现类。一般用于加载配置文件中的类导入 ImportBeanDefinitionRegistrar 实现类
导入Bean
代码实现
需要用到多模块编程项目结构如图 springboot_enable_02 springboot项目pom文件不需要格外到坐标 User public class User {
}UserConfig Configuration
public class UserConfig {Beanpublic User user(){return new User();}
}EnableUser自定义注解 Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Documented
Import(UserConfig.class)
public interface EnableUser {
}启动类 SpringBootApplication
public class SpringbootEnable02Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootEnable02Application.class, args);Object user context.getBean(user); // enable_02中肯定能取到UserSystem.out.println(user);}
}springboot_enable_01 pom文件导入springboot_enable_02的gav dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope
/dependency!--模块2--
dependencygroupIdcom.dong/groupIdartifactIdspringboot_enable_02/artifactIdversion0.0.1-SNAPSHOT/version
/dependency测试 //Import(User.class)
//Import(UserConfig.class)
//EnableUser
ComponentScan(com.dong.springboot_enable_02.config)
SpringBootApplication
public class SpringbootEnable01Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootEnable01Application.class, args);Object user context.getBean(User.class);System.out.println(user);}
}因为enable_01导如了enable_02的坐标相当是把02的所有代码拷贝在与01的启动类同级目录下如果包名和包的层级都相同就可以直接装配User类但是包的层级不同就必须加注解 Import(User.class)对应第一个使用场景 导入02中的User类 Import(UserConfig.class)对应第二个使用场景 加载02中的UserConfig配置类加载配置类中所有的方法和类 EnableUser 自定义的注解包装了一个Import(User.class) ComponentScan(“com.dong.springboot_enable_02.config”) 扫描包加载类和配置类
导入配置类
见上方示例的Import(UserConfig.class)导入配置类加载配置类中所有的方法和类
导入ImportSelector 实现类
导入 ImportBeanDefinitionRegistrar 实现类
ImportSelector 和 ImportBeanDefinitionRegistrar 一起演示
代码实现
项目结构
springboot_enable_04 springboot项目pom文件不需要额外到坐标 POJO 实体类User public class User {
}Student public class Student {
}UserConfig配置类 Configuration
public class UserConfig {Beanpublic User user(){return new User();}
}MyImportSelector public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{com.dong.springboot_enable_04.pojo.User,com.dong.springboot_enable_04.pojo.Student};}
}MyImportBeanDefinitionRegistrar public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AbstractBeanDefinition beanDefinition BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();registry.registerBeanDefinition(user1,beanDefinition);}
}springboot_enable_03 springboot_enable_03pom文件导入springboot_enable_04坐标 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!--springboot_enable_04坐标--dependencygroupIdcom.dong/groupIdartifactIdspringboot_enable_04/artifactIdversion0.0.1-SNAPSHOT/version/dependency
/dependencies测试启动类 ComponentScan(com.dong.springboot_enable_04.config)
Import(User.class)
Import(UserConfig.class)
Import(MyImportSelector.class)
Import(MyImportBeanDefinitionRegistrar.class)
SpringBootApplication
public class SpringbootEnable03Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootEnable03Application.class, args);User user context.getBean(User.class);System.out.println(user);Student student context.getBean(Student.class);System.out.println(student);User user1 (User) context.getBean(user1);System.out.println(user1);}
}Import(MyImportSelector.class)对应第三个使用场景 MyImportSelector实现了ImportSelector接口重写了selectImports方法在字符出数组中的完全相对路径即注入了容器因为引入了enable_04所以03中可以获取到User和Student Import(MyImportBeanDefinitionRegistrar.class)对应第四个使用场景 MyImportBeanDefinitionRegistrar实现了ImportBeanDefinitionRegistrar接口registerBeanDefinitions方法在此方法中就可以对Bean进行注册如案例演示04注入了一个User对象id是user1所以03中就可以获取到User这个对象打印出地址
EnableAutoConfiguration注解 主启动类 //SpringBootApplication 来标注一个主程序类
//说明这是一个Spring Boot应用
SpringBootApplication
public class SpringbootApplication {public static void main(String[] args) {//以为是启动了一个方法没想到启动了一个服务SpringApplication.run(SpringbootApplication.class, args);}
}SpringBootApplication注解内部 SpringBootConfiguration
EnableAutoConfiguration
ComponentScan(excludeFilters {Filter(type FilterType.CUSTOM,classes {TypeExcludeFilter.class}
), Filter(type FilterType.CUSTOM,classes {AutoConfigurationExcludeFilter.class}
)}
)
public interface SpringBootApplication {
// ......
}ComponentScan 这个注解在Spring中很重要 ,它对应XML配置中的元素。 作用自动扫描并加载符合条件的组件或者bean 将这个bean定义加载到IOC容器中 SpringBootConfiguration 作用SpringBoot的配置类 标注在某个类上 表示这是一个SpringBoot的配置类 //SpringBootConfiguration注解内部
//这里的 Configuration说明这是一个配置类 配置类就是对应Spring的xml 配置文件
Configuration
public interface SpringBootConfiguration {}
//里面的 Component 这就说明启动类本身也是Spring中的一个组件而已负责启动应用
Component
public interface Configuration {}AutoConfigurationPackage 自动配置包 //AutoConfigurationPackage的子注解
//Registrar.class 作用将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器
Import({Registrar.class})
public interface AutoConfigurationPackage {
}EnableAutoConfiguration开启自动配置功能 以前我们需要自己配置的东西而现在SpringBoot可以自动帮我们配置 EnableAutoConfiguration告诉SpringBoot开启自动配置功能这样自动配置才能生效 Import({AutoConfigurationImportSelector.class})给容器导入组件 AutoConfigurationImportSelector 自动配置导入选择器给容器中导入一些组件
AutoConfigurationImportSelector.class↓selectImports方法↓
this.getAutoConfigurationEntry(annotationMetadata)方法↓
this.getCandidateConfigurations(annotationMetadata, attributes)方法↓
方法体ListString 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;↓
在所有包名叫做autoConfiguration的包下面都有META-INF/spring.factories文件总结原理 EnableAutoConfiguration 注解内部使用 Import(AutoConfigurationImportSelector.class) 来加载配置类。 配置文件位置META-INF/spring.factories该配置文件中定义了大量的配置类当 SpringBoot 应用启动时会自动加载这些配置类初始化Bean 并不是所有的Bean都会被初始化在配置类中使用Condition来加载满足条件的Bean
SpringBoot自动配置原理扒源代码图解 自定义启动类的实现
案例需求
自定义redis-starter要求当导入redis坐标时SpringBoot自动创建Jedis的Bean
参考
可以参考mybatis启动类的应用 实现步骤
创建redis-spring-boot-autoconfigure模块创建redis-spring-boot-starter模块,依赖redis-spring-boot-autoconfigure的模块在redis-spring-boot-autoconfigure模块中初始化Jedis的Bean并定义META-INF/spring.factories文件在测试模块中引入自定义的redis-starter依赖测试获取Jedis的Bean操作redis
代码实现演示
目录结构 redis-spring-boot-autoconfigure模块 pom文件 dependenciesdependencygroupIdredis.clients/groupIdartifactIdjedis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependency!--spring-boot-starter-test注释掉了--
/deendenciesRedisAutoConfiguration配置类 Configuration
EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {Beanpublic Jedis jedis(RedisProperties redisProperties){return new Jedis(redisProperties.getHost(),redisProperties.getPort());}
}动态获取主机号和端口号的类 ConfigurationProperties(prefix spring.redis)
//如果配置文件中有就读取配置文件中的spring.redis下面get、set方法就会对host和port达到动态效果如果配置文件中没有spring.redis就默认localhost和6379
public class RedisProperties {private String hostlocalhost;private int port6379;public String getHost() {return host;}public void setHost(String host) {this.host host;}public int getPort() {return port;}public void setPort(int port) {this.port port;}
}在resources目录下创建META-INF文件夹下创建spring.factories文件写入键值 org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.dong.redisspringbootautoconfigure.config.RedisAutoConfigurationredis-spring-boot-start模块 此模块只需要在pom文件中导入上个模块的gavtest文件夹和java下的目录都可以删除 dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependency!--引入自定义的redis-spring-boot-autoconfigure--dependencygroupIdcom.dong/groupIdartifactIdredis-spring-boot-autoconfigure/artifactIdversion0.0.1-SNAPSHOT/version/dependency
/dependencies测试模块springboot_enable_05 pom文件导入redis-spring-boot-start模块gav dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!--导入自定义启动类--dependencygroupIdcom.dong/groupIdartifactIdredis-spring-boot-start/artifactIdversion0.0.1-SNAPSHOT/version/dependency
/dependenciesyaml配置文件修改端口 spring:redis:port: 6060测试 SpringBootApplication
public class SpringbootEnable05Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootEnable05Application.class, args);Jedis bean context.getBean(Jedis.class);System.out.println(bean);}
}输出内容BinaryJedis{Connection{DefaultJedisSocketFactory{localhost:6060}}} 说明走了我们自定义的启动器 文章转载自: http://www.morning.pltbd.cn.gov.cn.pltbd.cn http://www.morning.yfffg.cn.gov.cn.yfffg.cn http://www.morning.drbwh.cn.gov.cn.drbwh.cn http://www.morning.jcrlx.cn.gov.cn.jcrlx.cn http://www.morning.gklxm.cn.gov.cn.gklxm.cn http://www.morning.hcwlq.cn.gov.cn.hcwlq.cn http://www.morning.srxhd.cn.gov.cn.srxhd.cn http://www.morning.gbfzy.cn.gov.cn.gbfzy.cn http://www.morning.ggmls.cn.gov.cn.ggmls.cn http://www.morning.dkzrs.cn.gov.cn.dkzrs.cn http://www.morning.mslsn.cn.gov.cn.mslsn.cn http://www.morning.pylpd.cn.gov.cn.pylpd.cn http://www.morning.c7512.cn.gov.cn.c7512.cn http://www.morning.wmhlz.cn.gov.cn.wmhlz.cn http://www.morning.tcxzn.cn.gov.cn.tcxzn.cn http://www.morning.xjtnp.cn.gov.cn.xjtnp.cn http://www.morning.xbbrh.cn.gov.cn.xbbrh.cn http://www.morning.xfncq.cn.gov.cn.xfncq.cn http://www.morning.fgrcd.cn.gov.cn.fgrcd.cn http://www.morning.rlbg.cn.gov.cn.rlbg.cn http://www.morning.lgqdl.cn.gov.cn.lgqdl.cn http://www.morning.kpxky.cn.gov.cn.kpxky.cn http://www.morning.kyfnh.cn.gov.cn.kyfnh.cn http://www.morning.bpmfz.cn.gov.cn.bpmfz.cn http://www.morning.pndhh.cn.gov.cn.pndhh.cn http://www.morning.iznek.com.gov.cn.iznek.com http://www.morning.lhgkr.cn.gov.cn.lhgkr.cn http://www.morning.kpqjr.cn.gov.cn.kpqjr.cn http://www.morning.cqwb25.cn.gov.cn.cqwb25.cn http://www.morning.frnjm.cn.gov.cn.frnjm.cn http://www.morning.c7629.cn.gov.cn.c7629.cn http://www.morning.mlpmf.cn.gov.cn.mlpmf.cn http://www.morning.pbzgj.cn.gov.cn.pbzgj.cn http://www.morning.rqxmz.cn.gov.cn.rqxmz.cn http://www.morning.ntkpc.cn.gov.cn.ntkpc.cn http://www.morning.nsrtvu.com.gov.cn.nsrtvu.com http://www.morning.txlxr.cn.gov.cn.txlxr.cn http://www.morning.tsyny.cn.gov.cn.tsyny.cn http://www.morning.gfrtg.com.gov.cn.gfrtg.com http://www.morning.qrpx.cn.gov.cn.qrpx.cn http://www.morning.tbrnl.cn.gov.cn.tbrnl.cn http://www.morning.rgwrl.cn.gov.cn.rgwrl.cn http://www.morning.dywgl.cn.gov.cn.dywgl.cn http://www.morning.mllmm.cn.gov.cn.mllmm.cn http://www.morning.ljpqy.cn.gov.cn.ljpqy.cn http://www.morning.mjkqj.cn.gov.cn.mjkqj.cn http://www.morning.wlsrd.cn.gov.cn.wlsrd.cn http://www.morning.kwnnx.cn.gov.cn.kwnnx.cn http://www.morning.qtsks.cn.gov.cn.qtsks.cn http://www.morning.glpxx.cn.gov.cn.glpxx.cn http://www.morning.ftzll.cn.gov.cn.ftzll.cn http://www.morning.lwrcg.cn.gov.cn.lwrcg.cn http://www.morning.rjmd.cn.gov.cn.rjmd.cn http://www.morning.ztmkg.cn.gov.cn.ztmkg.cn http://www.morning.ljzss.cn.gov.cn.ljzss.cn http://www.morning.fqyxb.cn.gov.cn.fqyxb.cn http://www.morning.wwwghs.com.gov.cn.wwwghs.com http://www.morning.wjlrw.cn.gov.cn.wjlrw.cn http://www.morning.zlff.cn.gov.cn.zlff.cn http://www.morning.hmtft.cn.gov.cn.hmtft.cn http://www.morning.ctqlq.cn.gov.cn.ctqlq.cn http://www.morning.nxbsq.cn.gov.cn.nxbsq.cn http://www.morning.rwjh.cn.gov.cn.rwjh.cn http://www.morning.gsjzs.cn.gov.cn.gsjzs.cn http://www.morning.nqrlz.cn.gov.cn.nqrlz.cn http://www.morning.ckzjl.cn.gov.cn.ckzjl.cn http://www.morning.wqfrd.cn.gov.cn.wqfrd.cn http://www.morning.mhrzd.cn.gov.cn.mhrzd.cn http://www.morning.gfrjs.cn.gov.cn.gfrjs.cn http://www.morning.tfpqd.cn.gov.cn.tfpqd.cn http://www.morning.hbnwr.cn.gov.cn.hbnwr.cn http://www.morning.ksgjn.cn.gov.cn.ksgjn.cn http://www.morning.jnkng.cn.gov.cn.jnkng.cn http://www.morning.rqqkc.cn.gov.cn.rqqkc.cn http://www.morning.mphfn.cn.gov.cn.mphfn.cn http://www.morning.hhskr.cn.gov.cn.hhskr.cn http://www.morning.qkqzm.cn.gov.cn.qkqzm.cn http://www.morning.nqlcj.cn.gov.cn.nqlcj.cn http://www.morning.ykwbx.cn.gov.cn.ykwbx.cn http://www.morning.sgrdp.cn.gov.cn.sgrdp.cn