- 继承ApplicationRunner接口,可以在ApplicationContext加载完成后被调用
- 执行顺序是在所有的初始化和自动配置完成之后
- 可以使用@Component或@Configuration标记
- 当有多个继承ApplicationRunner的事后,执行的顺序是根据其注入的顺序决定的。如果想要指定顺序执行可以使用@Order进行排序
- 除了ApplicationRunner外,CommandLineRunner也提供了相似的功能,最大的区别在于一个用ApplicationArguments接收参数,一个用Sting数组进行接收参数
示例,修改传统实现获取基础持久对象方法,主动注入基类
原始调用方法
//传统实现调用方式1
@Slf4j
@Repository
@RequiredArgsConstructor
public class UserRepository extends BaseRepository<User, Long> {
private final UserDao userDao;
@Override
public BaseDao<User, Long> getBaseDao(){
return userDao;
}
}
//传统实现调用方式2
@Slf4j
@Repository
@RequiredArgsConstructor
public class UserRepository extends BaseRepository<User, Long> {
private final UserDao userDao;
//PostConstruct会在初始化对象技术,并且注入完类后,BeanPostProcessor后置处理器之前执行
@PostConstruct
public void init(){
this.baseDao = userDao;
}
}
修改后注入方式
//启动注入方式
@Slf4j
@Repository
@RequiredArgsConstructor
@AutomaticInjectionClassProvider(value = UserDao.class, fieldName = "baseDao")
public class UserRepository extends BaseRepository<User, Long> {
}
继承ApplicationRunner,当ApplicationContext加载完成后被调用,并且在所有的初始化和自动配置完成之后执行
@Configuration
@RequiredArgsConstructor
public class AutomaticInjectionPostProcessor implements ApplicationRunner {
private final ApplicationContext applicationContext;
@Override
public void run(ApplicationArguments args) throws Exception {
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(AutomaticInjectionClassProvider.class);
Collection<Object> values = beans.values();
for (Object beanObject : values) {
Class<?> beanClass = beanObject.getClass();
AutomaticInjectionClassProvider injectionClassProvider = beanClass.getAnnotation(AutomaticInjectionClassProvider.class);
Class<?> injectionClassProviderClass = injectionClassProvider.value();
String fieldName = injectionClassProvider.fieldName();
Object providerObject = SpringUtil.getBean(injectionClassProviderClass);
if (Objects.isNull(providerObject)) {
throw new RuntimeException("启动注入异常,类未实例化: " + beanObject.getClass().getTypeName());
}
this.injectObject(beanObject, fieldName, providerObject);
}
}
/**
* 注入对象
*
* @param beanObject 被注入对象
* @param fieldName 注入字段名
* @param providerObject 注入对象
* @throws Exception
*/
public void injectObject(Object beanObject, String fieldName, Object providerObject) throws Exception {
Field baseDaoField = this.getClassByName(beanObject, fieldName);
if (Objects.isNull(baseDaoField)) {
throw new RuntimeException("启动注入异常: " + beanObject.getClass().getTypeName());
}
baseDaoField.setAccessible(true);
if (AopUtils.isCglibProxy(beanObject)) {
Object target = this.getProxyObject(beanObject);
try {
baseDaoField.set(target, providerObject);
} catch (Exception e) {
e.printStackTrace();
}
} else {
baseDaoField.set(beanObject, providerObject);
}
}
/**
* 根据字段名称查找字段
*
* @param object 被查找对象
* @param name 字段名
* @return
*/
public Field getClassByName(Object object, String name) {
Assert.notNull(object, "Class must not be null");
Assert.isTrue(!Object.class.getName().equals(object.getClass().getName()), "没有找到被注入的字段, fieldName: " + name);
Class<?> clazz = object.getClass();
Field baseDaoField = ReflectionUtils.findField(clazz, name);
if (Objects.isNull(baseDaoField)) {
Class<?> superclass = clazz.getSuperclass();
if (Object.class.getTypeName().equals(superclass.getTypeName())) {
return null;
}
return getClassByName(clazz.getSuperclass(), name);
}
return baseDaoField;
}
/**
* 获取代理类
*
* @param obj 被代理类
* @return 代理对象
* @throws Exception 异常
*/
public Object getProxyObject(Object obj) throws Exception {
Field cglib$CALLBACK_0 = obj.getClass().getDeclaredField("CGLIB$CALLBACK_0");
cglib$CALLBACK_0.setAccessible(true);
Object cglibSupperObject = cglib$CALLBACK_0.get(obj);
Field advised = cglibSupperObject.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object target = ((AdvisedSupport) advised.get(cglibSupperObject)).getTargetSource().getTarget();
if (AopUtils.isCglibProxy(target)) {
return this.getProxyObject(target);
}
return target;
}
}
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutomaticInjectionClassProvider {
Class<?> value();
String fieldName();
}