我正在尝试实现向 Spring bean 添加新顾问的功能。想法是我将编写 Rest 端点,并将获得 PointCut 表达式 和我想通过该端点应用表达式的 Bean 名称。获得切入点表达式和 bean 名称后,我将使用表达式创建新的顾问程序。然后我将这个顾问添加到现有 bean 的代理中。(bean 名称来自休息点。)
根据这个问题https://stackoverflow.com/a/49080647,我在下面编写了用于添加新顾问的代码。在 setAdvisor(Class beanClazz, Advisor advisor) 方法中,Advised advisedBean = ((Advised) bean);
Casting 行不起作用。可能是因为 bean 实例来自 ApplicationContext 不是代理,所以我得到了 CastingException。
然后我尝试实现来创建我自己的 bean 代理,并再次将 Advisor 添加到此代理中,但它不起作用。这次我可以向代理添加顾问,但 MethodInterceptor 没有调用,所以 aop 不起作用。可能是它不起作用的原因,我没有把新创建的代理放到 ApplicationContext 等地方。那么我应该把这个代理放在哪里,或者我如何改变 Spring 来使用这个代理而不是 ApplicationContext 中 bean 的真实实例。>
除了这个解决方案,如果你有另一个解决方案,我会很高兴。
您可以在下面检查类的实现。
LoggingAttacher.Java
import org.aopalliance.aop.Advice;
import org.apache.naming.factory.BeanFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class LoggingAttacher implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
static <T> T getBean(Class<T> beanClazz) {
return context.getBean(beanClazz);
}
public static <T> void setAdvisor(Class<T> beanClazz, Advisor advisor) {
try {
T bean = getBean(beanClazz);
Advised advisedBean = ((Advised) bean);
advisedBean.addAdvisor(advisor);
} catch (BeansException e) {
e.printStackTrace();
}
}
public static <T> void setAdvisorWithNewProxy(Class<T> beanClazz, Advisor advisor) {
try {
T bean = getBean(beanClazz);
Advised advisedBean = ((Advised) createProxy(bean));
advisedBean.addAdvisor(advisor);
} catch (BeansException e) {
e.printStackTrace();
}
}
public static <T> Advised createProxy(T bean) {
if (bean instanceof Advised) {
System.out.println("Bean " + bean + " is already an advised proxy, doing nothing");
return (Advised) bean;
}
System.out.println("Creating proxy for bean " + bean);
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(bean);
return (Advised) proxyFactory.getProxy();
}
// Note: MypointCutAdvisor extends DefaultPointcutAdvisor!!!
public static MyPointCutAdvisor createAdvisor(String expression) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
return new MyPointCutAdvisor(pointcut, new LoggingInterceptor());
启用AopController.java
@RestController
public class EnablingAopController {
@GetMapping("/enable-aop")
public String enableAop() {
MyPointCutAdvisor myPointCutAdvisor = LoggingAttacher.createAdvisor("execution(* com.argmnt.logging.logging_project.AppService.*(..))");
LoggingAttacher.setAdvisor(AppService.class, myPointCutAdvisor);
return "example1";
}
}
MyPointCutAdvisor.java
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class MyPointCutAdvisor extends DefaultPointcutAdvisor {
public MyPointCutAdvisor(Pointcut pointcut, Advice advice) {
super(pointcut, advice);
}
}
LoggingInterceptor.java
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LoggingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("in interceptor");
return invocation.proceed();
}
注意:如果你问我还在 ApplicationMain 类上添加了 @EnableAspectJAutoProxy 注释。
我还检查了 https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch08s02.html 并找到了一些关于 8.2.4.2 Dynamic pointcuts 的内容,但它是很小的一段,我不太明白。
还找到了 https://stackoverflow.com/a/43052250 这个用于删除和添加 bean 到 ApplicationContext 的答案,但找不到如何将我创建的代理放入 ApplicationContext 或某处