江西省建设监督网站,php做的网站怎么运行,微分销平台登录,抓取资源的网站怎么做一、Condition Condition 是在 Spring 4.0 增加的条件判断功能#xff0c;通过这个可以功能可以实现选择性的创建 Bean 操 作。 思考#xff1a; SpringBoot 是如何知道要创建哪个 Bean 的#xff1f;比如 SpringBoot 是如何知道要创建 RedisTemplate 的#xff1f; …
一、Condition Condition 是在 Spring 4.0 增加的条件判断功能通过这个可以功能可以实现选择性的创建 Bean 操 作。 思考 SpringBoot 是如何知道要创建哪个 Bean 的比如 SpringBoot 是如何知道要创建 RedisTemplate 的 测试的项目结构 导入坐标 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdredis.clients/groupIdartifactIdjedis/artifactId/dependency ClassCondition.java /*** author zkt* Version 1.0* since 2024/7/24*/
public class ClassCondition implements Condition {/**** param context 上下文对象。用于获取环境IOC容器ClassLoader对象* param metadata 注解元对象。 可以用于获取注解定义的属性值* return*/Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {//1.需求 导入Jedis坐标后创建Bean//思路判断redis.clients.jedis.Jedis.class文件是否存在boolean flag true;try {Class? cls Class.forName(redis.clients.jedis.Jedis);} catch (ClassNotFoundException e) {flag false;}return flag;}
}UserConfig.java /*** author zkt* Version 1.0* since 2024/7/24*/
Configuration
public class UserConfig {//Conditional中的ClassCondition.class的matches方法返回true执行以下代码否则反之BeanConditional(value ClassCondition.class)public User user(){return new User();}
} User.java /*** author zkt* Version 1.0* since 2024/7/24*/
public class User {
} SpringbootConditionApplication.java SpringBootApplication
public class SpringbootCondition01Application {public static void main(String[] args) {//启动SpringBoot的应用返回Spring的IOC容器ConfigurableApplicationContext context SpringApplication.run(SpringbootCondition01Application.class, args);//获取BeanredisTemplate//情况1 没有添加坐标前发现为空//情况2 有添加坐标前发现有对象Object redisTemplate context.getBean(redisTemplate);System.out.println(redisTemplate);/********************案例1********************/Object user context.getBean(user);System.out.println(user);}}测试结果 情况1 没有添加坐标前发现为空 情况2 有添加坐标前发现有对象 案例需求1 在 Spring 的 IOC 容器中有一个 User 的 Bean 现要求 1. 导入 Jedis 坐标后加载该 Bean 没导入则不加载。 案例需求2 在 Spring 的 IOC 容器中有一个 User 的 Bean 现要求 将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定 实现步骤 不使用Conditional(ClassCondition.class)注解 自定义注解ConditionOnClass,因为他和之前Conditional注解功能一直所以直接复制 编写ClassCondition中的matches方法 测试的项目结构 导入坐标 dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-data-redis/artifactId
/dependency
dependency
groupIdredis.clients/groupId
artifactIdjedis/artifactId
/dependency
!-- dependency --
!-- groupIdcom.alibaba/groupId --
!-- artifactIdfastjson/artifactId --
!-- version1.2.62/version --
!-- /dependency -- 在原有的基础上 新建一个自定义注解 Target({ElementType.TYPE, ElementType.METHOD})//可以修饰在类与方法上
Retention(RetentionPolicy.RUNTIME)//注解生效节点runtime
Documented//生成文档
Conditional(valueClassCondition.class)
public interface ConditionOnClass {String[] value();//设置此注解的属性redis.clients.jedis.Jedis
} 修改ClassCondition .java public class ClassCondition implements Condition {/**** param context 上下文对象。用于获取环境IOC容器ClassLoader对象* param metadata 注解元对象。 可以用于获取注解定义的属性值* return*/Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {//1.需求 导入Jedis坐标后创建Bean//思路判断redis.clients.jedis.Jedis.class文件是否存在
// boolean flag true;
// try {
// Class? cls Class.forName(redis.clients.jedis.Jedis);
// } catch (ClassNotFoundException e) {
// flag false;
// }
// return flag;//2.需求 导入通过注解属性值value指定坐标后创建Bean//获取注解属性值 valueMapString, Object map metadata.getAnnotationAttributes(ConditionOnClass.class.getName());System.out.println(map);String[] value (String[]) map.get(value);boolean flag true;try {for (String className : value) {Class? cls Class.forName(className);}} catch (ClassNotFoundException e) {flag false;}return flag;}
}测试 情况1 情况2 小结 自定义条件 ① 定义条件类自定义类实现Condition接口重写 matches 方法在 matches 方法中进行逻辑判 断返回 boolean值 。 matches 方法两个参数 context上下文对象可以获取属性值获取类加载器获取BeanFactory等。 metadata元数据对象用于获取注解属性。 ② 判断条件 在初始化Bean时使用 Conditional(条件类.class)注解 SpringBoot 提供的常用条件注解 注解名描述ConditionalOnProperty判断配置文件中是否有对应属性和值才初始化BeanConditionalOnClass判断环境中是否有对应字节码文件才初始化BeanConditionalOnMissingBean 判断环境中没有对应Bean才初始化Bean ConditionalOnBean 判断环境中有对应Bean才初始化Bean 可以查看RedisAutoConfiguration类说明以上注解使用 具体演示 ConditionalOnProperty 二、Enable注解 SpringBoot中提供了很多Enable开头的注解这些注解都是用于动态启用某些功能的。而其底层原理 是使用Import注 解导入一些配置类实现Bean的动态加载 测试 测试的项目结构 其中 springboot-enable-other用于模拟其他jar包先在其放到enable项目内部类似于给项目导入jar包然后在到外面的SpringBoot项目里获取里面项目的Bean测试看看能否获取到。 将04 的坐标导入进去 导入坐标 !-- 导入坐标 --dependencygroupIdcom.zkt/groupIdartifactIdspringboot-enable_other-04/artifactIdversion0.0.1-SNAPSHOT/version/dependency EnableUser.java Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Documented
Import(UserConfig.class)
public interface EnableUser {
}UserConfig /*** author zkt* Version 1.0* since 2024/7/24*/
Configurationpublic class UserConfig {Beanpublic User user() {return new User();}
} user /*** author zkt* Version 1.0* since 2024/7/24*/
public class User {
} SpringBootApplication
//ComponentScan(com.zkt.config)
//Import(User.class)//导入javaBean
//Import(UserConfig.class)
EnableUser
//EnableScheduling
//EnableAsync
public class SpringbootEnable03Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootEnable03Application.class, args);/*** SpringBootApplication中有ComponentScan注解 扫描范围当前引导类所在包及其子包* 当前引导类所在包com.apesource.springbootenable03* 注入user类所在包com.apesource.springbootenable_other04.config* 因此扫描不到所以容器中没有user* 解决方案* 1.使用ComponentScan扫描com.apesource.springbootenable_other04.config包* 2.可以使用Import注解加载类。这些类都会被Spring创建并放入IOC容器* 3.可以对Import注解进行封装。**///获取BeanUser user context.getBean(User.class);System.out.println(user);}} 测试 都不导入 ComponentScan扫描 导入Bean 导入配置类 可以对Import注解进行封装 三、Import注解 Enable底层依赖于Import注解导入一些类使用Import导入的类会被Spring加载到IOC容器中。 而Import 提供 4 中用法 ① 导入Bean ② 导入配置类 ③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类 ④ 导入 ImportBeanDefinitionRegistrar 实现类。 测试 测试的项目结构 EnableUser.java Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Import(UserConfig.class)
public interface EnableUser {
} MyImportBeanDefinationRegister.java public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//AnnotationMetadata注解//BeanDefinitionRegistry向spring容器中注入//1.获取user的definition对象AbstractBeanDefinition beanDefinition BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();//2.通过beanDefinition属性信息,向spring容器中注册id为user的对象registry.registerBeanDefinition(user, beanDefinition);}
}MyImportSelector.java public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {//目前字符串数组的内容是写死的未来可以设置在配置文件中动态加载return new String[]{com.zkt.domain.User, com.zkt.domain.Student};}
} public class Student {
} SpringBootApplication
//Import(User.class)
//Import(UserConfig.class)
//Import(MyImportSelector.class)
//Import({MyImportBeanDefinitionRegistrar.class})
//EnableAsync
//EnableScheduling
public class SpringbootEnable03Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootEnable03Application.class, args);/*** Import4中用法* 1. 导入Bean* 2. 导入配置类* 3. 导入ImportSelector的实现类* 查看ImportSelector接口源码* String[] selectImports(AnnotationMetadata importingClassMetadata);* 代表将“字符串数组”中的的类全部导入spring容器* 4. 导入ImportBeanDefinitionRegistrar实现类**/
// User user context.getBean(User.class);
// System.out.println(user);
//
// Student student context.getBean(Student.class);
// System.out.println(student);User user (User) context.getBean(user);System.out.println(user);}}其余同上 测试结果 什么都不导入 ① 导入Bean ② 导入配置类 ③ 导入 ImportSelector 实现类。一般用于加载配置文件中的类 ④ 导入 ImportBeanDefinitionRegistrar 实现类。 SpringBoot启动类注解 SpringBootApplication 是通过上面来实现导入其他类的步骤依次为 SpringBootApplication EnableAutoConfiguration Import(AutoConfigurationImportSelector.class) interface DeferredImportSelector extends ImportSelector 四、EnableAutoConfiguration 注解 EnableAutoConfiguration 注解内部使用import(AutoConfigurationImportSelector.class) 来加载配置类配置文件位置META-INF/spring.factories, 改配置文件中定义了大量的配置类当SpringBoot应用启动时会自动加载这些配置类初始化Bean 一层一层地查找源码 主启动类 //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文件 通过源码的提示可以看到自动加载类的配置文件在 META-INF/spring.factories的位置现在找到org.springframework.boot.autoconfigure中的spring-boot-autoconfigure-2.5.6.jar 可以找到存在 META-INF文件夹而里面就有一个 spring.factories的文件 如下图spring.factories部分内容如下 可以发现它包含了Redis类从而就加载到了容器中这就是为什么SpringBoot可以直接获取到redisTemplate的原因 总结原理 EnableAutoConfiguration 注解内部使用 Import(AutoConfigurationImportSelector. class ) 来加载配置类。 配置文件位置 META-INF/spring.factories 该配置文件中定义了大量的配置类当 SpringBoot 应用启动时会自动加载这些配置类初始化 Bean 并不是所有的 Bean 都会被初始化在配置类中使用 Condition 来加载满足条件的 Bean 五、自定义启动器 需求 自定义 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并定义METAINF/spring.factories文件 在测试模块中引入自定义的redis-starter依赖测试获取Jedis的Bean操作redis。 导入坐标 在 redis-spring-boot-configuration模块中负责配置 jedis 模拟 Redis的自动配置注该模块的test类需删除否则会报错 在负责起步依赖的redis-spring-boot-starter模块中只负责在pom.xml里添加confguration模块的依赖注该模块的test类需删除否则会报错 项目结构 RedisProperties.java 用于Redis连接的配置实体类将作为Bean注入到Spring 容器中 ConfigurationProperties(prefixredis)
public class RedisProperties {private String host localhost;private int port 6379;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;}
} RedisAutoConfiguration.java 根据之前注入的redisProperties配置Bean来创建一个Jedis Bean 并注入到容器中 Configuration
EnableConfigurationProperties(RedisProperties.class)
ConditionalOnClass(Jedis.class)
public class RedisAutoConfiguration {BeanConditionalOnMissingBean(name jedis)public Jedis jedis(RedisProperties redisProperties){System.out.println(RedisAutoConfiguration...);return new Jedis(redisProperties.getHost(), redisProperties.getPort());}
} 根据之前的源码查找在声明自动配置类后需要在resources/META-INF下创建一个spring.factories配置文件用于声明实现了自动扫描的配置类 org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.zkt.RedisAutoconfiguration至此已完成了模拟Redis自动配置的模块现在到另一个SpringBoot模块中引入实现的redis-spring-boot-starter起步依赖 SpringBootApplication
public class SpringbootStarter04Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(SpringbootStarter04Application.class, args);Jedis bean1 context.getBean(Jedis.class);System.out.println(bean1);}} 成功 六、自动装配原理 自动装配是什么及作用 springboot的自动装配实际上就是为了从spring.factories文件中获取到对应的需要进行自动装配的类并生成相应的Bean对象然后将它们交给spring容器来帮我们进行管理 1. 启动类上注解的作用 SpringBootApplication 这个注解是springboot启动类上的一个注解是一个组合注解也就是由其他注解组合起来它的主要作用就是标记说明这个类是springboot的主配置类springboot应该运行这个类里面的main()方法来启动程序 这个注解主要由三个子注解组成 SpringBootConfigurationEnableAutoConfigurationComponentScan 七、 总结 SpringBoot自动装配 核心注解SpringBootApplication 是一个复合注解 SpringBootApplication EnableAutoConfiguration Configuration ComponentScan EnableAutoConfiguration启动 SpringBoot 的自动配置机制Configuration允许上下文注册额外的bean或者导入其它配置类ComponentScan扫描 ComponentService、Controller注解的bean默认会扫描启动类所在的包下的所有类可以自定义不扫描某些类 EnableAutoConfiguration 导入了 AutoConfigurationImportSelector 类这个类负责从 META-INF /spring.factories 文件中加载并过滤自动配置类根据条件注解Conditional 来过滤这些自动配置类. 只有当条件满足时对应的自动配置类才会被加载 3.