目录
背景
springboot为我们提供了大量的开箱即用的插件与功能,我们也时常对一些常用功能进行封装,按照springboot的方式提供插件或以其他方式制造我们自己的轮子供自己或团队使用。通常限于我们的设计思路或者在某些方面的取舍,总是不能面面俱到,不能很好的支持一些小众的业务场景,就可以利用spring提供的条件化bean构建机制让我们的插件有很好的自定义扩展能力,能被更多的场景以很小的代价进行应用,从而发挥最大的价值。
思路
把我们的固定逻辑以接口的方式进行定义,当然,也可以用抽象类,但是更推荐使用接口,因为接口可以更加灵活的组合和扩展。然后在我们的核心逻辑中利用多态以接口的方式引入依赖,并执行相应逻辑,可以提供一个针对通用场景的实现作为默认,这样就能使我们的插件能以零代码的方式开箱即用,当需要自定义实现时,则自动关闭默认实现,使用自定义的逻辑。
示例代码
基本操作
核心功能组件接口
package example.component;
public interface ExampleComponent {
void whoAmI();
}
组件的使用者
package example.component;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Demo implements InitializingBean {
@Autowired
private ExampleComponent exampleComponent;
@Override
public void afterPropertiesSet() throws Exception {
exampleComponent.whoAmI();
}
}
提供一个默认的实现
package example.component;
import org.springframework.stereotype.Component;
@Component
public class DefaultExampleComponent implements ExampleComponent {
@Override
public void whoAmI() {
System.out.println("I'm default.");
}
}
运行结果
正常输出I'm default.,这个应该没问题好质疑的
添加ConditionalOnMissingBean注解
package example.component;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;
@Component
@ConditionalOnMissingBean(value = { ExampleComponent.class })
public class DefaultExampleComponent implements ExampleComponent {
@Override
public void whoAmI() {
System.out.println("I'm default.");
}
}
再次运行,还能正常吗?
***************************
APPLICATION FAILED TO START
***************************
Description:
Field exampleComponent in example.component.Demo required a bean of type 'example.component.ExampleComponent' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'example.component.ExampleComponent' in your configuration.
把日志级别调到debug,看看到底发生了什么
DefaultExampleComponent:
Did not match:
- @ConditionalOnMissingBean (types: example.component.ExampleComponent; SearchStrategy: all) found beans of type 'example.component.ExampleComponent' defaultExampleComponent (OnBeanCondition)
默认实现也被识别为了该接口的实现,所以不满足条件,没有被创建
添加忽略,忽略自己
package example.component;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;
@Component
@ConditionalOnMissingBean(value = { ExampleComponent.class }, ignored = { DefaultExampleComponent.class })
public class DefaultExampleComponent implements ExampleComponent {
@Override
public void whoAmI() {
System.out.println("I'm default.");
}
}
再次运行
DefaultExampleComponent matched:
- @ConditionalOnMissingBean (types: example.component.ExampleComponent ignored: example.component.DefaultExampleComponent; SearchStrategy: all) did not find any beans (OnBeanCondition)
满足条件了,这个bean被创建了
添加自定义实现,看看扩展效果
package example.component;
import org.springframework.stereotype.Component;
@Component
public class AnotherExampleComponent implements ExampleComponent {
@Override
public void whoAmI() {
System.out.println("I'm another.");
}
}
运行
已经存在一个实现,默认实现不满足条件,没有被创建,使用了自定义的AnotherExampleComponent
DefaultExampleComponent:
Did not match:
- @ConditionalOnMissingBean (types: example.component.ExampleComponent ignored: example.component.DefaultExampleComponent; SearchStrategy: all) found beans of type 'example.component.ExampleComponent' anotherExampleComponent (OnBeanCondition)