侧边栏壁纸
博主头像
憨憨大头个人博客博主等级

心存希冀,目有繁星

  • 累计撰写 110 篇文章
  • 累计创建 13 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Cglib、Jdk以及ProxyFactory实现动态代理,以及springAop一些源码分析

Administrator
2024-08-09 / 0 评论 / 0 点赞 / 9 阅读 / 34237 字

动态代理就是在不改变原代码逻辑的基础上,对代码功能进行增强。

一、Jdk动态代理

Jdk的动态代理是基于接口的,即如果想要对目标对象进行增强,目标对象一定要实现某一个接口,因为传入的参数就是接口。

SpringMyBatis的整合过程中,就是使用jdk的动态代理,对Mapper文件进行代理,最终成为Spring中的Bean对象。

1、新增一个UserService接口

public interface UserService {
    void show();
    void test();
}

2、新增一个接口的实现类UserrServiceImpl

public class UserServiceImpl implements UserService{
    @Override
    public void show() {
        System.out.println("aop测试show方法");
    }

    @Override
    public void test() {
        System.out.println("aop测试test方法");
    }
}

3、编写Jdk动态代理测试类

public class JdkTest {
    public static void main(String[] args) {
        // 实例化需要被增强的对象
        UserService userService = new UserServiceImpl();

        // 参数:类加载器、被代理的接口数组、handler处理器
        Object proxyInstance = Proxy.newProxyInstance(UserService.class.getClassLoader(), 
                new Class[]{UserService.class}, 
                (proxy, method, args1) -> {
            System.out.println("增强开始部分");
            // 被代理对象的方法
            Object invoke = method.invoke(userService, args1);
            System.out.println("增强结束部分");
            return invoke;
        });

        UserService instance = (UserService) proxyInstance;
        // 调用实例的方法,此时会进入代理逻辑
        instance.show();
    }

}

测试结果:

增强开始部分
aop测试show方法
增强结束部分

二、Cglib动态代理

使用该方式进行功能增强的时候,相较于JDK被代理的对象不需要实现接口,可以简单的理解为要求更低。

1、对之前的UserServiceImpl类进行改造,将实现接口去掉

public class UserServiceImpl{
    public void show() {
        System.out.println("aop测试show方法");
    }

    public void test() {
        System.out.println("aop测试test方法");
    }
}

2、编写对应的Cglib测试代码

public class CglibTest {
    public static void main(String[] args) {
        // 创建被代理对象
        UserServiceImpl userService = new UserServiceImpl();
        // 创建一个Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置对应的父子关系
        enhancer.setSuperclass(UserServiceImpl.class);
        // 创建MethodInterceptor单个或数组,用来处理代理逻辑
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("Cglib前置增强");
                Object result = methodProxy.invokeSuper(o, objects);
                System.out.println("Cglib后置增强");
                return result;
            }
        });
        // 创建对应代理对象
        UserServiceImpl instance = (UserServiceImpl) enhancer.create();
        // 调用show方法会进行代理
        instance.show();
    }

}

测试结果

Cglib前置增强
aop测试show方法
Cglib后置增强

3、对同一个类的不同方法使用不同的代理方法

对该cglib代理测试方法进行改造。使得我们在调用show方法时,触发对应的增强功能;使用test方法的时候,不进行任何的增强操作。
setCallbacks方法内编写方法的代理逻辑
setCallbackFilter方法内编写被代理对象的方法过滤逻辑

public class CglibTest {
    public static void main(String[] args) {
        // 创建被代理对象
        UserServiceImpl userService = new UserServiceImpl();
        // 创建一个Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 设置对应的父子关系
        enhancer.setSuperclass(UserServiceImpl.class);
        // 创建MethodInterceptor单个或数组,用来处理代理逻辑
        enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("Cglib前置增强");
                Object result = methodProxy.invokeSuper(o, objects);
                System.out.println("Cglib后置增强");
                return result;
            }
        },
                // 添加多个拦截器, 该拦截器不做任何处理NoOp()
                new NoOp() {
        }});

        // 设置回调过滤器,这里采用lam表达式
        enhancer.setCallbackFilter(method -> {
            if (method.getName().equals("test")){
                return 1;
            }else if (method.getName().equals("show")){
                return 0;
            }
            // 默认采用第二个,即空代理
            return 1;
        });

        // 创建对应代理对象
        UserServiceImpl instance = (UserServiceImpl) enhancer.create();
        // 调用show方法会进行代理
        instance.show();
        // 调用test方法会空代理
        instance.test();
    }

}

测试结果:

Cglib前置增强
aop测试show方法
Cglib后置增强
aop测试test方法

三、ProxyFactory动态代理

前面介绍了两种不同的实现动态代理的方式。在Spring的动态代理中,同样支持上面的两种不同形式的动态代理,Spring会根据代理对象的不同条件,选择使用不同的实现动态代理的方式。

它将两个不同的对象操作集中到一个ProxyFactory对象上,最终使用ProxyFactory对象来执行对应的动态代理操作。

Spring中的AOP就是使用ProxyFactory来实现的,所以下面的测试代码,我也仿造AOP部分的代码进行测试

1、编写对应的Before方法

public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("代理前逻辑");
    }
}

2、编写对应的After方法

public class AfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("代理后的逻辑");
    }
}

3、编写对应的测试方法

public class ProxyFactoryTest {
    public static void main(String[] args) {
        // 创建被代理对象
        UserServiceImpl userService = new UserServiceImpl();
        // 创建一个ProxyFactory对象
        ProxyFactory factory = new ProxyFactory();
        // 设置目标对象
        factory.setTarget(userService);

        // 添加代理逻辑
        factory.addAdvice(new BeforeAdvice());
        factory.addAdvice(new AfterAdvice());
        // 进行方法调用
        factory.addAdvice(new MethodInterceptor() {
            @Nullable
            @Override
            // 注意:此处的MethodInvocation是aop包下面的,不是Cglib的
            public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
                System.out.println("方法调用前----");
                Object proceed = invocation.proceed();
                System.out.println("方法调用后----");
                return proceed;
            }
        });

        UserServiceImpl instance = (UserServiceImpl) factory.getProxy();
        instance.show();
    }

}

测试结果:

代理前逻辑
方法调用前----
aop测试show方法
方法调用后----
代理后的逻辑

高级版本,更细粒度的代理

通过观察addAdvice方法的底层我们可以发现,我们添加的addvice对象,最终都会封装为advisor对象

Advice + Pointcut = Advisor

Pointcut:何种条件才能满足切入点条件,即何种条件才进行Advice的代理逻辑

Advice:对应的代理逻辑
理解使用该种方式定义Advisor,对于Spring中AOP源码部分理解起着至关重要的作用!!!

image-20221223113334458

四、Spring中AOP源代码分享

Spring的AOP就是通过ProxyFactory进行实现的,通过观察上面的内容我们不难发现,想要完成对一个方法的代理,大致需要以下一个步骤即可:

1. 找到符合当前Bean的所有的Advice
2. 将所有的Advice添加到ProxyFactory的对象中
3. 调用对应的方法

1、AOP方法的代理入口

类:AbstractAutoProxyCreator.class

image-20221223113949569

getAdvicesAndAdvisorsForBean:

根据bean的名字,找出所有符合条件的advice切入点最终返回的对象都是封装好的InstantiationModleAwarePointcutAdvisorImpl集合对象,条件成立则直接返回代理对象

2、找到当前Bean的所有Advice

image-20221223114819972

@Override
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
        // 先找到所有Advisor类型的bean对象
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
        // 再从所有切面中解析Advisor对象
		if (this.aspectJAdvisorsBuilder != null) 
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

类之间的关系图

image-20221223114714794

3、找到符合当前Bean的所有的Advice

image-20221223115533060

判断目标类是否和当前切点匹配

4、将所有的advisor对象添加ProxyFactory的对象中

image-20221223115821834

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (proxyFactory.isProxyTargetClass()) {
			// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
			if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
				// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
				for (Class<?> ifc : beanClass.getInterfaces()) {
					proxyFactory.addInterface(ifc);
				}
			}
		}
		else {
			// No proxyTargetClass flag enforced, let's apply our default checks...
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}
		
    	// 构建proxyFactory流程,将前面找到的advisor数组添加到factory当中
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// Use original ClassLoader if bean class not locally loaded in overriding class loader
		ClassLoader classLoader = getProxyClassLoader();
		if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
			classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
		}
		return proxyFactory.getProxy(classLoader);
	}

5、获得对应的Advisor责任链并调用入口

类:JdkDynamicAopProxy.class

@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
            // 被代理的对象和类
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
            // 代理对象在执行方法时,筛选出匹配的Advisor,并适配成Intercepetor,构成链
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);			
                // 空的话直接执行
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
                // 不为空执行上面构造的链
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

6、最终的调用方法位置

类:ReflectiveMethodInvocation.class

// 责任链递归调用,将责任链节点都进行调用
public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    
    // 如果没有匹配则递归调用proceed()方法
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      // 动态匹配,跟据参数进行方法匹配,匹配了就执行对应方法
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}
0

评论区