gpt4 book ai didi

java - Spring - 拦截 bean 创建和注入(inject)自定义代理

转载 作者:IT老高 更新时间:2023-10-28 13:56:50 31 4
gpt4 key购买 nike

我有一个带有 @Autowired 字段和处理程序方法的 @Controller,我想用自定义注释进行注释。

例如,

@Controller
public class MyController{
@Autowired
public MyDao myDao;

@RequestMapping("/home")
@OnlyIfXYZ
public String onlyForXYZ() {
// do something
return "xyz";
}
}

其中 @OnlyIfXYZ 是自定义注释的示例。我在想我会拦截 Controller bean 创建,传递我自己的 CGLIB 代理,然后 Spring 可以在该代理上设置属性,例如 Autowiring 字段。

我尝试使用 InstantiationAwareBeanPostProcessor,但该解决方案效果不佳,因为 postProcessBeforeInstantiation() 使其余过程短路。我尝试使用 postProcessAfterInitialization(),如下所示

public class MyProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// Here the bean autowired fields are already set
return bean;
}

@Override
public Object postProcessAfterInitialization(Object aBean, String aBeanName) throws BeansException {
Class<?> clazz = aBean.getClass();
// only for Controllers, possibly only those with my custom annotation on them
if (!clazz.isAnnotationPresent(Controller.class))
return aBean;

Object proxy = Enhancer.create(clazz, new MyMethodInterceptor());
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
// get the field and copy it over to the proxy
Object objectToCopy = field.get(aBean);
field.set(proxy, objectToCopy);
} catch (IllegalArgumentException | IllegalAccessException e) {
return aBean;
}
}
return proxy;
}
}

此解决方案使用反射将目标 bean 的所有字段复制到代理 bean(对我来说有点 hacky)。但是,如果 HttpServletRequestHttpServletResponse 对象不是我正在拦截的方法中的参数,我将无权访问它们。

在 Spring 填充其属性之前,我是否可以将另一个回调注入(inject)到 Spring bean 创建逻辑中以注入(inject)我自己的代理 Controller ? 我需要能够访问 HttpServletRequestHttpServletResponse 对象,无论 Controller 处理程序方法是否在其定义中包含它,即。作为论据。

注意 @Autowired 字段也是一个代理,它带有 @Transactional 注释,因此 Spring 代理它。

编辑: AOP 解决方案可以很好地拦截方法调用,但我找不到访问 HttpServletRequestHttpServletResponse 的方法> 对象,如果它们还不是方法参数。

我可能最终会使用 HandlerInterceptorAdapter,但我希望我可以使用 OOP 来做到这一点,以免给不需要它的方法增加开销。

最佳答案

看看Spring AOP .它拥有您所追求的设施。对于您的示例,您可以执行以下操作:

@Aspect
@Component
public class MyAspect {
@Around("@annotation(path.to.your.annotation.OnlyIfXYZ)")
public Object onlyIfXyz(final ProceedingJoinPoint pjp) throws Exception {
//do some stuff before invoking methods annotated with @OnlyIfXYZ
final Object returnValue = pjp.proceed();
//do some stuff after invoking methods annotated with @OnlyIfXYZ
return returnValue;
}
}

值得注意的是,Spring 只会将代理应用于属于其应用程序上下文的类。 (在您的示例中就是这种情况)

您还可以使用 Spring AOP 将参数绑定(bind)到您的切面方法。这可以通过多种方式完成,但您所追求的可能是 args(paramName)

@Aspect
@Component
public class MyAspect2 {
@Around("@annotation(path.to.your.annotation.OnlyIfXYZ) && " +
"args(..,request,..)")
public Object onlyIfXyzAndHasHttpServletRequest(final ProceedingJoinPoint pjp,
final HttpServletRequest request) throws Exception {
//do some stuff before invoking methods annotated with @OnlyIfXYZ
//do something special with your HttpServletRequest
final Object returnValue = pjp.proceed();
//do some stuff after invoking methods annotated with @OnlyIfXYZ
//do more special things with your HttpServletRequest
return returnValue;
}
}

这方面应该做你所追求的一部分。它将代理使用 @OnlyIfXYZ 注释的方法,ALSOHttpServletRequest 作为参数。此外,它会将这个 HttpServletRequest 作为传入参数绑定(bind)到 Aspect 方法中。

我了解您可能同时关注 HttpServletRequestHttpServletResponse,因此您应该能够修改 args 表达式以同时接受两者请求和响应。

关于java - Spring - 拦截 bean 创建和注入(inject)自定义代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15594071/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com