这两天再看 公司 之前写的组件的代码,不看不知道,一看吓一跳。。。。这里就说其中一个

不知道你在写组件中的 @Bean 加载的时分 怎么写?

预祝大家 元旦高兴,新年高兴

办法一

直接META-INF/spring.factories 写

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.ForeignProxyServiceImpl

办法二

定义一个 config类,然后

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.ForeignSdkValidateConfig

然后 config中写

@Bean
@ConditionalOnMissingBean
public ForeignCallbackImpl foreignCallbackImpl() {
    return new ForeignCallbackImpl();
}

小总结

上面2个 哪个更好,肯定是办法二

办法一 对之后的扩展不友好,因为 可能之后有需求,根据type 或许 enable 来决议敞开哪几个类,这个时分就会发现 结构不明晰,欠好拆分

办法二 能够 对config类 进行控制,结构上也愈加明晰

到这 你看看上面的写法还有问题么

没错 就上面这短短几行代码还有问题

什么? @ConditionalOnMissingBean 你没设置value?

问题出在

返回值应该是 接口 ,不能是 完成类

@Bean
@ConditionalOnMissingBean
//返回值应该是 接口 ,不能是 完成类
public ForeignCallbackImpl foreignCallbackImpl() {
    return new ForeignCallbackImpl();
}

问题

@ConditionalOnMissingBean 和 @ConditionalOnMissingBean(xxx.class) 有差异么?

这就需要知道 @ConditionalOnMissingBean 如果不填的时分 默许值是怎么取的

其中最终的代码在

private void addDeducedBeanTypeForBeanMethod(ConditionContext context, MethodMetadata metadata, final List<String> beanTypes) {
    try {
        Class<?> returnType  = this.getReturnType(context, metadata);
        //returnType 获取的是 办法的返回值的类型
        beanTypes.add(returnType.getName());
    } catch (Throwable var5) {
        throw new BeanTypeDeductionException(metadata.getDeclaringClassName(), metadata.getMethodName(), var5);
    }
}

例子

@Component
@Slf4j
public class ForeignSdkValidateConfig  {
    @Bean
    @ConditionalOnMissingBean
    public AImpl foreignCallbackController() {
        return new AImpl();
    }
}
public interface AIn {
}
public class AImpl implements AIn {
}

什么? @ConditionalOnMissingBean 你没设置value?

这就相当于@ConditionalOnMissingBean(AImpl.class)

可是咱们要的是 @ConditionalOnMissingBean(AIn.class)

这样才能让 AIn 只要一个完成的bean

一句话 能够使用 @ConditionalOnMissingBean 无参数 ,可是一定要返回 接口,不能是 完成类

其实这个 一般不会犯错,和技术无关, 便是细节上的事

问一个额外的问题

@ConditionalOnMissingBean(AIn.class)

AIn.class 赋值在哪个特点上了

答案是 会赋值在 value 特点上

什么? @ConditionalOnMissingBean 你没设置value?

不赋值的时分 会主动获取 返回值的class 放到value中

详细材料 能够看 docs.oracle.com/javase/tuto…

If there is just one element named`value`, then the name can be omitted, as in:

大约意思是 会赋值在 value上,那是不是能够理解为 只要@interface 注解中有value ,默许就能够不指定 value元素了

例子

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestBean {
}

什么? @ConditionalOnMissingBean 你没设置value?

你认为到这 就完毕了?

什么? @ConditionalOnMissingBean 你没设置value?

到这 会想到 不设置特点会去找 value 是怎么写的,咱们能够自定义么?

首先咱们要先确定 归于编译期间做的事 仍是 解析的时分 做的事

这就触及 java的编译

大约流程如下

什么? @ConditionalOnMissingBean 你没设置value?

简单的办法便是看class 文件,下面是 class文件的内容,发现仍是没有 value=

什么? @ConditionalOnMissingBean 你没设置value?

能够确定是 java 代码执行的时分 带的处理

什么? @ConditionalOnMissingBean 你没设置value?

其实这部分的解析 便是spring 对注解的解析

咱们能够先看咱们平时怎么获取 class中的注解的

实际代码

Field[] fields = new ForeignSdkValidateConfig().getClass().getDeclaredFields();
Annotation annotation = AnnotationUtils.getAnnotation(fields[0], TestBean.class);

真实的解析代码

declAnnos = AnnotationParser.parseAnnotations(
        annotations,
        sun.misc.SharedSecrets.getJavaLangAccess()
                .getConstantPool(getDeclaringClass()),
        getDeclaringClass());
public static Object parseMemberValue(Class<?> memberType,
                                      ByteBuffer buf,
                                      ConstantPool constPool,
                                      Class<?> container) {
    Object result = null;
    int tag = buf.get();
    switch(tag) {
      case 'e':
          return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
      case 'c':
          result = parseClassValue(buf, constPool, container);
          break;
      case '@':
          result = parseAnnotation(buf, constPool, container, true);
          break;
      case '[':
          return parseArray(memberType, buf, constPool, container);
      default:
          result = parseConst(tag, buf, constPool);
    }
    if (!(result instanceof ExceptionProxy) &&
        !memberType.isInstance(result))
        result = new AnnotationTypeMismatchExceptionProxy(
            result.getClass() + "[" + result + "]");
    return result;
}

默许是value是下面这块,底层调用的native 办法

//和 16个1 进行& 操作,取前16位
int memberNameIndex = buf.getShort() & 0xFFFF;
String memberName = constPool.getUTF8At(memberNameIndex);
public String   getUTF8At          (int index) { return getUTF8At0          (constantPoolOop, index); }
private native String   getUTF8At0          (Object constantPoolOop, int index);
private static Object parseClassValue(ByteBuffer buf,
                                      ConstantPool constPool,
                                      Class<?> container) {
    int classIndex = buf.getShort() & 0xFFFF;
    try {
        try {
            String sig = constPool.getUTF8At(classIndex);
            return parseSig(sig, container);
        } catch (IllegalArgumentException ex) {
            // support obsolete early jsr175 format class files
            return constPool.getClassAt(classIndex);
        }
    } catch (NoClassDefFoundError e) {
        return new TypeNotPresentExceptionProxy("[unknown]", e);
    }
    catch (TypeNotPresentException e) {
        return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
    }
}

什么? @ConditionalOnMissingBean 你没设置value?

value 这个特点的默许值 是写在class 类中的

什么? 你问 @Bean 还有什么常用注解?

@Conditional 满意指定的条件,则进行组件注入,如果不满意,则不注入。

@ConditionalOnBean:表明当容器中存在某个组件才进行组件注入

@ConditionalOnMissingBean:表明当容器中没有某个组件才进行组件注入

思考

Java 的 JIT 编译器和 JavaScript 的 V8 编译器,它们都不谋而合地采用了“Sea of Nodes”的 IR 来做优化,这是为什么呢?这种 IR 有什么优势呢?

彩蛋

这几天看着大哥们 再投的 <人气创作者>的投票,我已经摆烂了,给个 阳光普照就好

什么? @ConditionalOnMissingBean 你没设置value?