如何动态配置Spring AOP使运行时注册的切面配置生效
动态注册Spring AOP配置生效方案
失效原因
Spring AOP的代理生成逻辑默认仅在单例Bean初始化的后置处理器阶段执行,运行时动态注册切面/Advisor后,已经完成初始化的目标Bean不会自动重新生成代理,因此切面逻辑无法触发。
你第二个方案失效的额外原因:你注册的Config类中的config()方法为私有且无@Bean注解,Spring不会自动将方法返回的Advisor实例注册到容器中,自然不会生效。
可行实现方案
方案1:直接注册Advisor(更适合安全利用场景,逻辑更简单无注解依赖)
- 构造恶意拦截器和Advisor
// 自定义拦截器,写入恶意执行逻辑 MethodInterceptor maliciousInterceptor = new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { // 恶意逻辑位置 System.out.println("执行恶意代码,当前调用方法:" + invocation.getMethod().getName()); return invocation.proceed(); } }; // 构造切入点,匹配你要拦截的目标方法 AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(public * com.example.aop.*.*(String))"); // 组装Advisor DefaultPointcutAdvisor maliciousAdvisor = new DefaultPointcutAdvisor(pointcut, maliciousInterceptor);
- 注册Advisor到Spring容器
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory(); // 直接注册Advisor单例 beanFactory.registerSingleton("maliciousAdvisor", maliciousAdvisor);
- 触发已初始化Bean重新代理
拿到容器中存在的AnnotationAwareAspectJAutoProxyCreator实例(只要项目开启了AOP功能就会存在该Bean),对目标Bean重新生成代理并替换容器中原实例:
AnnotationAwareAspectJAutoProxyCreator proxyCreator = beanFactory.getBean(AnnotationAwareAspectJAutoProxyCreator.class); // 可指定目标BeanName,不需要全量遍历,减少利用特征 String targetBeanName = "yourTargetBeanName"; Object targetBean = beanFactory.getBean(targetBeanName); Object proxyBean = proxyCreator.postProcessAfterInitialization(targetBean, targetBeanName); // 替换容器中原实例 if (proxyBean != targetBean) { beanFactory.destroySingleton(targetBeanName); beanFactory.registerSingleton(targetBeanName, proxyBean); }
方案2:动态注册@Aspect类
如果要用带@Aspect注解的类,注册时需标记其为基础设施Bean,避免被其他切面代理,之后同样执行重代理逻辑即可:
BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(ParamAspect.class); // 标记为基础设施角色 beanDefBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); if (!beanFactory.containsBeanDefinition("paramAspect")) { beanFactory.registerBeanDefinition("paramAspect", beanDefBuilder.getBeanDefinition()); } // 后续执行和方案1相同的重代理逻辑即可生效
内容的提问来源于stack exchange,提问作者4ra1n
相关产品推荐
相关产品推荐

