0

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

argmnt
  • 69
  • 6
  • You referred to my answer, but it does not contain any calls to `setAdvisor`. I.e., you must have changed something, but I did not analyse your code. Did you clone my GitHub repository and start with that first? Actually, you should not do a lot of manual configuration but do what I suggested in the "update 3" section of my answer. In any case, this is a complex problem, so please share an [MCVE](https://stackoverflow.com/help/mcve) on GitHub, just like I did. – kriegaex Aug 02 '21 at 04:38
  • Without any feedback, it is difficult to help you. – kriegaex Aug 06 '21 at 00:54

0 Answers0