springboot学习之五(自动配置)

一、@Conditional源码

springboot的自动配置是通过@Conditional注解(条件判断)实现的.

@Conditional是Spring4版本新提供的一种注解,它的作用是按照设定的条件进行判断,把满足判断条件的bean注册到Spring容器。

package org.springframework.context.annotation;

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;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

@Conditional只有一个参数,并且这个参数要求是继承与Condition类,并且参数是个数组,也就是可以 传多个的。

Condition类是一个函数式接口(只有一个方法的接口被称为函数式接口)。matches方法就是比较方法,如果为true则注入,如果为false则不注入。

@FunctionalInterface
public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

 

二、@Conditional扩展注解

而除了@Conditional注解外,springboot通过@Conditional注解又扩展了很多注解出来,如下@ConditionalOnBean、@ConditionalOnClass等等…

 

三、@Conditional实战

需求:在spring的IOC容器中有一个User的Bean,先要求

1.导入Jedis坐标后,加载该Bean,没导入,则不加载。

2.将坐标类的判断设置成动态的,可以把Jedis随时当做参数替换成其他坐标。

 ------类似于ConditionalOnClass注解----

只要加了@Conditional注解,这个注解回传一个实现了Condition接口的实现类,这个类里面覆写一个matches方法返回值决定是否执行.

 步骤:

1.写一个自己的注解@Mycondition,加上@Conditional注解,

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention( RetentionPolicy.RUNTIME)
@Documented
@Conditional(MyAnnoCondition.class)
public @interface Mycondition {
    public String [] name() default "";
}
//这样有@Contitional的条件判断,也可以携带自己的属性name[]

2.加的@Conditional注解要实现Condition接口的实现类MyAnnoCondition 

public class MyAnnoCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //context:上下文对象,可以获取环境,IOC容器,classLoader对象
        //metadata:注解元对象,可以获取注解定义的属性值

        //1.获取注解属性值
        Map<String, Object> map = metadata.getAnnotationAttributes(Mycondition.class.getName());
        //System.out.println(map);
        String[] name = (String[]) map.get("name");
        boolean flag = true;

        for (String className : name){
            try {
                Class<?> cls = Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                flag = false;
            }
        }
        
        return flag;
    }
}

3.写一个User的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
}

4.把User实体类以注解配置@Configuration形式交由IOC容器管理

@Configuration
public class TestConfig {
    @Bean
    @Mycondition( name = "redis.clients.jedis.Jedis" )
    public User user(){
        System.out.println("User");
        return new User();
    }
}

5.现在就实验,pom.xml有无 jedis 坐标,来判断user是否被容器创建

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

springboot 启动main()方法

@SpringBootApplication
public class SpringbootRedisApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringbootRedisApplication.class, args);

        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
    }
}

 

 

 

创建或不创建User,取决于Jedis坐标是否导入.

 

 

 

 

转 :https://blog.csdn.net/weixin_43888891/article/details/127503336

https://blog.csdn.net/baidu_37107022/article/details/88878703/

 

 

https://www.cnblogs.com/kaituorensheng/p/8024199.html

 

posted @ 2023-04-19 16:02  与f  阅读(45)  评论(0编辑  收藏  举报