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,JdkDynamicAopProxygetAopProxyFactory為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);@Autowiredprivate 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方法。
總結
以上是生活随笔為你收集整理的spring service ,controller反向代理生成AOP代理类流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring ioc加载流程
- 下一篇: spring BeanPostProce