不少java开发者在使用Spring框架中都见事后缀为FactoryBean的类,好比Mybatis-Spring中的SqlSessionFactoryBean。说到这里就不得不提BeanFactory。FactoryBean和BeanFactory特别容易让人混淆,面试还常常问到这两种概念。其实它们的做用和使用场景是不同的java
先来讲说BeanFactory。 用于访问Spring bean容器的根接口。这是Spring bean容器的基本客户端视图。原来是获取Spring Bean的接口,也就是IoC容器。而后咱们看类图面试
原来咱们更经常使用的ApplicationContext就是一个BeanFactory。咱们经过bean的名称或者类型均可以从BeanFactory来获取bean。对于BeanFactory这么介绍相信都不陌生了。让咱们把关注点转向FactoryBean上。segmentfault
FactoryBean 是个什么玩意儿呢?来看看源码框架
public interface FactoryBean<T> { @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
FactoryBean 用来建立一类bean。好比你有一些同属鸟类的bean须要被建立,可是它们本身有各自的特色,你只须要把他们的特色注入FactoryBean中就能够生产出各类鸟类的实例。举一个更加贴近实际生产的例子。甚至这个例子你能够应用到实际java开发中去。咱们须要本身造一个定时任务的轮子。用FactoryBean 再合适不过了。咱们来用代码说话一步步来演示FactoryBean的使用场景。ide
咱们声明定时任务通常具备下列要素:测试
Task任务执行抽象接口的实现。实现包含两个方面:this
public class CustomTask implements Task { private SomeService someService; private String cronExpression; public CustomTask(SomeService someService) { this.someService = someService; } @Override public void execute() { //do something someService.doTask(); } @Override public void setCron(String cronExpression) { this.cronExpression = cronExpression; } @Override public String getCron() { return cronExpression; } }
经过以上的定义。任务的时间和任务的逻辑能够根据不一样的业务作到差别化配置。而后咱们实现一个关于Task的FactoryBean。spa
public class TaskFactoryBean implements FactoryBean<Task> { private SomeService someService; private String cronExpression; @Override public Task getObject() throws Exception { CustomTask customTask = new CustomTask(someService); customTask.setCron(cronExpression); return customTask; } @Override public Class<?> getObjectType() { return CustomTask.class; } @Override public boolean isSingleton() { return true; } public SomeService getSomeService() { return someService; } public void setSomeService(SomeService someService) { this.someService = someService; } public String getCronExpression() { return cronExpression; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } }
你可使用xml的注入方式,固然也可使用javaConfig的配置方式。这里咱们使用javaConfig注入。咱们将两个FactroyBean注入到Spring容器中去。debug
@Configuration public class Config { @Bean public TaskFactoryBean customTask() { TaskFactoryBean taskFactoryBean = new TaskFactoryBean(); taskFactoryBean.setCronExpression("0 15 10 * * ?"); String word = "定时任务一"; SomeService someService = new SomeService(); someService.setWord(word); taskFactoryBean.setSomeService(someService); return taskFactoryBean; } @Bean public TaskFactoryBean otherTask() { TaskFactoryBean taskFactoryBean = new TaskFactoryBean(); taskFactoryBean.setCronExpression("0 15 17 * * ?"); String word = "定时任务二"; SomeService someService = new SomeService(); someService.setWord(word); taskFactoryBean.setSomeService(someService); return taskFactoryBean; } }
通常如上声明后,@Bean注解若是不显式声明bean名称则方法名做为bean的名称,并且返回值做为注入的Bean。可是咱们经过debug发现倒是这样的:code
也就是说经过方法名是返回FactoryBean 建立的Bean。那么如何返回该FactoryBean呢?上图中也给出了答案在方法前增长引用符“&”。具体的缘由还用从BeanFactory中寻找,真是否是冤家不聚头
咱们对上面声明的两个bean进行测试,也出色地完成了不一样的定时任务业务逻辑。
@Autowired private Task customTask; @Autowired private Task otherTask; @Test public void task() { customTask.execute(); otherTask.execute(); }
在后续的使用中你能够经过声明不一样的cron表达式,以及不一样SomeService来定制更多的定时任务。经过这个例子相信你会对FactoryBean有的清晰的认识。demo就不提供了,很是简单,强烈建议你本身试一试以加深理解。
关注公众号:码农小胖哥 获取更多资讯