spring原理之@Conditional与@Configuration

你有没有一种需求,就是当某个外部条件成立的时候,就让spring创建bean,并让它管理,一定有的对吧,那么你一定要了解spring的@Conditional这个注解。你有时候有没有觉得@Configuration与@Component都可以把一个类让spring创建并管理,那么它们到底有什么区别呢。今天我就来和你聊聊这两个话题。

     你一定在一些与spring整合的框架源码上,看到大量的@Conditional的注解,这个注解有个Class类型的数组属性,当你在这个注解上加上某个类的时候,其实意思就是你加的这个类必须实现Condition这个接口,这个接口上有个matchs方法,当方法的值返回为true的时候,则这个被标注Condition注解的类,才会正常解析并且变成beanDefinition对象。如果返回为false则直接退出当前类的解析,就不会被spring创建并管理。我们通过查找代码路径ConfigurationClassPostProcessor ->processConfigBeanDefinitions()->parser.parse(candidates) 来看下具体源码我们可以看如下截图:

952b12d3eafbd17310a65b102cd83a71.png 

仔细看红线的地方,第一个地方判断有没有Conditional注解,第二地方是调用mactchs方法,如果macths返回true,最终结果是false,则外面的if就不会走,也就不会走return,反之则会走。所以看到这个地方是不是很神奇,接着我们再看看看一个例子,就是根据外部的一个属性决定是否创建bean并被spring管理:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(value = {PropertityOnClass.class})
public @interface PropertityAnnotation {

    Class[] value() default {};
    String[] name() default {};
}
@Component@PropertityAnnotation(name = "com.hrao")
public class PropertityBean {

}
public class PropertityOnClass implements Condition {
    @Override    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        if (metadata.isAnnotated(PropertityAnnotation.class.getName())) {
            AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(PropertityAnnotation.class.getName(), false));            String[] names = annotationAttributes.getStringArray("name");            try {
                Properties properties = PropertiesLoaderUtils.loadAllProperties("application.properties", ClassUtils.getDefaultClassLoader());                for (String name : names) {
                    if (properties.getProperty(name).equals("true")) {
                        return true;                    }
                }
            } catch (IOException e) {
                return false;            }
        }
        return false;    }

}

PropertityAnnotation这注解上有Conditional注解,注解的注解,你可以理解成继承的关系把。我们可以看到,可以根据配置文件的的com.hrao这个属性决定释放创建bean。好了关于@Condition 这个注解我就讲到这里了,接下来我们再看看 以上代码有个地方要说明下,就是注解的注解,在注解上加上注解与其在一个注解中的作用是一样的。你可以理解成继承的关系把。我们可以看到,可以根据配置文件的的com.hrao这个属性决定释放创建bean。接下来我们就来聊聊@Configuration这个注解的作用。                                 

     关于@Configuration这注解我就先入为主的给大家灌输一个概念,那就是代理,只要是被这个注解标注的类,spring会为这个类生成一个增强的.class文件,当对这个类的有@bean注解的方法进行调用的时候,实际上是对这个增强的.class类进行调用,就是代理。我们知道,jdk原生的动态代理,只能对实现了接口的类进行代理,不能对未实现接口的类进行代理,所以spring使用了cglib动态代理方式,这种方式可以对未实现接口的类进行代理增强。有了这个概念以后,我们通过代码路径先来到以下代码:                   ConfigurationClassPostProcessor->postProcessBeanFactory()这个方法:                   

 

我们看到上面的截图有标记,我来解释下这些标记的意思

1 找到这个类上的configurationClass类注解(@configuration),如果有将这个beanDefinition放入到几乎中

2 如果集合为空,则直接退出,表示没有任何被@configuration标注的类

3 这个地方是核心,创建一个cglib的代理的.class类,具体的你可以看下这个方法的里面怎么创建代理,这cglib创建代理类的标准api是一样的没有什么特别之处

4 将原先的beanDefinition的beanClass属性设置为cglib创建的.class类的属性,以后创建实例的时候,其实是创建这个代理的实例。

  看了上面的截图,是不是感觉很简单啊。其实一般类里面@configuration标有这个注解的和方法上有@bean注解配合使用的比较多,也就是说通过代理执行的方法创建对象,是放到缓存里面的,无论你调用多少次,都是获得缓存的里面的bean,都是一个bean,还有就是@bean的创建方式,和我们之前在xml里面的factoryBean和factoryMethod的创建方式是一样的,其实就是@bean使用了现有的xml的factoryBean和factoryMethod方式创建的,只是之前使用的是xml现在使用的是注解,后台的方法是一模一样的,变得只是入口存在的形式而已。

    好了关于今天的这两个话题,我已经讲完了,期待后面的分享,谢谢观看。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值