spring service ,controller反向代理生成AOP代理类流程

一、在applicationContext的beanFactory.preInstantiateSingletons方法中,会初始化所有的单例BEAN.

二、

1.AbstractAutowireCapableBeanFactory.doCreateBean在调用BEAN默认构造函数反射生成实例对象后,会populateBean填充属性,
2.如果属性是通过AUTOWIRED或者RESOURCE依赖注入时,则会触发CommonAnnotationBeanPostProcessor的处理器,此处理器会再次去BEAN工厂获取属性BEAN,不存在则再次调用createBean创建。

3.在实例化完属性对象后,会调用AbstractAutowireCapableBeanFactory.initializeBean再次对BEAN进行后置处理,

4.然后又会调用AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization对BEAN对象进行修改。

5.最后调用AbstractAutoProxyCreator.createProxy创建代理对象。此函数创建代理对象时会传入所有当前系统注册的切面注入到代理对象,ExposeInvocationInterceptor--这个是系统默认的拦截对象。

三、实际生成cglib/jdk proxy object,的流程。

 1.接上面最后一步,在public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport这个类中,会调用createAopProxy().getProxy(classLoader)

2.createAopProxy()会调用getAopProxyFactory().createAopProxy(this);这个接口返回的对象为

AopProxy,有两种实现,分为CglibAopProxy,JdkDynamicAopProxy

getAopProxyFactory为DefaultAopProxyFactory

3.CglibAopProxy的getProxy接口来生成实际的CGLIB或者 JDK代理类。生成代理类中会设置一系列的callback
就是拦截器,也就是系统容器中定义的通知处理方法(如执行前,执行后,环绕,返回前,抛出异常前)。
package com.tpw.newday.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.tpw.newday.annation.CacheProcesser;
import com.tpw.newday.common.MyConstants;
import com.tpw.newday.redis.RedisParam;
import com.tpw.newday.redis.RedisService;
import com.tpw.newday.utils.RedisUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * <h3>newday</h3>
 * <p>xx</p>
 *
 * @author : lipengyao
 * @date : 2021-04-30 15:56:19
 **/
@Aspect
@Component
public class CacheAspect {

    private static final Log logger = LogFactory.getLog(CacheAspect.class);

    private RedisUtil redisUtil = new RedisUtil(MyConstants.redis_host_ip,MyConstants.redis_port,MyConstants.redis_password);

    @Autowired
    private RedisService redisService;

    @Pointcut("execution(* com.tpw.newday.service..*.*(..)))")
    private void cacheMethod() {

    }

    /**
     * 前置通知:在目标方法执行前调用
     */
    @Before("cacheMethod()")
    public void begin() {
        logger.info("==@Before== lipy cache method : begin");
    }

    /**
     * 后置通知:在目标方法执行后调用,若目标方法出现异常,则不执行
     */
    @AfterReturning("cacheMethod()")
    public void afterReturning() {
        logger.info("==@AfterReturning== lipy cache method : after returning");
    }

    /**
     * 后置/最终通知:无论目标方法在执行过程中出现一场都会在它之后调用
     */
    @After("cacheMethod()")
    public void after() {
        logger.info("==@After== lipy cache method : finally returning");
    }

    /**
     * 异常通知:目标方法抛出异常时执行
     */
    @AfterThrowing("cacheMethod()")
    public void afterThrowing() {
        logger.info("==@AfterThrowing==  lipy cache method : after throwing");
    }

    /**
     * 环绕通知:灵活自由的在目标方法中切入代码
     */
    @Around("cacheMethod()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        // 获取方法传入参数
        Object[] params = joinPoint.getArgs();
        logger.info("==@Around== lipy cache method --》 method name " + methodName + " args " + params[0]);
        return handleMethod(joinPoint);
    }

    /**
     * 获取redis的key
     */
    private String parseKey(String fieldKey, Method method, Object[] args) {
        //获取被拦截方法参数名列表(使用Spring支持类库)
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = u.getParameterNames(method);
        //使用SPEL进行key的解析
        ExpressionParser parser = new SpelExpressionParser();
        //SPEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        //把方法参数放入SPEL上下文中
        for (int i = 0; i < paraNameArr.length; i++) {
            context.setVariable(paraNameArr[i], args[i]);
        }
        String key= parser.parseExpression(fieldKey).getValue(context, String.class);
        return  key;
    }

    /**
     * 获取方法中声明的注解
     *
     * @param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    public Object handleMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法名
        String methodName = joinPoint.getSignature().getName();
        // 反射获取目标类
        Class<?> targetClass = joinPoint.getTarget().getClass();
        // 拿到方法对应的参数类型
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        // 根据类、方法、参数类型(重载)获取到方法的具体信息
        Method objMethod = targetClass.getMethod(methodName, parameterTypes);

        // 获取方法传入参数
        Object[] params = joinPoint.getArgs();
        // 拿到方法定义的注解信息
        CacheProcesser annotation = objMethod.getDeclaredAnnotation(CacheProcesser.class);
        if (ObjectUtil.isNull(annotation)){
            // 执行源方法
            return joinPoint.proceed();
        }

        if (annotation.cacheOperation() == CacheProcesser.CacheOperation.QUERY){
            String cacheKey = annotation.key()+ ":"+this.parseKey(annotation.fieldKey(),objMethod ,params );
            RedisParam redisParam = new RedisParam(cacheKey,annotation.expireTime());
            Object cacheResult = redisService.get(redisParam);
            if (ObjectUtil.isNotNull(cacheResult)){
                logger.info(" get from cache key:" + cacheKey);
                return cacheResult;
            }else{
                Object obj = joinPoint.proceed();
                redisService.set(redisParam,obj );
                logger.info(" call method,set to  cache key:" + cacheKey);
                return  obj;
            }
        }else if (annotation.cacheOperation() == CacheProcesser.CacheOperation.UPDATE ||
                annotation.cacheOperation() == CacheProcesser.CacheOperation.DELETE ){
            Object obj = joinPoint.proceed();
            String cacheKey = annotation.key()+ ":"+this.parseKey(annotation.fieldKey(),objMethod ,params );
            RedisParam redisParam = new RedisParam(cacheKey,annotation.expireTime());
            logger.info(" delete from cache key:" + cacheKey);
            redisService.remove(redisParam);
            return  obj;
        }
        return  joinPoint.proceed();
    }
}

  4.最终把cglib或者JDK生成的代理类注入到属性中,或者返回给创建者。

四、最终HTTP请求调用过时,调用服务类接口时,首先会调用到代理类的方法。

  1.上述接口会先调用DynamicAdvisedInterceptor.intercept方法,此接口实现了cglib的

MethodInterceptor方法,会被CGLIB反向调用。

2.上述方法内会调用 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(), CglibMethodInvocation 会继承于 ReflectiveMethodInvocation,最终触发到

ReflectiveMethodInvocation.proceed()

3.ReflectiveMethodInvocation内有一个拦截器数组interceptorsAndDynamicMethodMatchers,存储了所有的切面方法,会根据索引逐个调用,拦截器内部又会再次调用此对象的ReflectiveMethodInvocation.proceed,调到下一个拦截器,

拦截器列表:

4.如果拦截器调用完,则会调用最终的methodProxy方法。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值