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());
        }
    }
}
相關文章
相關標籤/搜索