①. 自动配置
①. condition
1>. condition
①. 什么是Condition?
1.什么是condition?
- ①. condition是在Spring4.0增加的条件判断功能,通过这个功能可以实现选择性的创建Bean操作
- ②. 自定义条件
自定义条件:
(1).定义条件类:自定义实现Condition接口,重写matches方法,在matches方法中进行逻辑判断,返回boolean值。matches方法两个参数:
context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等
metadata:元数据对象,用于获取注解属性
(2).SpringBoot提供的常见条件注解:
ConditionalOnProperty:判断配置文件是否有对应属性和值才初始化Bean
ConditionalOnClass:判断坏境中是否有对应字节码文件才初始化Bean
ConditionalOnMissingBean:判断坏境中没有对应Bean才初始化Bean
上面这些可以在如下找到:
②. 案例1
2. 案例1
- ①. 需求:在Spring的IOC容器中有一个User的Bean,现要求:
导入Jedis坐标后,加载该Bean,没导入,则不加载
- ②. 具体代码实现:
@Configuration public class UserConfig { @Bean @Conditional(UserCondition.class) public User getUser(){ return new User(); } }
package com.itheima.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class UserCondition implements Condition { /* * matches()方法 * 如果返回值是true,那么会创建相对应的对象 * 如果方法返回值是false,那么则不会创建相对应的对象 * 1.conditionContext:上下文对象。用于获取坏境,IOC容器,ClassLoader对象 * 2.annotatedTypeMetadata:注解的元对象。可以用于获取注解定义的属性值 * */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { /* * 需求: 1.导入Jedis坐标后创建bean * 思路: 判断redis.clients.jedis.Jedis;文件是否存在 * */ /* Environment environment = conditionContext.getEnvironment(); environment.getProperty(); * */ boolean flag=true; try { Class<?> cls = Class.forName("redis.clients.jedis.Jedis"); } catch (ClassNotFoundException e) { flag=false; } return flag; } }
③. 案例2
3. 案例2
- ①. 需求:在Spring的IOC容器中有一个User的Bean,现要求:
将类的判断定义为动态的判断哪个字节码文件可以动态指定(ConditionOnClass)
- ②. 代码演示:
@Configuration public class UserConfig { @Bean //@Conditional(UserCondition.class) @ConditionOnClass("redis.clients.jedis.Jedis") public User getUser(){ return new User(); } }
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(UserCondition.class) public @interface ConditionOnClass { String[]value(); }
public class UserCondition implements Condition { /* * matches()方法 * 如果返回值是true,那么会创建相对应的对象 * 如果方法返回值是false,那么则不会创建相对应的对象 * 1.conditionContext:上下文对象。用于获取坏境,IOC容器,ClassLoader对象 * 2.annotatedTypeMetadata:注解的元对象。可以用于获取注解定义的属性值 * */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { /* * 需求: 1.导入Jedis坐标后创建bean * 思路: 判断redis.clients.jedis.Jedis;文件是否存在 * */ /* Environment environment = conditionContext.getEnvironment(); environment.getProperty(); * */ /* boolean flag=true; try { Class<?> cls = Class.forName("redis.clients.jedis.Jedis"); } catch (ClassNotFoundException e) { flag=false; } return flag;*/ //2.需求:导入通过注解属性值value指定坐标后创建Bean //获取注解属性值 value Map<String, Object> map = annotatedTypeMetadata.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; } }
②. 监听机制
2>.监听机制(了解)
- SpringBoot的web坏境中默认使用tomcat作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可以很方便的进行切换。
- spring-boot-autoConfigure–》web–》embedded
- ③. 代码演示如下(如要切换jetty):
<dependencies> <!--移除tomcat的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <artifactId>spring-boot-starter-tomcat</artifactId> <groupId>org.springframework.boot</groupId> </exclusion> </exclusions> </dependency> <!--引入jetty的依赖--> <dependency> <artifactId>spring-boot-starter-jetty</artifactId> <groupId>org.springframework.boot</groupId> </dependency> </dependencies>
③. @Enable * 注解原理
3>. @Enable * 注解原理
①. 问题的提出:SpringBoot工程是否可以直接获取jar包中定义的Bean?
不能,ComponentScan只能扫描引导类所在包及子包
②. 解决方案:
(1).使用@ComponentScan进行包扫描
(2).@Import注解,加载类,这些类都会被Spring创建,并放入IOC容器
(3).可以对@Import进行封装,这样就可以不需要知道@Import()里面填写什么东西
④. @Import
4>. @Import
①. 导入Bean
②. 导入配置类
③. 导入ImportSelector实现类,一般用于加载配置文件中的类
//这是工程和User类是同一个工程,@Import 则是另一个工程 public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { //这里的 "com.itheima.domain.User" 是全限类名 return new String[]{"com.itheima.domain.User"}; } }
@SpringBootApplication //@Import(User.class) @Import(MyImportSelector.class) public class SpringbootApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args); User user= context.getBean(User.class); /*Map<String, User> map = context.getBeansOfType(User.class); System.out.println(map);*/ System.out.println(user); } }
- ④. 导入ImportBeanDefinitionRegistrar 的实现类(了解)
⑤. @EnableAutoConfiguration
5>. @EnableAutoConfiguration 掌握
①. EnableAutoConfiguration 中的@Import 在SpringBoot中流程分析:
- ②. @EnableAutoConfiguration注解内部使用@Import({AutoConfigurationImportSelector.class})来加载配置类
- ③. 配置文件位置:META-INF/spring.factories,该配置文件中定义了大量的配置类,当SpringBoot应用启动时,会自动加载这些配置类,初始化Bean
- ④. 并不是所有的Bean都会被初始化,在配置类中使用Condition来加载满足条件的Bean