在项目中,用到了SPI来扩展一些功能,发现很多实现类中用到了bean对象,并且都是通过getBean的方式每次都去拿,感觉不是很方便,而且速度也没有直接使用对象快。
正好安排的工作就是优化那一块的代码,所以就改造了一下,让SPI实现类中支持注入spring bean依赖,下面的类名有所改变,还有使用到的方法,大家可以按需改造。
-
首先,为了不影响之前的逻辑,定义了一个接口
BeanResource
,需要自动注入bean的类,就实现这个接口;java/** * 实现类中,实现了这个接口就会自动注入bean,配合注入注解等使用 */ public interface BeanResource { }
-
通过
ApplicationContext
类的getAutowireCapableBeanFactory()
方法拿到AutowireCapableBeanFactory
工厂类;可以通过hutool工具包的
SpringUtil.getApplicationContext().getAutowireCapableBeanFactory()
方式拿到,也可以自己实现一个ApplicationContextAware
接口,然后在构造器中获取ApplicationContext
对象。 -
通过
autowireBeanProperties
方法注入bean对象
autowireBeanProperties
方法有三个形参,第一个是要注入bean依赖的对象,第二个是注入的方式(根据类型或名称),第三个参数是是否依赖检查,这里我们用true
,这样注入bean依赖有问题会报错。java// 首先通过拿到所有的子类 final ServiceLoader<XXXXX> loader = ServiceLoader.load(XXXXX.class); final AutowireCapableBeanFactory beanFactory = SpringUtil.getApplicationContext().getAutowireCapableBeanFactory(); for (XXXXX xxxxx : loader) { // 如果需要注入bean对象 if (xxxxx instanceof BeanResource) { try { // 给xxxxx注入bean对象,支持@Resource和@Autowired注入,还有set注入; 按类型注入(其实只要你用平常的注入方式BY NAME也可以,除了构造器注入,因为对象是已经创建好了的);进行依赖检查,如果有问题直接报错 beanFactory.autowireBeanProperties(xxxxx, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); } catch (Exception e) { e.printStackTrace(); } } }
-
最后在扩展类中使用,除了构造器注入,其他常用的注入方式都行。
java@AutoService(XXXXX.class) public class Sub implements XXXXX, BeanResource { @Resource private A a; @Autowired private B b; @Setter private C c; }