SpringBoot自动装配之Condition深入讲解
作者:不死鸟.亚历山大.狼崽子 发布时间:2023-12-03 02:20:29
Condition是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean操作。
思考:
SpringBoot是如何知道要创建哪个Bean的?比如SpringBoot是如何知道要创建RedisTemplate的?
看一个例子:
当我们没导入redis-start时,会报错
引出问题
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'redisTemplate' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:874)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1358)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154)
at com.example.condition.SpringbootDemo01Application.main(SpringbootDemo01Application.java:13)
当导入redis起步依赖后
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
org.springframework.data.redis.core.RedisTemplate@5a6d5a8f
问题:
SpringBoot是怎么知道我们导入redis坐标的呢?
案例一
需求:
在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:
通过condition设置加载或者不加载。
新建实体类:
package com.example.condition.entity;
public class User {
}
新建配置文件:
package com.example.condition.config;
import com.example.condition.condition.ClassCondition;
import com.example.condition.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
public User user(){
return new User();
}
}
新建condition:
如果为true则加载,如果为false则不加载
package com.example.condition.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
测试:
package com.example.condition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootDemo01Application {
public static void main(String[] args) {
//启动SpringBoot应用,返回Spring的IOC容器
ConfigurableApplicationContext context = SpringApplication.run(SpringbootDemo01Application.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
案例二
需求:
在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:
导入Jedis坐标后,加载该Bean,没导入,则不加载。
新建User实体类:
package com.example.condition.entity;
public class User {
}
新建配置文件:
package com.example.condition.config;
import com.example.condition.condition.ClassCondition;
import com.example.condition.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
public User user(){
return new User();
}
}
condition通过反射判断jedis是否已经加载完毕
package com.example.condition.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ClassCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
boolean flag =true;
try {
Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
}catch (ClassNotFoundException e){
flag =false;
}
return flag;
}
}
测试类:
package com.example.condition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootDemo01Application {
public static void main(String[] args) {
//启动SpringBoot应用,返回Spring的IOC容器
ConfigurableApplicationContext context = SpringApplication.run(SpringbootDemo01Application.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
引入jedis进行测试判断:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
案例三
需求:
在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:
导入Jedis坐标后,加载该Bean,没导入,则不加载。
将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。
实体类:
package com.example.condition.entity;
public class User {
}
自定义注解:
package com.example.condition.condition;import org.springframework.context.annotation.Conditional;import java.lang.annotation.*;@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Conditional(ClassCondition.class)public @interface ConditionOnClass { String[] value();}
Condition类:
package com.example.condition.condition;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
String[] value();
}
配置类:
package com.example.condition.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 ClassCondition implements Condition {
/**
* @param context 上下文对象,用于获取环境,ClassLoader对象
* @param metadata 注解的元对象,可以用于注解定义的属性值
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
//1.需求:导入指定坐标后创建Bean
//思路:判断指定坐标文件是否存在
//获取注解属性值 value
Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
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;
}
}
测试类:
package com.example.condition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootDemo01Application {
public static void main(String[] args) {
//启动SpringBoot应用,返回Spring的IOC容器
ConfigurableApplicationContext context = SpringApplication.run(SpringbootDemo01Application.class, args);
Object user = context.getBean("user");
System.out.println(user);
}
}
ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean
来源:https://blog.csdn.net/u013938578/article/details/128680784


猜你喜欢
- 这篇文章主要介绍了Spring Cache手动清理Redis缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 本文实例讲述了C#实现翻转字符串的方法。分享给大家供大家参考。具体实现方法如下:Func<string, string> Rev
- API参数:/**fileName: 临时文件的名字, 生成后的文件名字将会是【fileName + 随机数】suffix: 文件后缀,例如
- 本实例将显示类似于windows7提供的图片预览窗格效果,单击任意一张图片,可以在右侧显示该图片的预览效果。效果如图所示:具体实现方法:re
- 前言本文给大家分享一个使用Android开发写字板功能Dem、简单操作内存中的图像、对图像进行简单的处理、绘制直线、以达到写字板的效果效果图
- 本文实例讲述了微信js sdk invalid signature签名错误问题的解决方法。分享给大家供大家参考,具体如下:/**最近在做微信
- 在Android中实现菜单功能有多种方法。 Options Menu:用户按下menu Button时显示的菜单。 Context Menu
- 实例引入在家庭影院中,有灯光,屏幕,投影机,功放机,DVD 播放器这几个基本的工具:灯光,可以关闭灯光和打开灯光。投影机,可以打开和关闭投影
- System.Web.Caching.Cache Insert和Add方法的区别Add()object Add(string key, ob
- 随着Flash应用的流行,网上出现了多种在线Flash版本“连连看”。如“水晶连连看”、“果蔬连连看”等,流行的“水晶连连看”以华丽界面吸引
- Android存储方式有很多种,在这里所用的存储方式是SharedPreferrences,其采用了Map数据结构来存储数据,以键值的方式存
- CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout
- 首先我们先看下效果图实现思路这是两张前后对比图,右边第二张图里面的已抢光标签图片当已经没有商品的时候就会显示了,在每个图片的中心位置,第一想
- 标识符Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符技巧:凡是自己可以起名字的地方都叫标识符定义合法标识符规则:由26个
- 讲解之前需要说明的是旋转屏幕:在系统的自动旋转屏幕开启的情况下,我们旋转屏幕手动设置屏幕:我们自己去调用Activity的 setReque
- 异常处理是每个项目中都绕不开的话题,那么如何优雅的处理异常,是本文的话题。本文将结合SpringBoot框架一起和大家探讨下。要思考的问题在
- 本文实例讲述了Android编程基于距离传感器控制手机屏幕熄灭的方法。分享给大家供大家参考,具体如下:在现实生活中,打电话的时候手机挨着自己
- 功能需求 最近项目中有这么一个功能,用户登录系
- 效果和代码都非常直观:实例1:TimePicker<RelativeLayout xmlns:android="http:/
- 1.更新同步方式:/** * 三个参数 * the path of the node