I am trying to implement capability of addition of new advisors to Spring beans. Idea is I will write Rest endpoint and will get PointCut expression and Bean name which I want to apply expression to via that endpoint. After I get pointcut expression and bean name, I will create new advisor with expression. Then I will add this advisor to proxy of existing bean.(Bean name coming from rest point.)
According to this SO question https://stackoverflow.com/a/49080647 I wrote code below for adding new advisors. In setAdvisor(Class beanClazz, Advisor advisor) method the line of Advised advisedBean = ((Advised) bean);
Casting did not work. Probably because of bean instance coming from ApplicationContext is not a proxy so I got CastingException.
Then I tried implement to create my own proxy of the bean and adding Advisor to this proxy again it did not work. This time I could add advisor to proxy but MethodInterceptor did not invoked so aop did not worked. Probably The reason it doesn't work, I did not put newly created proxy into somewhere like ApplicationContext etc. So where should I put this proxy or how can I change Spring to use this proxy instead of real instance of bean in ApplicationContext.
Besides this solution, if you have another solution, I would be very glad.
You can check implementations of classes below.
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());
EnablingAopController.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();
}
Note: In case you ask I also added @EnableAspectJAutoProxy annotation on the ApplicationMain class.
I also examine https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch08s02.html and found little bit about 8.2.4.2 Dynamic pointcuts but It is very small paragraph I couldn't understand well.
Also found https://stackoverflow.com/a/43052250 this answer for removing and adding beans to ApplicationContext but could not find how to put proxy that I created into ApplicationContext or somewhere