可能标题不准确,描述一下问题:
有这么一个接口:
public interface InterceptorPredicate {
default boolean allowed(HttpServletRequest request) {
return true;
}
}
然后有个拦截器:
public class MyInterceptor implements HandlerInterceptor {
private InterceptorPredicate predicate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (predicate.allowed(request)) {
do something...
}
return true;
}
public MyInterceptor(InterceptorPredicate predicate) {
this.predicate = predicate;
}
}
我要怎么样做到说如果外部有实现了InterceptorPredicate
的bean,那么就用外部的,否则用默认的实现类?
就像DataSource
可以用spring自己默认的,也可以用自定义的一样。
这个可以用 FactoryBean 来解决
业务类依赖 FactoryBean, FactoryBean 里面的 getObject 方法根据实际情况构造需要的对象 (例如你可以在那里访问 ApplicationContext, 能捞得到对象就返回捞到的对象, 否则则自己 new 一个)
另外实际上 MyBatis 也用到了这个 (SqlSessionFactoryBean等等等)
###和FactoryBean
去定义具体获取方式不同,其实也有Spring提供类似的机制,可以完成这个获取方式,即有自定义的用自定义,没有的话,使用默认的
比如:
@ConditionalOnMissingBean
用@ConditionalOnMissingBean
这个注解,你在配置你的默认实现时,给它上面加一个
@Bean
@ConditionalOnMissingBean(InterceptorPredicate.class)
public InterceptorPredicate defaultPre(){
return new YourDefaultPredicate();
}
这样如果配置之后,如果别人有配置了InterceptorPredicate
的实现,那你这个默认的实现自动失效了,然后你在你的MyInterceptor
里可以直接@Autowired
即可
@Component
public class MyInterceptor implements HandlerInterceptor {
@Autowired
private InterceptorPredicate predicate;
}
其实这种做法,官方里也很常用,尤其在一些autoconfigure
,比如redisTemplate
亦或者mongoTemplate
ObjectProvider
从该接口的注释就可以看得出,它就是你想要的,尤其是optionality,选择性,意味着你可以选择你Bean
的实现
其中的方法getIfAvailable
,从名字你就可以看出来,如果Bean
存在就返回
不说其他,我们看看其他autoconfigure
包里是怎么使用的,你就明白了
所以这样你的MyInterceptor
就好配置啦
@Bean
public HandlerInterceptor myInterceptor(ObjectProvider<InterceptorPredicate> predicateProvider){
InterceptorPredicate predicate = predicateProvider.getIfAvailable();
if(predicate == null) {
predicate = new YourDefaultPredicate();
}
return new MyInterceptor(predicate);
}
当然我们也可以看到MyInterceptor
还有一个重载的方法,传入一个默认的Supplier
所以我们也可以这样写
@Bean
public HandlerInterceptor myInterceptor(ObjectProvider<InterceptorPredicate> predicateProvider){
InterceptorPredicate predicate = predicateProvider.getIfAvailable(YourDefaultPredicate::new);
return new MyInterceptor(predicate);
}
如果只是简单的为空默认替换,其实上面两种基本都够用了,如果还有一些额外的不只是判空替换规则的话,你就还需要@Conditional
注解了,去定制你的bean
注入的条件