Spring pointcut(value=${})注入

背景

公司的一个小的公共SDK,须要将每一个项目的方法调用的切面日志输出。session

  1. 输出指定类(方法)的切面日志;
  2. 每一个项目的切点可配置。

需求分析

其实该需求很是明确ide

  1. 工程引入SDK包;
  2. 切点采用配置文件配置;
  3. 切点为注解: 需求转化为,在Spring 初始化过程当中,动态设置切点的值。 通过这两步以后就能够正常输出切面日志了。

难点

  1. Spring bean是由BeanFactory建立, 如何在其初始化过程当中,获取到该bean,并设置相应注解的值;
  2. 如何获取正在建立(初始化)中的bean

解决方案

如何获取到bean

如上图所示,采用 BeanPostProcessor(该图未经原做者受权,若有侵犯将当即删除) https://www.zhihu.com/question/48427693/answer/723146648?utm_source=wechat_session&utm_medium=social&utm_oi=71495346814976post

修改注解的值

采用Java反射的方式进行修改。 http://www.javashuo.com/article/p-ofkxaaqw-ks.htmlthis

代码

@Component
public class LogAspectBeanPostProcessor implements BeanPostProcessor {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogAspectBeanPostProcessor.class);
    @Value("${aspect.log.pointcut:test}")
    private String pointValue;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * 功能描述: 采用反射的方式处理该问题
     *
     * @param:
     * @return:
     * @auther: kukuxiahuni
     * @date: 2019-09-18 17:09
     * @modify_auther: kukuxiahuni
     * @modify_time: 2019-09-18 17:09
     **/
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Object object = bean;
        if (bean instanceof ControllerAspect) {
            Class beanClass = bean.getClass();
            try {
                /**
                 * 切面
                 */
                Method aroundMethod = beanClass.getDeclaredMethod("methodPoint");
                /**
                 * 切点注解
                 */
                Pointcut pointcut = aroundMethod.getAnnotation(Pointcut.class);
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("注解原始值={}", pointcut.value());
                }

                if (Objects.isNull(pointcut)) {

                    return object;
                }
                /**
                 * 注解使用中实质为代理类
                 */
                InvocationHandler invocationHandler = Proxy.getInvocationHandler(pointcut);
                // 获取 AnnotationInvocationHandler 的 memberValues 字段
                Field declaredField = invocationHandler.getClass().getDeclaredField("memberValues");
                declaredField.setAccessible(true);

                Map<String, Object> valMap = (Map<String, Object>) declaredField.get(invocationHandler);
                valMap.put("value", this.pointValue);

                info(LOGGER, () -> {
                    String s = "新值为:" + pointcut.value();
                    return s;
                });

            } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
                LOGGER.error("处理新值失败", e);
            }

        }
        return object;
    }

    /**
     * 功能描述: TODO
     *
     * @param:
     * @return:
     * @auther: kukuxiahuni
     * @date: 2019-09-18 17:44
     * @modify_auther: kukuxiahuni
     * @modify_time: 2019-09-18 17:44
     **/
    private final void info(Logger logger, Supplier<String> content) {

        if (logger.isInfoEnabled()) {
            logger.info(content.get());
        }
    }
}
相关文章
相关标签/搜索