我想在Spring完全实例化之后,以某种方式对它进行后置处理。
但是,当我无法在ConfigurableListenerFactory发生ContextRefreshedEvent后从ContextRefreshedEvent获得原始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版本:5.2.7 version版本: 1.8.0_172
发布于 2020-09-10 17:49:57
我认为您无法以简单的方式从侦听器访问原始bean类:在应用程序上下文中,在执行侦听器时已经存在bean的代理。
另外,注意,由于java.lang.Proxy与接口一起工作,实际上没有“基础”bean,只有实现该接口的接口和代理。
因此,您可以在bean的接口中公开该方法,该接口将获取类并实现代理,以便它将委托给该方法。
interface MyBean {
...
Class<?> getRealClass();
}另一种方法是创建Class<?>到Class<?>的映射。这个映射将包含一个代理类,作为映射到“真正”bean类作为值的键,bean后处理器将向该映射添加条目,稍后在侦听器期间可以从应用程序上下文访问映射,但这也不是一种简单的方法。
总之,它可能会指出一些设计问题,因为实际上bean是没有创建的,所以我想不出任何这样的处理的具体示例,因为原始bean甚至不存在.
发布于 2020-09-10 19:58:49
事实证明,在Spring (与XML配置相比)中,bean定义中没有Bean类名的概念。bean是使用@Configuration类作为工厂创建的,没有保留真正的bean定义名称。
我能够实现我的目标:在Spring上下文初始化完成之后,调用bean的原始方法(bean被代理)如下:
information.
InvocationHandler的自定义实现,并传入所需的bean
代码:
public class MyInvocationHandler implements InvocationHandler {
private Object bean;
private ProfilingController controller;
public MyInvocationHandler(Object bean) {
this.bean = bean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Custom logic here - irrelevant for the purpose of this example
return method.invoke(bean, args);
}
public Object getBean() {
return bean;
}
}
public class PostProxyInvocationProcessor implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
final String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
final Object proxy = applicationContext.getBean(beanName);
if (proxy instanceof Proxy) {
final MyInvocationHandler invocationHandler = (MyInvocationHandler) Proxy.getInvocationHandler(proxy);
final Object bean = invocationHandler.getBean();
final Class<?> aClass = bean.getClass();
final Method[] methods = aClass.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyCustomAnnotation.class)) {
try {
method.invoke(bean);
}
catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}}
发布于 2020-09-10 20:58:30
我认为Bean的定义名实际上是Bean的名称。

因此,可以直接从configurableListableBeanFactory检索类名。
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
final ApplicationContext applicationContext = event.getApplicationContext();
final String[] beanDefinitionNamesFromAppContext = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName: beanDefinitionNamesFromAppContext) {
System.out.println( configurableListableBeanFactory.getBean(beanDefinitionName).getClass());
}
}https://stackoverflow.com/questions/63834134
复制相似问题