JavaSpringBeanDefinition类名包含实例化bean的null
我想在Springbean完全实例化之后,以某种方式对其进行后期处理
但是,当ContextRefreshedEvent
发生后,我无法从ConfigurableListenerFactory
获取原始bean类名(因为它是代理的)
我无法从ApplicationContext
获取bean类,因为它是由JDK动态代理代理的。
问题-如何获得原始bean的类
请参见下面的可验证示例:
import java.lang.reflect.Proxy;
import java.util.Objects;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
public class ApplicationContextRefreshedEventTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigurationClass.class);
MyBean myBean = applicationContext.getBean(MyBean.class);
myBean.hello();
}
}
@Configuration
class MyConfigurationClass {
@Bean
public MyBean myBean() {
return new MyBeanImp();
}
@Bean
public MyAppEventListener myAppEventListener() {
return new MyAppEventListener();
}
@Bean
static MyBeanPostProcessor myBeanPostProcessor() {
return new MyBeanPostProcessor();
}
}
class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("myBean")) {
final Class<?> aClass = bean.getClass();
return Proxy.newProxyInstance(aClass.getClassLoader(), aClass.getInterfaces(),
(proxy, method, args) -> method.invoke(bean, args));
} else {
return bean;
}
}
}
class MyAppEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
ConfigurableListableBeanFactory configurableListableBeanFactory;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
final String[] beanDefinitionNames = event.getApplicationContext().getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
final BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition(beanName);
final String beanClassName = beanDefinition.getBeanClassName();
if (Objects.isNull(beanClassName)){
System.out.println(beanDefinition);
}
}
}
}
interface MyBean {
void hello();
}
class MyBeanImp implements MyBean {
@Override
public void hello() {
}
}
输出:
Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=myConfigurationClass; factoryMethodName=myBean; initMethodName=null; destroyMethodName=(inferred); defined in com.example.MyConfigurationClass
null
Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=myConfigurationClass; factoryMethodName=myAppEventListener; initMethodName=null; destroyMethodName=(inferred); defined in com.example.MyConfigurationClass
null
Spring version : 5.2.7.RELEASE JDK version : 1.8.0_172
# 1 楼答案
事实证明,在SpringJava配置中(与XML配置相比),bean定义中没有bean类名称的概念。bean是使用
@Configuration
类作为工厂创建的,不保留真正的bean定义名称我能够实现我的目标:在Spring上下文初始化完成后调用bean的原始方法(bean被代理),如下所示:
InvocationHandler
的自定义实现,并传入了所需的bean信息李>InvocationHandler
李>代码:
}
# 2 楼答案
我认为您无法从侦听器以简单的方式访问原始bean类:在应用程序上下文中,当侦听器被执行时,已经存在bean的代理
另外,请注意,由于
java.lang.Proxy
与接口一起工作,因此实际上没有“底层”bean,只有实现该接口的接口和代理因此,您可以在bean的接口中公开该方法,该接口将获取该类并实现代理,以便它将委托给该方法
另一种方法是创建
Class<?>
到Class<?>
的映射。这个映射将包含一个代理类作为一个键映射到“真实”bean类作为一个值,bean后处理器将向这个映射添加条目,这个映射可以在稍后的侦听器期间从应用程序上下文访问,但同样,这不是一个简单的方法总而言之,它可能会指向一些设计问题,因为实际上bean并没有被创建,所以我想不出任何具体的操作系统示例,比如处理,因为原始bean甚至不存在
# 3 楼答案
我认为Bean定义名称实际上就是Bean名称。
因此,可以直接从configurableListableBeanFactory