问题分享:BeanPostProcessor拦截某些Bean时拦截不到

  •  
  • 谁适合读此文章:
  1. 拥有八块腹肌的人

  2. 没博主帅的人

  • 背景:

项目引用了公共jar,里面定义了某些公共的service。但是本人开发中的项目需要对调用某些service的方法进行后处理

  • 初步思路:

经常使用spring的人应该知道,在bean初始化的时候会调用已经注册到容器的BeanPostProcessor(不知道我也不管你)。

本人的方案是:

  1. 新建一个bean(取名为MyServiceBeanPostProcessors)实现BeanPostProcessor接口,用于拦截MyService

  2. 拦截到MyService后给MyService创建一个代理并返回(所有依赖MyService这个bean的类其实依赖的是我们新创建的代理)

  3. 代理中针对要拦截的方法做处理,其它方法则直接调用

直接上代码

MyService:jar包中的结构

public interface MyService {
    String who();
}

MyServiceImpl:jar包中的实现类

@Service
public class MyServiceImpl implements MyService {
    @Override
    public String who() {
        return "博主";
    }
}

MyServiceProxy:新创建的代理

public class MyServiceProxy implements InvocationHandler {
    //被代理的方法
    private MyService myService;

    public MyServiceProxy(MyService myService) {
        this.myService = myService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("fuck")) {
            //前置处理
            System.out.println("我有腹肌");

            //调用被代理的方法 who
            Object result = method.invoke(myService, args);

            //后置处理
            System.out.println("我最帅");

            return result;
        }
        return method.invoke(myService, args);
    }

    public MyService getProxy() {
        // 给myService创建代理
        return (MyService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                myService.getClass().getInterfaces(), this);
    }
}

MyServiceBeanPostProcessors:(注意:@Conponent标签不能少,因为该bean也必须交给spring管理)

@Component
public class MyServiceBeanPostProcessors 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(bean instanceof MyService){
            return new MyServiceProxy((MyService) bean).getProxy();
        }
        return bean;
    }
}

一切感觉很完美

可是,万万没想到。完全不在意料之中,MyService这个Bean初始化的时候没有调用自定义的PostProcessor

问题出在哪呢?

难道因为博主太帅了(很有可能);

难道spring文档出问题了;

难道spring版本有问题;

 

掏出debug大法(感谢万能的IDEA)

警告!警告!下面会涉及一丢丢spring源码

 

编译成class的类一般会加上默认构造器,如下

@Service
public class MyServiceImpl implements MyService {
    public MyServiceImpl() {
    }

    public String who() {
        return "博主";
    }
}

直接断点在构造方法处,看初始化此类时的调用信息。初始化Bean时会调用构造方法:

发现调用起点在如下处:应用启动时调用

org.springframework.context.support.AbstractApplicationContext.refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
    // 前后方法省略
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // 前后方法省略
    // 调用点在这  
    registerBeanPostProcessors(beanFactory);
		
}

该方法会调用PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this),主要是注册和初始化已经被解析成BeanDefinition并且实现了BeanPostProcessor的Bean

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

下面是重点关注点,重点关注执行顺序

	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
		// 获取所有类型为BeanPostProcessor的bean
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		/**
		 * 	BeanPostProcessorChecker是一个普通的信息大于,当出现spring后置处理器还没有注册就开始
		 * 	初始化bean的时候会打印里面设置的日志,博主的就打印了 (实现很简单,请自行查看)
		 */
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// 实现了PriorityOrdered的PostProcessors
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		// 有序的orderedPostProcessorNames
		List<String> orderedPostProcessorNames = new ArrayList<>();
		// 无序的PostProcessors
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();

		// 给上面的list添加值
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				// 实例化所有实现了 PriorityOrdered 的bean
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			} else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// 排序priorityOrderedPostProcessors
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		// 注册priorityOrderedPostProcessors里的 PostProcessors
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			// 初始化与orderedPostProcessorNames里名称关联的所有bean
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}

		// 排序
		sortPostProcessors(orderedPostProcessors, beanFactory);
		// 注册orderedPostProcessors里的 PostProcessors
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);


		// 和上面流程类似
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

大致说一下上面的流程:

  1. 首先获取所有实现了BeanPostProcessor的并且已被解析成BeanDefinition对应的beanName
  2. 向容器注册一个BeanPostProcessorChecker。该处理器的作用是在还没有注册完所有的BeanPostProcessor就开始初始化其它bean时,会打印对应的info日志。(好东西呀)
  3. 接下来会对有优先级的,有序的,无序的BeanPostProcessor依次进行初始化并注册,注意:这里是依次,是有先后顺序的

相信读者看了上面的流程大概也知道为什么会出现自定义到的BeanPostProcessor对有些bean无效了吧。

举个例子:如果在初始化带有优先级的BeanPostProcessor时候初始化了其它bean(对应的BeanPostProcessor依赖其他非BeanPostProcessor的bean),会导致初始化有序的,无序的BeanPostProcessor时无法对前面已经初始化的bean进行处理

 

我的解决方案是自定义的BeanPostProcessor实现PriorityOrdered接口(保证自定义的处理器先注册):有更好的方案请留言,欢迎弹劾:

我的方案有个问题:如果其他实现PriorityOrdered的BeanPostProcessor先初始化,并且里面实例化了其它bean,这种我还无解。------------------啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,欢迎大神赐教

@Component
public class MyServiceBeanPostProcessors implements BeanPostProcessor,PriorityOrdered {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 初始化前不做任何处理
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 初始化后使用代理对象
        if(bean instanceof MyService){
            return new MyServiceProxy((MyService) bean).getProxy();
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

 

每天进步一点点!!欢迎各位大神参与讨论

联系邮箱:zhanghao_scyb@sina.com 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值